diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..03efbe6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +tests export-ignore +bin export-ignore +.gitattributes export-ignore +.gitignore export-ignore +.travis.yml export-ignore +phpcs.xml export-ignore +README.md export-ignore +LICENSE export-ignore \ No newline at end of file diff --git a/.github/workflows/phpcs.yml b/.github/workflows/phpcs.yml new file mode 100644 index 0000000..cbaf483 --- /dev/null +++ b/.github/workflows/phpcs.yml @@ -0,0 +1,15 @@ +name: PHP CodeSniffer + +on: + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancel all previous workflow runs for the same branch that have not yet completed. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + phpcs: + uses: wp-media/workflows/.github/workflows/phpcs.yml@main \ No newline at end of file diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 0000000..9681221 --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,15 @@ +name: PHPStan + +on: + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancel all previous workflow runs for the same branch that have not yet completed. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + phpstan: + uses: wp-media/workflows/.github/workflows/phpstan.yml@main diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..1c566bb --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,51 @@ +name: PHPUnit + +on: + pull_request: + # Allow manually triggering the workflow. + workflow_dispatch: + +# Cancel all previous workflow runs for the same branch that have not yet completed. +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + run: + name: PHPUnit + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + ini-values: 'memory_limit=1G' + coverage: none + tools: cs2pr + + - name: Install Composer dependencies + uses: "ramsey/composer-install@v3" + with: + # Bust the cache at least once a month - output format: YYYY-MM. + custom-cache-suffix: $(date -u "+%Y-%m") + + - name: Install SVN + run: sudo apt-get install subversion + + - name: Start mysql service + run: sudo /etc/init.d/mysql start + + - name: Install tests + run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:3306 latest + + - name: Mysql8 auth plugin workaround + run: sudo mysql -u root -proot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root';" + + - name: Run PHPUnit unit tests + run: composer test-unit + + - name: Run PHPUnit integration tests + run: composer test-integration \ No newline at end of file diff --git a/.gitignore b/.gitignore index f76a1b4..ad1bb9e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ # Exclude everything in the vendor directory. /vendor/* +composer.lock +.phpunit.result.cache \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b4f0a9a..0000000 --- a/.travis.yml +++ /dev/null @@ -1,50 +0,0 @@ -sudo: false -language: php -services: - - mysql -notifications: - slack: wp-media:nnBz5DMaiRLNaEqIStaUgygW - email: - on_success: never - on_failure: never -branches: - only: - - master - - develop - - /branch-.*$/ -cache: - directories: - - vendor - - "$HOME/.composer/cache" -matrix: - include: - - php: 7.4 - env: WP_VERSION=latest - - php: 7.3 - env: WP_VERSION=latest - - php: 7.2 - env: WP_VERSION=latest - - php: 7.1 - env: WP_VERSION=latest - - php: 7.0 - env: WP_VERSION=latest - - php: 5.6 - env: WP_VERSION=4.9.11 - - php: 5.6 - env: WP_VERSION=latest -before_script: -- rm composer.lock -- export PATH="$HOME/.composer/vendor/bin:$PATH" -- composer install --no-progress -- | - if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then - phpenv config-rm xdebug.ini - else - echo "xdebug.ini does not exist" - fi -- | - if [[ ! -z "$WP_VERSION" ]] ; then - bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION - fi -script: -- composer run-tests diff --git a/README.md b/README.md index 58ad854..3d0f66d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,66 @@ -# event-manager +# Event Manager Event management system for WordPress -Based on https://carlalexander.ca/designing-system-wordpress-event-management/ \ No newline at end of file +## Overview +This event management system provides a centralized way to handle WordPress hooks (actions and filters) through an event subscriber pattern. It allows you to organize hook callbacks into dedicated subscriber classes, making your WordPress code more maintainable and testable by decoupling hook registration from business logic. + +## Purpose +This system provides a robust and scalable solution for managing events within WordPress, following best practices for event-driven architecture. + +## Installation + +Install via Composer: + +```bash +composer require wp-media/event-manager +``` + +## Initialization + +Initialize the Event Manager in your WordPress plugin or theme: + +```php +use WPMedia\EventManager\EventManager; +use WPMedia\EventManager\PluginApiManager; + +$event_manager = new EventManager(new PluginApiManager()); +$event_manager->add_subscriber(new YourEventSubscriber()); +``` + +## Usage + +### Creating an Event Subscriber + +Implement the `SubscriberInterface` to listen to WordPress hooks: + +```php +use WPMedia\EventManager\SubscriberInterface; + +class YourEventSubscriber implements SubscriberInterface +{ + public static function get_subscribed_events(): array + { + return [ + 'init' => 'on_init', + 'wp_enqueue_scripts' => ['on_enqueue_scripts', 10], + ]; + } + + public function on_init() + { + // Handle init hook + } + + public function on_enqueue_scripts() + { + // Handle script enqueuing + } +} +``` + +## Reference +- **Original Design Article**: [Designing a System for WordPress Event Management](https://carlalexander.ca/designing-system-wordpress-event-management/) +- **Author**: Carl Alexander + +## Implementation Notes +This implementation adapts the concepts from the referenced article to create a practical event management solution for WordPress applications. \ No newline at end of file diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh new file mode 100644 index 0000000..878881f --- /dev/null +++ b/bin/install-wp-tests.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash + +if [ $# -lt 3 ]; then + echo "usage: $0 [db-host] [wp-version] [skip-database-creation]" + exit 1 +fi + +DB_NAME=$1 +DB_USER=$2 +DB_PASS=$3 +DB_HOST=${4-localhost} +WP_VERSION=${5-latest} +SKIP_DB_CREATE=${6-false} + +TMPDIR=${TMPDIR-/tmp} +TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//") +WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib} +WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress/} + +download() { + if [ `which curl` ]; then + curl -s "$1" > "$2"; + elif [ `which wget` ]; then + wget -nv -O "$2" "$1" + fi +} + +if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then + WP_TESTS_TAG="branches/$WP_VERSION" +elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then + if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then + # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x + WP_TESTS_TAG="tags/${WP_VERSION%??}" + else + WP_TESTS_TAG="tags/$WP_VERSION" + fi +elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + WP_TESTS_TAG="trunk" +else + # http serves a single offer, whereas https serves multiple. we only want one + download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json + grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json + LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//') + if [[ -z "$LATEST_VERSION" ]]; then + echo "Latest WordPress version could not be found" + exit 1 + fi + WP_TESTS_TAG="tags/$LATEST_VERSION" +fi + +set -ex + +install_wp() { + + if [ -d $WP_CORE_DIR ]; then + return; + fi + + mkdir -p $WP_CORE_DIR + + if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then + mkdir -p $TMPDIR/wordpress-nightly + download https://wordpress.org/nightly-builds/wordpress-latest.zip $TMPDIR/wordpress-nightly/wordpress-nightly.zip + unzip -q $TMPDIR/wordpress-nightly/wordpress-nightly.zip -d $TMPDIR/wordpress-nightly/ + mv $TMPDIR/wordpress-nightly/wordpress/* $WP_CORE_DIR + else + if [ $WP_VERSION == 'latest' ]; then + local ARCHIVE_NAME='latest' + elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then + # https serves multiple offers, whereas http serves single. + download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json + if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then + # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x + LATEST_VERSION=${WP_VERSION%??} + else + # otherwise, scan the releases and get the most up to date minor version of the major release + local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'` + LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1) + fi + if [[ -z "$LATEST_VERSION" ]]; then + local ARCHIVE_NAME="wordpress-$WP_VERSION" + else + local ARCHIVE_NAME="wordpress-$LATEST_VERSION" + fi + else + local ARCHIVE_NAME="wordpress-$WP_VERSION" + fi + download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz + tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR + fi + + download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php +} + +install_test_suite() { + # portable in-place argument for both GNU sed and Mac OSX sed + if [[ $(uname -s) == 'Darwin' ]]; then + local ioption='-i .bak' + else + local ioption='-i' + fi + + # set up testing suite if it doesn't yet exist + if [ ! -d $WP_TESTS_DIR ]; then + # set up testing suite + mkdir -p $WP_TESTS_DIR + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes + svn co --quiet https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data + fi + + if [ ! -f wp-tests-config.php ]; then + download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php + # remove all forward slashes in the end + WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::") + sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php + sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php + fi + +} + +install_db() { + + if [ ${SKIP_DB_CREATE} = "true" ]; then + return 0 + fi + + # parse DB_HOST for port or socket references + local PARTS=(${DB_HOST//\:/ }) + local DB_HOSTNAME=${PARTS[0]}; + local DB_SOCK_OR_PORT=${PARTS[1]}; + local EXTRA="" + + if ! [ -z $DB_HOSTNAME ] ; then + if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then + EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp" + elif ! [ -z $DB_SOCK_OR_PORT ] ; then + EXTRA=" --socket=$DB_SOCK_OR_PORT" + elif ! [ -z $DB_HOSTNAME ] ; then + EXTRA=" --host=$DB_HOSTNAME --protocol=tcp" + fi + fi + + # create database + mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA +} + +install_wp +install_test_suite +install_db diff --git a/composer.json b/composer.json index 8c7ed7c..d8fdc95 100644 --- a/composer.json +++ b/composer.json @@ -6,6 +6,7 @@ "homepage": "https://github.com/wp-media/event-manager", "license": "GPL-3.0-or-later", "support": { + "source": "https://github.com/wp-media/event-manager", "issues": "https://github.com/wp-media/event-manager/issues" }, "authors": [ @@ -16,31 +17,45 @@ ], "minimum-stability": "stable", "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "composer/installers": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "phpstan/extension-installer": true + } }, "require": { - "php": ">=5.6" + "php": ">=7.4" }, "require-dev": { - "php": "^5.6 || ^7", - "brain/monkey": "^2.0", - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "phpcompatibility/phpcompatibility-wp": "*", - "phpunit/phpunit": "^5.7 || ^7", - "wp-coding-standards/wpcs": "^2.0" + "php": ">=7.4", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "phpcompatibility/phpcompatibility-wp": "^2.0", + "php-stubs/wordpress-tests-stubs": "^6.8", + "phpstan/extension-installer": "^1.3", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.4", + "szepeviktor/phpstan-wordpress": "^1.3", + "roave/security-advisories": "dev-master", + "wp-coding-standards/wpcs": "^3", + "wp-media/phpunit": "^3" }, "autoload": { "psr-4": { - "WP_Media\\EventManager\\": "src/" + "WPMedia\\EventManager\\": "inc/" } }, "autoload-dev": { "psr-4": { - "WP_Media\\EventManager\\Tests\\Unit\\": "test/Unit", - "WP_Media\\EventManager\\Tests\\Integration\\": "test/Integration" + "WPMedia\\EventManager\\Tests\\Unit\\": "tests/Unit", + "WPMedia\\EventManager\\Tests\\Integration\\": "tests/Integration", + "WPMedia\\EventManager\\Tests\\Fixtures\\": "tests/Fixtures" } }, "scripts": { + "phpcs": "vendor/bin/phpcs", + "phpcs:fix": "vendor/bin/phpcbf", + "phpstan": "vendor/bin/phpstan analyze --memory-limit=2G", "test-unit":"\"vendor/bin/phpunit\" --testsuite unit --colors=always --configuration tests/Unit/phpunit.xml.dist", "test-integration": "\"vendor/bin/phpunit\" --testsuite integration --colors=always --configuration tests/Integration/phpunit.xml.dist", "run-tests": [ diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 25f9a28..0000000 --- a/composer.lock +++ /dev/null @@ -1,2035 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "982475964ef30574813edc0db72f2583", - "packages": [], - "packages-dev": [ - { - "name": "antecedent/patchwork", - "version": "2.1.11", - "source": { - "type": "git", - "url": "https://github.com/antecedent/patchwork.git", - "reference": "ff7aae02f1c5492716fe13d59de4cfc389b8c4b0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/antecedent/patchwork/zipball/ff7aae02f1c5492716fe13d59de4cfc389b8c4b0", - "reference": "ff7aae02f1c5492716fe13d59de4cfc389b8c4b0", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": ">=4" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Ignas Rudaitis", - "email": "ignas.rudaitis@gmail.com" - } - ], - "description": "Method redefinition (monkey-patching) functionality for PHP.", - "homepage": "http://patchwork2.org/", - "keywords": [ - "aop", - "aspect", - "interception", - "monkeypatching", - "redefinition", - "runkit", - "testing" - ], - "time": "2019-10-26T07:10:56+00:00" - }, - { - "name": "brain/monkey", - "version": "2.4.0", - "source": { - "type": "git", - "url": "https://github.com/Brain-WP/BrainMonkey.git", - "reference": "b3ce8b619c26db6abd01b9dcfd6a2c0254060956" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/b3ce8b619c26db6abd01b9dcfd6a2c0254060956", - "reference": "b3ce8b619c26db6abd01b9dcfd6a2c0254060956", - "shasum": "" - }, - "require": { - "antecedent/patchwork": "^2.0", - "mockery/mockery": ">=0.9 <2", - "php": ">=5.6.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4", - "phpcompatibility/php-compatibility": "^9.3.0", - "phpunit/phpunit": "^5.7.9 || ^6.0 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-version/1": "1.x-dev", - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Brain\\Monkey\\": "src/" - }, - "files": [ - "inc/api.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Giuseppe Mazzapica", - "email": "giuseppe.mazzapica@gmail.com", - "homepage": "https://gmazzap.me", - "role": "Developer" - } - ], - "description": "Mocking utility for PHP functions and WordPress plugin API", - "keywords": [ - "Monkey Patching", - "interception", - "mock", - "mock functions", - "mockery", - "patchwork", - "redefinition", - "runkit", - "test", - "testing" - ], - "time": "2019-11-24T16:03:21+00:00" - }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.5.0", - "source": { - "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "e749410375ff6fb7a040a68878c656c2e610b132" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e749410375ff6fb7a040a68878c656c2e610b132", - "reference": "e749410375ff6fb7a040a68878c656c2e610b132", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0", - "php": "^5.3|^7", - "squizlabs/php_codesniffer": "^2|^3" - }, - "require-dev": { - "composer/composer": "*", - "phpcompatibility/php-compatibility": "^9.0", - "sensiolabs/security-checker": "^4.1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "franck.nijhof@dealerdirect.com", - "homepage": "http://www.frenck.nl", - "role": "Developer / IT Manager" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "homepage": "http://www.dealerdirect.com", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "time": "2018-10-26T13:21:45+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/ae466f726242e637cebdd526a7d991b9433bacf1", - "reference": "ae466f726242e637cebdd526a7d991b9433bacf1", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "doctrine/coding-standard": "^6.0", - "ext-pdo": "*", - "ext-phar": "*", - "phpbench/phpbench": "^0.13", - "phpstan/phpstan-phpunit": "^0.11", - "phpstan/phpstan-shim": "^0.11", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://www.doctrine-project.org/projects/instantiator.html", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2019-10-21T16:45:58+00:00" - }, - { - "name": "hamcrest/hamcrest-php", - "version": "v2.0.0", - "source": { - "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/776503d3a8e85d4f9a1148614f95b7a608b046ad", - "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad", - "shasum": "" - }, - "require": { - "php": "^5.3|^7.0" - }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" - }, - "require-dev": { - "phpunit/php-file-iterator": "1.3.3", - "phpunit/phpunit": "~4.0", - "satooshi/php-coveralls": "^1.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "hamcrest" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD" - ], - "description": "This is the PHP port of Hamcrest Matchers", - "keywords": [ - "test" - ], - "time": "2016-01-20T08:20:44+00:00" - }, - { - "name": "mockery/mockery", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "5571962a4f733fbb57bede39778f71647fae8e66" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/5571962a4f733fbb57bede39778f71647fae8e66", - "reference": "5571962a4f733fbb57bede39778f71647fae8e66", - "shasum": "" - }, - "require": { - "hamcrest/hamcrest-php": "~2.0", - "lib-pcre": ">=7.0", - "php": ">=5.6.0", - "sebastian/comparator": "^1.2.4|^3.0" - }, - "require-dev": { - "phpunit/phpunit": "~5.7.10|~6.5|~7.0|~8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-0": { - "Mockery": "library/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" - }, - { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" - } - ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", - "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" - ], - "time": "2019-11-24T07:54:50+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.9.4", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/579bb7356d91f9456ccd505f24ca8b667966a0a7", - "reference": "579bb7356d91f9456ccd505f24ca8b667966a0a7", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" - }, - "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, - "files": [ - "src/DeepCopy/deep_copy.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" - ], - "time": "2019-12-15T19:12:40+00:00" - }, - { - "name": "phar-io/manifest", - "version": "1.0.3", - "source": { - "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2018-07-08T19:23:20+00:00" - }, - { - "name": "phar-io/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" - } - ], - "description": "Library for handling version information and constraints", - "time": "2018-07-08T19:19:57+00:00" - }, - { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "1f37659196e4f3113ea506a7efba201c52303bf1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/1f37659196e4f3113ea506a7efba201c52303bf1", - "reference": "1f37659196e4f3113ea506a7efba201c52303bf1", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - } - ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", - "keywords": [ - "compatibility", - "phpcs", - "standards" - ], - "time": "2019-11-15T04:12:02+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c", - "reference": "b862bc32f7e860d0b164b199bd995e690b4b191c", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5", - "paragonie/random_compat": "dev-master", - "paragonie/sodium_compat": "dev-master" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "paragonie", - "phpcs", - "polyfill", - "standards" - ], - "time": "2019-11-04T15:17:54+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0", - "phpcompatibility/phpcompatibility-paragonie": "^1.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "phpcs", - "standards", - "wordpress" - ], - "time": "2019-08-28T14:22:28+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/63a995caa1ca9e5590304cd845c15ad6d482a62a", - "reference": "63a995caa1ca9e5590304cd845c15ad6d482a62a", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2018-08-07T13:53:10+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "4.3.3", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62", - "reference": "2ecaa9fef01634c83bfa8dc1fe35fb5cef223a62", - "shasum": "" - }, - "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0", - "phpdocumentor/type-resolver": "~0.4 || ^1.0.0", - "webmozart/assert": "^1.0" - }, - "require-dev": { - "doctrine/instantiator": "^1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2019-12-20T13:40:23+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "reference": "2e32a6d48972b2c1976ed5d8967145b6cec4a4a9", - "shasum": "" - }, - "require": { - "php": "^7.1", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "^7.1", - "mockery/mockery": "~1", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "time": "2019-08-22T18:11:29+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.10.0", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "d638ebbb58daba25a6a0dc7969e1358a0e3c6682" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/d638ebbb58daba25a6a0dc7969e1358a0e3c6682", - "reference": "d638ebbb58daba25a6a0dc7969e1358a0e3c6682", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0", - "sebastian/comparator": "^1.2.3|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5 || ^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10.x-dev" - } - }, - "autoload": { - "psr-4": { - "Prophecy\\": "src/Prophecy" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, - { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" - } - ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", - "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2019-12-17T16:54:23+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "6.1.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^2.0", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1 || ^4.0", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "suggest": { - "ext-xdebug": "^2.6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "6.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2018-10-31T16:06:48+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "050bedf145a257b1ff02746c31894800e5122946" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", - "reference": "050bedf145a257b1ff02746c31894800e5122946", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2018-09-13T20:33:42+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2015-06-21T13:50:34+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "2.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/1038454804406b0b5f5f520358e78c1c2f71501e", - "reference": "1038454804406b0b5f5f520358e78c1c2f71501e", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2019-06-07T04:22:29+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/995192df77f63a59e47f025390d2d1fdf8f425ff", - "reference": "995192df77f63a59e47f025390d2d1fdf8f425ff", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2019-09-17T06:23:10+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "7.5.18", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "fcf6c4bfafaadc07785528b06385cce88935474d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fcf6c4bfafaadc07785528b06385cce88935474d", - "reference": "fcf6c4bfafaadc07785528b06385cce88935474d", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.7", - "phpunit/php-file-iterator": "^2.0.1", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.1", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^4.0", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", - "sebastian/version": "^2.0.1" - }, - "conflict": { - "phpunit/phpunit-mock-objects": "*" - }, - "require-dev": { - "ext-pdo": "*" - }, - "suggest": { - "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "7.5-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "https://phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2019-12-06T05:14:37+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "1.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "shasum": "" - }, - "require": { - "php": "^5.6 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" - }, - { - "name": "sebastian/comparator", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "shasum": "" - }, - "require": { - "php": "^7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "time": "2018-07-12T15:12:46+00:00" - }, - { - "name": "sebastian/diff", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "reference": "720fcc7e9b5cf384ea68d9d930d480907a0c1a29", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "time": "2019-02-04T06:01:07+00:00" - }, - { - "name": "sebastian/environment", - "version": "4.2.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/464c90d7bdf5ad4e8a6aea15c091fec0603d4368", - "reference": "464c90d7bdf5ad4e8a6aea15c091fec0603d4368", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "phpunit/phpunit": "^7.5" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides functionality to handle HHVM/PHP environments", - "homepage": "http://www.github.com/sebastianbergmann/environment", - "keywords": [ - "Xdebug", - "environment", - "hhvm" - ], - "time": "2019-11-20T08:46:58+00:00" - }, - { - "name": "sebastian/exporter", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/68609e1261d215ea5b21b7987539cbfbe156ec3e", - "reference": "68609e1261d215ea5b21b7987539cbfbe156ec3e", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.1.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Volker Dusch", - "email": "github@wallbash.com" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - }, - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", - "keywords": [ - "export", - "exporter" - ], - "time": "2019-09-14T09:02:43+00:00" - }, - { - "name": "sebastian/global-state", - "version": "2.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Snapshotting of global state", - "homepage": "http://www.github.com/sebastianbergmann/global-state", - "keywords": [ - "global state" - ], - "time": "2017-04-27T15:39:26+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "shasum": "" - }, - "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Traverses array structures and object graphs to enumerate all referenced objects", - "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "1.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - } - ], - "description": "Provides a list of PHP built-in functions that operate on resources", - "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2018-10-04T04:07:39+00:00" - }, - { - "name": "sebastian/version", - "version": "2.0.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", - "shasum": "" - }, - "require": { - "php": ">=5.6" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "Library that helps with managing the version number of Git-hosted PHP projects", - "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.5.3", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", - "reference": "557a1fc7ac702c66b0bbfe16ab3d55839ef724cb", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "bin": [ - "bin/phpcs", - "bin/phpcbf" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "role": "lead" - } - ], - "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards" - ], - "time": "2019-12-04T04:46:47+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "time": "2019-11-27T13:56:44+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.1.3", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "reference": "11336f6f84e16a720dae9d8e6ed5019efa85a0f9", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.0" - }, - "type": "library", - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - } - ], - "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2019-06-13T22:48:21+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.6.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925", - "reference": "573381c0a64f155a0d9a23f4b0c797194805b925", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "vimeo/psalm": "<3.6.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.36 || ^7.5.13" - }, - "type": "library", - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "time": "2019-11-24T13:36:37+00:00" - }, - { - "name": "wp-coding-standards/wpcs", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "f90e8692ce97b693633db7ab20bfa78d930f536a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/f90e8692ce97b693633db7ab20bfa78d930f536a", - "reference": "f90e8692ce97b693633db7ab20bfa78d930f536a", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0", - "phpcompatibility/php-compatibility": "^9.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", - "keywords": [ - "phpcs", - "standards", - "wordpress" - ], - "time": "2019-11-11T12:34:03+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": ">=5.6" - }, - "platform-dev": { - "php": "^5.6 || ^7" - } -} diff --git a/inc/EventManager.php b/inc/EventManager.php new file mode 100644 index 0000000..ae5a671 --- /dev/null +++ b/inc/EventManager.php @@ -0,0 +1,125 @@ +plugin_api_manager = $plugin_api_manager; + } + + /** + * Adds the given event listener to the list of event listeners + * + * @param string $event_name Name of the event. + * @param callable $listener Listener Callback function. + * @param int $priority Priority. + * @param int $accepted_args Number of arguments. + * + * @return void + */ + public function add_listener( $event_name, $listener, $priority = 10, $accepted_args = 1 ): void { + $this->plugin_api_manager->add_callback( $event_name, $listener, $priority, $accepted_args ); + } + + /** + * Adds an event subscriber. + * + * The event manager adds the given subscriber to the list of event listeners + * for all the events that it wants to listen to. + * + * @param SubscriberInterface $subscriber SubscriberInterface implementation. + */ + public function add_subscriber( SubscriberInterface $subscriber ): void { + if ( $subscriber instanceof EventManagerAwareSubscriberInterface ) { + $subscriber->set_event_manager( $this ); + } + + foreach ( $subscriber->get_subscribed_events() as $event_name => $parameters ) { + $this->add_subscriber_listener( $subscriber, $event_name, $parameters ); + } + } + + /** + * Removes the given event listener from the list of event listeners + * that listen to the given event. + * + * @param string $event_name Event name. + * @param callable|string|array $callback Callback. + * @param int $priority Priority. + * + * @return bool + */ + public function remove_listener( $event_name, $callback, $priority = 10 ): bool { + return $this->plugin_api_manager->remove_callback( $event_name, $callback, $priority ); + } + + /** + * Removes an event subscriber. + * + * The event manager removes the given subscriber from the list of event listeners + * for all the events that it wants to listen to. + * + * @param SubscriberInterface $subscriber SubscriberInterface implementation. + */ + public function remove_subscriber( SubscriberInterface $subscriber ): void { + foreach ( $subscriber->get_subscribed_events() as $event_name => $parameters ) { + $this->remove_subscriber_listener( $subscriber, $event_name, $parameters ); + } + } + + /** + * Adds the given subscriber listener to the list of event listeners + * that listen to the given event. + * + * @param SubscriberInterface $subscriber SubscriberInterface implementation. + * @param string $event_name Event name. + * @param string|array $parameters Parameters, can be a string, an array or a multidimensional array. + */ + private function add_subscriber_listener( SubscriberInterface $subscriber, $event_name, $parameters ): void { + if ( is_string( $parameters ) ) { + $this->add_listener( $event_name, [ $subscriber, $parameters ] ); + } elseif ( count( $parameters ) !== count( $parameters, COUNT_RECURSIVE ) ) { + foreach ( $parameters as $parameter ) { + $this->add_subscriber_listener( $subscriber, $event_name, $parameter ); + } + } elseif ( isset( $parameters[0] ) ) { + $this->add_listener( $event_name, [ $subscriber, $parameters[0] ], isset( $parameters[1] ) ? $parameters[1] : 10, isset( $parameters[2] ) ? $parameters[2] : 1 ); + } + } + + /** + * Removes the given subscriber listener from the list of event listeners + * that listen to the given event. + * + * @param SubscriberInterface $subscriber SubscriberInterface implementation. + * @param string $event_name Event name. + * @param string|array $parameters Parameters, can be a string, an array or a multidimensional array. + */ + private function remove_subscriber_listener( SubscriberInterface $subscriber, $event_name, $parameters ): void { + if ( is_string( $parameters ) ) { + $this->remove_listener( $event_name, [ $subscriber, $parameters ] ); + } elseif ( count( $parameters ) !== count( $parameters, COUNT_RECURSIVE ) ) { + foreach ( $parameters as $parameter ) { + $this->remove_subscriber_listener( $subscriber, $event_name, $parameter ); + } + } elseif ( isset( $parameters[0] ) ) { + $this->remove_listener( $event_name, [ $subscriber, $parameters[0] ], isset( $parameters[1] ) ? $parameters[1] : 10 ); + } + } +} diff --git a/inc/EventManagerAwareSubscriberInterface.php b/inc/EventManagerAwareSubscriberInterface.php new file mode 100644 index 0000000..79dca66 --- /dev/null +++ b/inc/EventManagerAwareSubscriberInterface.php @@ -0,0 +1,16 @@ + 'method_name') + * * array('event_name' => array('method_name', $priority)) + * * array('event_name' => array('method_name', $priority, $accepted_args)) + * * array('event_name' => array(array('method_name_1', $priority_1, $accepted_args_1)), array('method_name_2', $priority_2, $accepted_args_2))) + * + * @return array + */ + public static function get_subscribed_events(): array; +} diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index fda5f49..0000000 --- a/phpcs.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - Event Manager for WordPress - - - - - . - /vendor/* - - - - - - - - - - - - - - - - - - - *\.php$ - - \ No newline at end of file diff --git a/phpcs.xml.dist b/phpcs.xml.dist new file mode 100644 index 0000000..a1090ba --- /dev/null +++ b/phpcs.xml.dist @@ -0,0 +1,45 @@ + + + The custom ruleset for EventManager. + + + + + + + + + + inc + tests/Fixtures + tests/Integration + tests/Unit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..2bcb4bc --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,13 @@ +includes: + - phar://phpstan.phar/conf/bleedingEdge.neon +parameters: + level: 5 + inferPrivatePropertyTypeFromConstructor: true + paths: + - inc/ + - tests/Fixtures + - tests/Integration + - tests/Unit + scanFiles: + - vendor/php-stubs/wordpress-stubs/wordpress-stubs.php + - vendor/php-stubs/wordpress-tests-stubs/wordpress-tests-stubs.php \ No newline at end of file diff --git a/tests/Fixtures/DummySubscriber.php b/tests/Fixtures/DummySubscriber.php new file mode 100644 index 0000000..a6d75ba --- /dev/null +++ b/tests/Fixtures/DummySubscriber.php @@ -0,0 +1,28 @@ +|array>> + */ + public static function get_subscribed_events(): array { + return [ + 'foo' => 'bar', + 'foofoo' => [ 'barbar', 20 ], + 'foobar' => [ 'foobarbar', 50, 3 ], + 'barfoo' => [ + [ 'filter_this' ], + [ 'filter_that', 10, 2 ], + ], + ]; + } +} diff --git a/tests/Integration/EventManager/AddSubscriberTest.php b/tests/Integration/EventManager/AddSubscriberTest.php new file mode 100644 index 0000000..bc46016 --- /dev/null +++ b/tests/Integration/EventManager/AddSubscriberTest.php @@ -0,0 +1,48 @@ +add_subscriber( $subscriber ); + + $this->assertSame( + 10, + has_filter( 'foo', [ $subscriber, 'bar' ] ) + ); + $this->assertSame( + 20, + has_filter( 'foofoo', [ $subscriber, 'barbar' ] ) + ); + $this->assertSame( + 50, + has_filter( 'foobar', [ $subscriber, 'foobarbar' ] ) + ); + $this->assertSame( + 10, + has_filter( 'barfoo', [ $subscriber, 'filter_this' ] ) + ); + $this->assertSame( + 10, + has_filter( 'barfoo', [ $subscriber, 'filter_that' ] ) + ); + } +} diff --git a/tests/Integration/EventManager/RemoveSubscriberTest.php b/tests/Integration/EventManager/RemoveSubscriberTest.php new file mode 100644 index 0000000..4a92658 --- /dev/null +++ b/tests/Integration/EventManager/RemoveSubscriberTest.php @@ -0,0 +1,34 @@ +add_subscriber( $subscriber ); + $manager->remove_subscriber( $subscriber ); + + $this->assertFalse( has_filter( 'foo', [ $subscriber, 'bar' ] ) ); + $this->assertFalse( has_filter( 'foofoo', [ $subscriber, 'barbar' ] ) ); + $this->assertFalse( has_filter( 'foobar', [ $subscriber, 'foobarbar' ] ) ); + $this->assertFalse( has_filter( 'barfoo', [ $subscriber, 'filter_this' ] ) ); + $this->assertFalse( has_filter( 'barfoo', [ $subscriber, 'filter_that' ] ) ); + } +} diff --git a/tests/Integration/PluginApiManager/AddCallbackTest.php b/tests/Integration/PluginApiManager/AddCallbackTest.php new file mode 100644 index 0000000..3b51848 --- /dev/null +++ b/tests/Integration/PluginApiManager/AddCallbackTest.php @@ -0,0 +1,41 @@ +add_callback( 'the_content', 'strtolower' ); + + $this->assertSame( + 10, + has_filter( 'the_content', 'strtolower' ) + ); + } + + /** + * Test should add a new filter with a priority 100 and 3 arguments + */ + public function testShouldAddNewFilterWithAllParameters() { + $plugin_api_manager = new PluginApiManager(); + $plugin_api_manager->add_callback( 'the_content', 'strtolower', 100, 3 ); + + $this->assertSame( + 100, + has_filter( 'the_content', 'strtolower' ) + ); + } +} diff --git a/tests/Integration/PluginApiManager/ExecuteTest.php b/tests/Integration/PluginApiManager/ExecuteTest.php new file mode 100644 index 0000000..2e6f4d5 --- /dev/null +++ b/tests/Integration/PluginApiManager/ExecuteTest.php @@ -0,0 +1,26 @@ +execute( 'my_action' ); + + $this->assertSame( 1, did_action( 'my_action' ) ); + } +} diff --git a/tests/Integration/PluginApiManager/FilterTest.php b/tests/Integration/PluginApiManager/FilterTest.php new file mode 100644 index 0000000..a432165 --- /dev/null +++ b/tests/Integration/PluginApiManager/FilterTest.php @@ -0,0 +1,31 @@ +filter( 'my_filter', 'filter value' ); + + add_filter( 'my_filter', 'strtoupper' ); + + $this->assertSame( + 10, + has_filter( 'my_filter', 'strtoupper' ) + ); + } +} diff --git a/tests/Integration/PluginApiManager/HasCallbackTest.php b/tests/Integration/PluginApiManager/HasCallbackTest.php new file mode 100644 index 0000000..590176d --- /dev/null +++ b/tests/Integration/PluginApiManager/HasCallbackTest.php @@ -0,0 +1,60 @@ +assertFalse( $plugin_api_manager->has_callback( 'my_custom_filter' ) ); + } + + /** + * Test should return true when a callback is attached to the given hook. + */ + public function testShouldReturnTrueWhenCallbackAttached() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertTrue( $plugin_api_manager->has_callback( 'the_content' ) ); + } + + /** + * Test should return false when the given callback is not attached to the given hook. + */ + public function testShouldReturnFalseWhenCallbackNotAttached() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertFalse( $plugin_api_manager->has_callback( 'the_content', 'strtoupper' ) ); + } + + /** + * Test should return priority int when the given callback is attached to the given hook. + */ + public function testShouldReturnPriorityIntWhenCallbackAttached() { + add_filter( 'the_content', 'strtolower', 11 ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertSame( + 11, + $plugin_api_manager->has_callback( 'the_content', 'strtolower' ) + ); + } +} diff --git a/tests/Integration/PluginApiManager/RemoveCallbackTest.php b/tests/Integration/PluginApiManager/RemoveCallbackTest.php new file mode 100644 index 0000000..7a50fd6 --- /dev/null +++ b/tests/Integration/PluginApiManager/RemoveCallbackTest.php @@ -0,0 +1,59 @@ +assertTrue( $plugin_api_manager->remove_callback( 'the_content', 'strtolower' ) ); + } + + /** + * Test should return false when the given callback doesn't exist for the given hook + */ + public function testShouldReturnFalseWhenCallbackDoesNotExist() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertFalse( $plugin_api_manager->remove_callback( 'the_content', 'strtoupper' ) ); + } + + /** + * Test should return false when the given callback priority doesn't match with the priority when added + */ + public function testShouldReturnFalseWhenPriorityDoesNotMatch() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertFalse( $plugin_api_manager->remove_callback( 'the_content', 'strtolower', 100 ) ); + } + + /** + * Test should return true when the given callback priority matches with the priority when added + */ + public function testShouldReturnTrueWhenPriorityMatches() { + add_filter( 'the_content', 'strtolower', 100 ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertTrue( $plugin_api_manager->remove_callback( 'the_content', 'strtolower', 100 ) ); + } +} diff --git a/tests/Integration/TestCase.php b/tests/Integration/TestCase.php new file mode 100644 index 0000000..c526f9a --- /dev/null +++ b/tests/Integration/TestCase.php @@ -0,0 +1,60 @@ +} + */ + protected $config; + + /** + * Setup method for the test case. + * + * @return void + */ + public function set_up() { + parent::set_up(); + + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + } + + /** + * Get the test data configuration. + * + * @return array + */ + public function configTestData(): array { + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + + return isset( $this->config['test_data'] ) + ? $this->config['test_data'] + : $this->config; + } + + /** + * Load test data configuration. + * + * @return void + */ + protected function loadTestDataConfig(): void { + $obj = new ReflectionObject( $this ); + $filename = $obj->getFileName(); + + if ( false === $filename ) { + return; + } + + $this->config = $this->getTestData( dirname( $filename ), basename( $filename, '.php' ) ); + } +} diff --git a/tests/Integration/bootstrap.php b/tests/Integration/bootstrap.php new file mode 100644 index 0000000..dbd5377 --- /dev/null +++ b/tests/Integration/bootstrap.php @@ -0,0 +1,8 @@ + + + + + ../../inc + + + + + . + + + diff --git a/tests/Unit/EventManager/AddSubscriberTest.php b/tests/Unit/EventManager/AddSubscriberTest.php new file mode 100644 index 0000000..a45e1f8 --- /dev/null +++ b/tests/Unit/EventManager/AddSubscriberTest.php @@ -0,0 +1,30 @@ +shouldReceive( 'add_callback' ) + ->times( 5 ); + + $manager = new EventManager( $plugin_api_manager ); + + $manager->add_subscriber( new DummySubscriber() ); + } +} diff --git a/tests/Unit/EventManager/RemoveSubscriberTest.php b/tests/Unit/EventManager/RemoveSubscriberTest.php new file mode 100644 index 0000000..65fa16a --- /dev/null +++ b/tests/Unit/EventManager/RemoveSubscriberTest.php @@ -0,0 +1,30 @@ +shouldReceive( 'remove_callback' ) + ->times( 5 ); + + $manager = new EventManager( $plugin_api_manager ); + + $manager->remove_subscriber( new DummySubscriber() ); + } +} diff --git a/tests/Unit/PluginApiManager/AddCallbackTest.php b/tests/Unit/PluginApiManager/AddCallbackTest.php new file mode 100644 index 0000000..2967901 --- /dev/null +++ b/tests/Unit/PluginApiManager/AddCallbackTest.php @@ -0,0 +1,38 @@ +with( 'strtolower', 10, 1 ); + + $plugin_api_manager = new PluginApiManager(); + $plugin_api_manager->add_callback( 'the_content', 'strtolower' ); + } + + /** + * Test should add a new filter with a priority 100 and 3 arguments + */ + public function testShouldAddNewFilterWithAllParameters() { + Filters\expectAdded( 'the_content' ) + ->with( 'strtolower', 100, 3 ); + + $plugin_api_manager = new PluginApiManager(); + $plugin_api_manager->add_callback( 'the_content', 'strtolower', 100, 3 ); + } +} diff --git a/tests/Unit/PluginApiManager/ExecuteTest.php b/tests/Unit/PluginApiManager/ExecuteTest.php new file mode 100644 index 0000000..4bf5034 --- /dev/null +++ b/tests/Unit/PluginApiManager/ExecuteTest.php @@ -0,0 +1,26 @@ +execute( 'my_action' ); + + $this->assertSame( 1, did_action( 'my_action' ) ); + } +} diff --git a/tests/Unit/PluginApiManager/FilterTest.php b/tests/Unit/PluginApiManager/FilterTest.php new file mode 100644 index 0000000..b3ec54c --- /dev/null +++ b/tests/Unit/PluginApiManager/FilterTest.php @@ -0,0 +1,27 @@ +filter( 'my_filter', 'filter value' ); + + $this->assertTrue( Filters\applied( 'my_filter' ) > 0 ); + } +} diff --git a/tests/Unit/PluginApiManager/HasCallbackTest.php b/tests/Unit/PluginApiManager/HasCallbackTest.php new file mode 100644 index 0000000..3b1224f --- /dev/null +++ b/tests/Unit/PluginApiManager/HasCallbackTest.php @@ -0,0 +1,46 @@ +assertFalse( $plugin_api_manager->has_callback( 'the_content' ) ); + } + + /** + * Test should return false when the given callback is not attached to the given hook. + */ + public function testShouldReturnFalseWhenCallbackNotAttached() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertFalse( $plugin_api_manager->has_callback( 'the_content', 'strtoupper' ) ); + } + + /** + * Test should return priority value when the given callback is attached to the given hook. + */ + public function testShouldReturnPriorityIntWhenCallbackAttached() { + add_filter( 'the_content', 'strtolower', 11 ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertSame( 11, $plugin_api_manager->has_callback( 'the_content', 'strtolower' ) ); + } +} diff --git a/tests/Unit/PluginApiManager/RemoveCallbackTest.php b/tests/Unit/PluginApiManager/RemoveCallbackTest.php new file mode 100644 index 0000000..ecc2459 --- /dev/null +++ b/tests/Unit/PluginApiManager/RemoveCallbackTest.php @@ -0,0 +1,59 @@ +assertTrue( $plugin_api_manager->remove_callback( 'the_content', 'strtolower' ) ); + } + + /** + * Test should return false when the given callback doesn't exist for the given hook + */ + public function testShouldReturnFalseWhenCallbackDoesNotExist() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertFalse( $plugin_api_manager->remove_callback( 'the_content', 'strtoupper' ) ); + } + + /** + * Test should return false when the given callback priority doesn't match with the priority when added + */ + public function testShouldReturnFalseWhenPriorityDoesNotMatch() { + add_filter( 'the_content', 'strtolower' ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertFalse( $plugin_api_manager->remove_callback( 'the_content', 'strtolower', 100 ) ); + } + + /** + * Test should return true when the given callback priority matches with the priority when added + */ + public function testShouldReturnTrueWhenPriorityMatches() { + add_filter( 'the_content', 'strtolower', 100 ); + + $plugin_api_manager = new PluginApiManager(); + + $this->assertTrue( $plugin_api_manager->remove_callback( 'the_content', 'strtolower', 100 ) ); + } +} diff --git a/tests/Unit/TestCase.php b/tests/Unit/TestCase.php new file mode 100644 index 0000000..c50b3ec --- /dev/null +++ b/tests/Unit/TestCase.php @@ -0,0 +1,60 @@ +} + */ + protected $config; + + /** + * Setup method for the test case. + * + * @return void + */ + protected function set_up() { + parent::set_up(); + + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + } + + /** + * Get the test data configuration. + * + * @return array + */ + public function configTestData(): array { + if ( empty( $this->config ) ) { + $this->loadTestDataConfig(); + } + + return isset( $this->config['test_data'] ) + ? $this->config['test_data'] + : $this->config; + } + + /** + * Load test data configuration. + * + * @return void + */ + protected function loadTestDataConfig(): void { + $obj = new ReflectionObject( $this ); + $filename = $obj->getFileName(); + + if ( false === $filename ) { + return; + } + + $this->config = $this->getTestData( dirname( $filename ), basename( $filename, '.php' ) ); + } +} diff --git a/tests/Unit/bootstrap.php b/tests/Unit/bootstrap.php new file mode 100644 index 0000000..a096202 --- /dev/null +++ b/tests/Unit/bootstrap.php @@ -0,0 +1,7 @@ + + + + + ../../inc + + + + + . + + +