From f05ae75a779c41ca209e6070489404a1e713ec17 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 18:57:54 +0100 Subject: [PATCH 01/36] Upgrade psalm to 4.3.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ccf0b3da..eade123e 100644 --- a/composer.json +++ b/composer.json @@ -32,7 +32,7 @@ "doctrine/coding-standard": "^6.0 || ^8.0", "doctrine/common": "^3.0", "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", - "vimeo/psalm": "^3.11" + "vimeo/psalm": "^4.3.1" }, "conflict": { "doctrine/common": "<2.10@dev" From b228e6a53edd40119f08f938651f2d9d0021fa0d Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 18:59:26 +0100 Subject: [PATCH 02/36] Use the ramsey/composer-install action to install dependencies Like https://github.com/doctrine/.github/pull/16 --- .github/workflows/coding-standards.yml | 11 ++----- .github/workflows/continuous-integration.yml | 31 ++++---------------- .github/workflows/static-analysis.yml | 11 ++----- 3 files changed, 11 insertions(+), 42 deletions(-) diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 18fcfa08..e325475b 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -35,15 +35,10 @@ jobs: php-version: "${{ matrix.php-version }}" tools: "cs2pr" - - name: "Cache dependencies installed with Composer" - uses: "actions/cache@v2" - with: - path: "~/.composer/cache" - key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" - restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - - name: "Install dependencies with Composer" - run: "composer install --no-interaction --no-progress --no-suggest" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "${{ matrix.deps }}" # https://github.com/doctrine/.github/issues/3 - name: "Run PHP_CodeSniffer" diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index eb32fcb5..1c8eb911 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -21,9 +21,9 @@ jobs: - "7.4" - "8.0" deps: - - "normal" + - "highest" include: - - deps: "low" + - deps: "lowest" php-version: "7.1" steps: @@ -46,31 +46,10 @@ jobs: php-version: "${{ matrix.php-version }}" coverage: "xdebug" - - name: "Cache dependencies installed with composer" - uses: "actions/cache@v2" + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" with: - path: "~/.composer/cache" - key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" - restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - - # Remove this block when - # https://github.com/felixfbecker/php-language-server-protocol/pull/15 is - # merged and released - - name: "Remove dependency on vimeo/psalm for PHP8" - run: "composer remove --dev --no-update vimeo/psalm" - if: "${{ matrix.php-version == '8.0' }}" - - - name: "Downgrade Composer" - run: "composer self-update --1" - if: "${{ matrix.php-version == '7.1' }}" - - - name: "Update dependencies with composer" - run: "composer update --no-interaction --no-progress --no-suggest" - if: "${{ matrix.deps == 'normal' }}" - - - name: "Install lowest possible dependencies with composer" - run: "composer update --no-interaction --no-progress --no-suggest --prefer-dist --prefer-lowest" - if: "${{ matrix.deps == 'low' }}" + dependency-versions: "${{ matrix.deps }}" - name: "Run PHPUnit" run: "vendor/bin/phpunit --coverage-clover=coverage.xml" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 2cd3a3e2..5c419c91 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -34,15 +34,10 @@ jobs: php-version: "${{ matrix.php-version }}" tools: "cs2pr" - - name: "Cache dependencies installed with composer" - uses: "actions/cache@v2" + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" with: - path: "~/.composer/cache" - key: "php-${{ matrix.php-version }}-composer-locked-${{ hashFiles('composer.lock') }}" - restore-keys: "php-${{ matrix.php-version }}-composer-locked-" - - - name: "Install dependencies with composer" - run: "composer install --no-interaction --no-progress --no-suggest" + dependency-versions: "${{ matrix.deps }}" - name: "Run a static analysis with phpstan/phpstan" run: "vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr" From 0baa94baf887d83f426a5a8800440adce6f57ad8 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 21:08:30 +0100 Subject: [PATCH 03/36] Add psalm.xml to .gitattributes This file is not needed for a end user --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 1c8e4949..46ee9619 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,4 +7,5 @@ /phpunit.xml.dist export-ignore /phpcs.xml.dist export-ignore /phpstan.neon export-ignore +/psalm.xml export-ignore /composer.lock export-ignore From 80aacacba02372950e554f811ecec3edb02db1bb Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 21:11:29 +0100 Subject: [PATCH 04/36] Remove composer.lock and add it to .gitignore --- .gitignore | 2 + composer.lock | 4317 ------------------------------------------------- 2 files changed, 2 insertions(+), 4317 deletions(-) delete mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 6cfbe965..b8270469 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /phpunit.xml /phpcs.xml /.phpcs-cache +/.phpunit.result.cache +composer.lock diff --git a/composer.lock b/composer.lock deleted file mode 100644 index 34ede20a..00000000 --- a/composer.lock +++ /dev/null @@ -1,4317 +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": "01e94c11f5292496c375a5e393a45e73", - "packages": [ - { - "name": "doctrine/annotations", - "version": "v1.8.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/904dca4eb10715b92569fbcd79e201d5c349b6bc", - "reference": "904dca4eb10715b92569fbcd79e201d5c349b6bc", - "shasum": "" - }, - "require": { - "doctrine/lexer": "1.*", - "php": "^7.1" - }, - "require-dev": { - "doctrine/cache": "1.*", - "phpunit/phpunit": "^7.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Docblock Annotations Parser", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "annotations", - "docblock", - "parser" - ], - "time": "2019-10-01T18:55:10+00:00" - }, - { - "name": "doctrine/cache", - "version": "v1.7.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/b3217d58609e9c8e661cd41357a54d926c4a2a1a", - "reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a", - "shasum": "" - }, - "require": { - "php": "~7.1" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "alcaeus/mongo-php-adapter": "^1.1", - "mongodb/mongodb": "^1.1", - "phpunit/phpunit": "^5.7", - "predis/predis": "~1.0" - }, - "suggest": { - "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.7.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Caching library offering an object-oriented API for many cache backends", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "cache", - "caching" - ], - "time": "2017-08-25T07:02:50+00:00" - }, - { - "name": "doctrine/collections", - "version": "v1.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/collections.git", - "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf", - "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "doctrine/coding-standard": "~0.1@dev", - "phpunit/phpunit": "^5.7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Collections\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Collections Abstraction library", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "array", - "collections", - "iterator" - ], - "time": "2017-07-22T10:37:32+00:00" - }, - { - "name": "doctrine/event-manager", - "version": "v1.0.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/event-manager.git", - "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3", - "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "conflict": { - "doctrine/common": "<2.9@dev" - }, - "require-dev": { - "doctrine/coding-standard": "^4.0", - "phpunit/phpunit": "^7.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "Doctrine Event Manager component", - "homepage": "https://www.doctrine-project.org/projects/event-manager.html", - "keywords": [ - "event", - "eventdispatcher", - "eventmanager" - ], - "time": "2018-06-11T11:59:03+00:00" - }, - { - "name": "doctrine/lexer", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", - "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-0": { - "Doctrine\\Common\\Lexer\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", - "homepage": "http://www.doctrine-project.org", - "keywords": [ - "lexer", - "parser" - ], - "time": "2014-09-09T13:34:57+00:00" - } - ], - "packages-dev": [ - { - "name": "amphp/amp", - "version": "v2.4.4", - "source": { - "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "1e58d53e4af390efc7813e36cd215bd82cba4b06" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/1e58d53e4af390efc7813e36cd215bd82cba4b06", - "reference": "1e58d53e4af390efc7813e36cd215bd82cba4b06", - "shasum": "" - }, - "require": { - "php": ">=7" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "amphp/phpunit-util": "^1", - "ext-json": "*", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^6.0.9 | ^7", - "react/promise": "^2", - "vimeo/psalm": "^3.11@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Amp\\": "lib" - }, - "files": [ - "lib/functions.php", - "lib/Internal/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "http://amphp.org/amp", - "keywords": [ - "async", - "asynchronous", - "awaitable", - "concurrency", - "event", - "event-loop", - "future", - "non-blocking", - "promise" - ], - "time": "2020-04-30T04:54:50+00:00" - }, - { - "name": "amphp/byte-stream", - "version": "v1.7.3", - "source": { - "type": "git", - "url": "https://github.com/amphp/byte-stream.git", - "reference": "b867505edb79dda8f253ca3c3a2bbadae4b16592" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/b867505edb79dda8f253ca3c3a2bbadae4b16592", - "reference": "b867505edb79dda8f253ca3c3a2bbadae4b16592", - "shasum": "" - }, - "require": { - "amphp/amp": "^2" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "amphp/phpunit-util": "^1", - "friendsofphp/php-cs-fixer": "^2.3", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^6 || ^7 || ^8", - "vimeo/psalm": "^3.9@dev" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Amp\\ByteStream\\": "lib" - }, - "files": [ - "lib/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "http://amphp.org/byte-stream", - "keywords": [ - "amp", - "amphp", - "async", - "io", - "non-blocking", - "stream" - ], - "time": "2020-04-04T16:56:54+00:00" - }, - { - "name": "composer/package-versions-deprecated", - "version": "1.11.99", - "source": { - "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855", - "reference": "c8c9aa8a14cc3d3bec86d0a8c3fa52ea79936855", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" - }, - "require-dev": { - "composer/composer": "^1.9.3 || ^2.0@dev", - "ext-zip": "^1.13", - "phpunit/phpunit": "^6.5 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "PackageVersions\\Installer", - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "PackageVersions\\": "src/PackageVersions" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" - } - ], - "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2020-08-25T05:50:16+00:00" - }, - { - "name": "composer/semver", - "version": "1.5.1", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/c6bea70230ef4dd483e6bbcab6005f682ed3a8de", - "reference": "c6bea70230ef4dd483e6bbcab6005f682ed3a8de", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.5 || ^5.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "time": "2020-01-13T12:06:48+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "cbe23383749496fe0f373345208b79568e4bc248" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/cbe23383749496fe0f373345208b79568e4bc248", - "reference": "cbe23383749496fe0f373345208b79568e4bc248", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "time": "2019-11-06T16:40:04+00:00" - }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v0.7.0", - "source": { - "type": "git", - "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", - "reference": "e8d808670b8f882188368faaf1144448c169c0b7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/e8d808670b8f882188368faaf1144448c169c0b7", - "reference": "e8d808670b8f882188368faaf1144448c169c0b7", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2 || ^3 || 4.0.x-dev" - }, - "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": "2020-06-25T14:57:39+00:00" - }, - { - "name": "doctrine/coding-standard", - "version": "8.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/coding-standard.git", - "reference": "637003febec655f1b27f4301b44bf2264be57434" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/coding-standard/zipball/637003febec655f1b27f4301b44bf2264be57434", - "reference": "637003febec655f1b27f4301b44bf2264be57434", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", - "php": "^7.2 || ^8.0", - "slevomat/coding-standard": "^6.3.9", - "squizlabs/php_codesniffer": "^3.5.5" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-master": "7.0.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Steve Mรผller", - "email": "st.mueller@dzh-online.de" - } - ], - "description": "The Doctrine Coding Standard is a set of PHPCS rules applied to all Doctrine projects.", - "homepage": "https://www.doctrine-project.org/projects/coding-standard.html", - "keywords": [ - "checks", - "code", - "coding", - "cs", - "doctrine", - "rules", - "sniffer", - "sniffs", - "standard", - "style" - ], - "time": "2020-07-05T20:35:22+00:00" - }, - { - "name": "doctrine/common", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/doctrine/common.git", - "reference": "a3c6479858989e242a2465972b4f7a8642baf0d4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/a3c6479858989e242a2465972b4f7a8642baf0d4", - "reference": "a3c6479858989e242a2465972b4f7a8642baf0d4", - "shasum": "" - }, - "require": { - "doctrine/persistence": "^2.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^1.0", - "phpstan/phpstan": "^0.11", - "phpstan/phpstan-phpunit": "^0.11", - "phpunit/phpunit": "^7.0", - "squizlabs/php_codesniffer": "^3.0", - "symfony/phpunit-bridge": "^4.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "lib/Doctrine/Common" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, persistence interfaces, proxies, event system and much more.", - "homepage": "https://www.doctrine-project.org/projects/common.html", - "keywords": [ - "common", - "doctrine", - "php" - ], - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon", - "type": "tidelift" - } - ], - "time": "2020-06-05T16:59:53+00:00" - }, - { - "name": "doctrine/instantiator", - "version": "1.3.1", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", - "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "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" - ], - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", - "type": "tidelift" - } - ], - "time": "2020-05-29T17:27:14+00:00" - }, - { - "name": "felixfbecker/advanced-json-rpc", - "version": "v3.1.1", - "source": { - "type": "git", - "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", - "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/0ed363f8de17d284d479ec813c9ad3f6834b5c40", - "reference": "0ed363f8de17d284d479ec813c9ad3f6834b5c40", - "shasum": "" - }, - "require": { - "netresearch/jsonmapper": "^1.0 || ^2.0", - "php": ">=7.0", - "phpdocumentor/reflection-docblock": "^4.0.0 || ^5.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "AdvancedJsonRpc\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "A more advanced JSONRPC implementation", - "support": { - "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", - "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/master" - }, - "time": "2020-03-11T15:21:41+00:00" - }, - { - "name": "felixfbecker/language-server-protocol", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "378801f6139bb74ac215d81cca1272af61df9a9f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/378801f6139bb74ac215d81cca1272af61df9a9f", - "reference": "378801f6139bb74ac215d81cca1272af61df9a9f", - "shasum": "" - }, - "require": { - "php": "^7.0" - }, - "require-dev": { - "phpstan/phpstan": "*", - "phpunit/phpunit": "^6.3", - "squizlabs/php_codesniffer": "^3.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "LanguageServerProtocol\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "PHP classes for the Language Server Protocol", - "keywords": [ - "language", - "microsoft", - "php", - "server" - ], - "support": { - "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.4.0" - }, - "time": "2019-06-23T21:03:50+00:00" - }, - { - "name": "jean85/pretty-package-versions", - "version": "1.2", - "source": { - "type": "git", - "url": "https://github.com/Jean85/pretty-package-versions.git", - "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/75c7effcf3f77501d0e0caa75111aff4daa0dd48", - "reference": "75c7effcf3f77501d0e0caa75111aff4daa0dd48", - "shasum": "" - }, - "require": { - "ocramius/package-versions": "^1.2.0", - "php": "^7.0" - }, - "require-dev": { - "phpunit/phpunit": "^6.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Jean85\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" - } - ], - "description": "A wrapper for ocramius/package-versions to get pretty versions strings", - "keywords": [ - "composer", - "package", - "release", - "versions" - ], - "time": "2018-06-13T13:22:40+00:00" - }, - { - "name": "myclabs/deep-copy", - "version": "1.10.1", - "source": { - "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", - "reference": "969b211f9a51aa1f6c01d1d2aef56d3bd91598e5", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "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" - ], - "funding": [ - { - "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", - "type": "tidelift" - } - ], - "time": "2020-06-29T13:22:24+00:00" - }, - { - "name": "netresearch/jsonmapper", - "version": "v2.1.0", - "source": { - "type": "git", - "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/e0f1e33a71587aca81be5cffbb9746510e1fe04e", - "reference": "e0f1e33a71587aca81be5cffbb9746510e1fe04e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.6" - }, - "require-dev": { - "phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4 || ~7.0", - "squizlabs/php_codesniffer": "~3.5" - }, - "type": "library", - "autoload": { - "psr-0": { - "JsonMapper": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "OSL-3.0" - ], - "authors": [ - { - "name": "Christian Weiske", - "email": "cweiske@cweiske.de", - "homepage": "http://github.com/cweiske/jsonmapper/", - "role": "Developer" - } - ], - "description": "Map nested JSON structures onto PHP classes", - "support": { - "email": "cweiske@cweiske.de", - "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/master" - }, - "time": "2020-04-16T18:48:43+00:00" - }, - { - "name": "nette/bootstrap", - "version": "v3.0.1", - "source": { - "type": "git", - "url": "https://github.com/nette/bootstrap.git", - "reference": "b45a1e33b6a44beb307756522396551e5a9ff249" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/bootstrap/zipball/b45a1e33b6a44beb307756522396551e5a9ff249", - "reference": "b45a1e33b6a44beb307756522396551e5a9ff249", - "shasum": "" - }, - "require": { - "nette/di": "^3.0", - "nette/utils": "^3.0", - "php": ">=7.1" - }, - "conflict": { - "tracy/tracy": "<2.6" - }, - "require-dev": { - "latte/latte": "^2.2", - "nette/application": "^3.0", - "nette/caching": "^3.0", - "nette/database": "^3.0", - "nette/forms": "^3.0", - "nette/http": "^3.0", - "nette/mail": "^3.0", - "nette/robot-loader": "^3.0", - "nette/safe-stream": "^2.2", - "nette/security": "^3.0", - "nette/tester": "^2.0", - "tracy/tracy": "^2.6" - }, - "suggest": { - "nette/robot-loader": "to use Configurator::createRobotLoader()", - "tracy/tracy": "to use Configurator::enableTracy()" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "๐Ÿ…ฑ Nette Bootstrap: the simple way to configure and bootstrap your Nette application.", - "homepage": "https://nette.org", - "keywords": [ - "bootstrapping", - "configurator", - "nette" - ], - "time": "2019-09-30T08:19:38+00:00" - }, - { - "name": "nette/di", - "version": "v3.0.1", - "source": { - "type": "git", - "url": "https://github.com/nette/di.git", - "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/di/zipball/4aff517a1c6bb5c36fa09733d4cea089f529de6d", - "reference": "4aff517a1c6bb5c36fa09733d4cea089f529de6d", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "nette/neon": "^3.0", - "nette/php-generator": "^3.2.2", - "nette/robot-loader": "^3.2", - "nette/schema": "^1.0", - "nette/utils": "^3.0", - "php": ">=7.1" - }, - "conflict": { - "nette/bootstrap": "<3.0" - }, - "require-dev": { - "nette/tester": "^2.2", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ], - "files": [ - "src/compatibility.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "๐Ÿ’Ž Nette Dependency Injection Container: Flexible, compiled and full-featured DIC with perfectly usable autowiring and support for all new PHP 7.1 features.", - "homepage": "https://nette.org", - "keywords": [ - "compiled", - "di", - "dic", - "factory", - "ioc", - "nette", - "static" - ], - "time": "2019-08-07T12:11:33+00:00" - }, - { - "name": "nette/finder", - "version": "v2.5.1", - "source": { - "type": "git", - "url": "https://github.com/nette/finder.git", - "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/finder/zipball/14164e1ddd69e9c5f627ff82a10874b3f5bba5fe", - "reference": "14164e1ddd69e9c5f627ff82a10874b3f5bba5fe", - "shasum": "" - }, - "require": { - "nette/utils": "^2.4 || ~3.0.0", - "php": ">=7.1" - }, - "conflict": { - "nette/nette": "<2.2" - }, - "require-dev": { - "nette/tester": "^2.0", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.5-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "๐Ÿ” Nette Finder: find files and directories with an intuitive API.", - "homepage": "https://nette.org", - "keywords": [ - "filesystem", - "glob", - "iterator", - "nette" - ], - "time": "2019-07-11T18:02:17+00:00" - }, - { - "name": "nette/neon", - "version": "v3.0.0", - "source": { - "type": "git", - "url": "https://github.com/nette/neon.git", - "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/neon/zipball/cbff32059cbdd8720deccf9e9eace6ee516f02eb", - "reference": "cbff32059cbdd8720deccf9e9eace6ee516f02eb", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "ext-json": "*", - "php": ">=7.0" - }, - "require-dev": { - "nette/tester": "^2.0", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "? Nette NEON: encodes and decodes NEON file format.", - "homepage": "http://ne-on.org", - "keywords": [ - "export", - "import", - "neon", - "nette", - "yaml" - ], - "time": "2019-02-05T21:30:40+00:00" - }, - { - "name": "nette/php-generator", - "version": "v3.3.1", - "source": { - "type": "git", - "url": "https://github.com/nette/php-generator.git", - "reference": "4240fd7adf499138c07b814ef9b9a6df9f6d7187" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/php-generator/zipball/4240fd7adf499138c07b814ef9b9a6df9f6d7187", - "reference": "4240fd7adf499138c07b814ef9b9a6df9f6d7187", - "shasum": "" - }, - "require": { - "nette/utils": "^2.4.2 || ~3.0.0", - "php": ">=7.1" - }, - "require-dev": { - "nette/tester": "^2.0", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.3-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "๐Ÿ˜ Nette PHP Generator: generates neat PHP code for you. Supports new PHP 7.3 features.", - "homepage": "https://nette.org", - "keywords": [ - "code", - "nette", - "php", - "scaffolding" - ], - "time": "2019-11-22T11:12:11+00:00" - }, - { - "name": "nette/robot-loader", - "version": "v3.2.0", - "source": { - "type": "git", - "url": "https://github.com/nette/robot-loader.git", - "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/robot-loader/zipball/0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", - "reference": "0712a0e39ae7956d6a94c0ab6ad41aa842544b5c", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "nette/finder": "^2.5", - "nette/utils": "^3.0", - "php": ">=7.1" - }, - "require-dev": { - "nette/tester": "^2.0", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "? Nette RobotLoader: high performance and comfortable autoloader that will search and autoload classes within your application.", - "homepage": "https://nette.org", - "keywords": [ - "autoload", - "class", - "interface", - "nette", - "trait" - ], - "time": "2019-03-08T21:57:24+00:00" - }, - { - "name": "nette/schema", - "version": "v1.0.1", - "source": { - "type": "git", - "url": "https://github.com/nette/schema.git", - "reference": "337117df1dade22e2ba1fdc4a4b832c1e9b06b76" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/337117df1dade22e2ba1fdc4a4b832c1e9b06b76", - "reference": "337117df1dade22e2ba1fdc4a4b832c1e9b06b76", - "shasum": "" - }, - "require": { - "nette/utils": "^3.0.1", - "php": ">=7.1" - }, - "require-dev": { - "nette/tester": "^2.2", - "tracy/tracy": "^2.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "๐Ÿ“ Nette Schema: validating data structures against a given Schema.", - "homepage": "https://nette.org", - "keywords": [ - "config", - "nette" - ], - "time": "2019-10-31T20:52:19+00:00" - }, - { - "name": "nette/utils", - "version": "v3.0.2", - "source": { - "type": "git", - "url": "https://github.com/nette/utils.git", - "reference": "c133e18c922dcf3ad07673077d92d92cef25a148" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/c133e18c922dcf3ad07673077d92d92cef25a148", - "reference": "c133e18c922dcf3ad07673077d92d92cef25a148", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "nette/tester": "~2.0", - "tracy/tracy": "^2.3" - }, - "suggest": { - "ext-gd": "to use Image", - "ext-iconv": "to use Strings::webalize() and toAscii()", - "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", - "ext-json": "to use Nette\\Utils\\Json", - "ext-mbstring": "to use Strings::lower() etc...", - "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()", - "ext-xml": "to use Strings::length() etc. when mbstring is not available" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause", - "GPL-2.0", - "GPL-3.0" - ], - "authors": [ - { - "name": "David Grudl", - "homepage": "https://davidgrudl.com" - }, - { - "name": "Nette Community", - "homepage": "https://nette.org/contributors" - } - ], - "description": "๐Ÿ›  Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", - "homepage": "https://nette.org", - "keywords": [ - "array", - "core", - "datetime", - "images", - "json", - "nette", - "paginator", - "password", - "slugify", - "string", - "unicode", - "utf-8", - "utility", - "validation" - ], - "time": "2019-10-21T20:40:16+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v4.3.0", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/9a9981c347c5c49d6dfe5cf826bb882b824080dc", - "reference": "9a9981c347c5c49d6dfe5cf826bb882b824080dc", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.0" - }, - "require-dev": { - "ircmaxell/php-yacc": "0.0.5", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.3-dev" - } - }, - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "time": "2019-11-08T13:50:10+00:00" - }, - { - "name": "openlss/lib-array2xml", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/nullivex/lib-array2xml.git", - "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", - "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "autoload": { - "psr-0": { - "LSS": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "Apache-2.0" - ], - "authors": [ - { - "name": "Bryan Tong", - "email": "bryan@nullivex.com", - "homepage": "https://www.nullivex.com" - }, - { - "name": "Tony Butler", - "email": "spudz76@gmail.com", - "homepage": "https://www.nullivex.com" - } - ], - "description": "Array2XML conversion library credit to lalit.org", - "homepage": "https://www.nullivex.com", - "keywords": [ - "array", - "array conversion", - "xml", - "xml conversion" - ], - "support": { - "issues": "https://github.com/nullivex/lib-array2xml/issues", - "source": "https://github.com/nullivex/lib-array2xml/tree/master" - }, - "time": "2019-03-29T20:06:56+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": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "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": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.2.2", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", - "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" - }, - "require-dev": { - "mockery/mockery": "~1.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.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" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2020-09-03T19:13:55+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.4.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" - }, - "require-dev": { - "ext-tokenizer": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "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": "2020-09-17T18:55:26+00:00" - }, - { - "name": "phpspec/prophecy", - "version": "1.12.1", - "source": { - "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/8ce87516be71aae9b956f81906aaf0338e0d8a2d", - "reference": "8ce87516be71aae9b956f81906aaf0338e0d8a2d", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.2", - "php": "^7.2 || ~8.0, <8.1", - "phpdocumentor/reflection-docblock": "^5.2", - "sebastian/comparator": "^3.0 || ^4.0", - "sebastian/recursion-context": "^3.0 || ^4.0" - }, - "require-dev": { - "phpspec/phpspec": "^6.0", - "phpunit/phpunit": "^8.0 || ^9.0 <9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.11.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": "2020-09-29T09:10:42+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "0.4.9", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "98a088b17966bdf6ee25c8a4b634df313d8aa531" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/98a088b17966bdf6ee25c8a4b634df313d8aa531", - "reference": "98a088b17966bdf6ee25c8a4b634df313d8aa531", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "consistence/coding-standard": "^3.5", - "ergebnis/composer-normalize": "^2.0.2", - "jakub-onderka/php-parallel-lint": "^0.9.2", - "phing/phing": "^2.16.0", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^0.12.26", - "phpstan/phpstan-strict-rules": "^0.12", - "phpunit/phpunit": "^6.3", - "slevomat/coding-standard": "^4.7.2", - "symfony/process": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - }, - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "time": "2020-08-03T20:32:43+00:00" - }, - { - "name": "phpstan/phpstan", - "version": "0.12.49", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpstan.git", - "reference": "9a6136c2b39d5214da78de37128d5fe08e5d5b05" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9a6136c2b39d5214da78de37128d5fe08e5d5b05", - "reference": "9a6136c2b39d5214da78de37128d5fe08e5d5b05", - "shasum": "" - }, - "require": { - "php": "^7.1|^8.0" - }, - "conflict": { - "phpstan/phpstan-shim": "*" - }, - "bin": [ - "phpstan", - "phpstan.phar" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.12-dev" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPStan - PHP Static Analysis Tool", - "funding": [ - { - "url": "https://github.com/ondrejmirtes", - "type": "github" - }, - { - "url": "https://www.patreon.com/phpstan", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/phpstan/phpstan", - "type": "tidelift" - } - ], - "time": "2020-10-12T14:10:44+00:00" - }, - { - "name": "phpunit/php-code-coverage", - "version": "8.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca6647ffddd2add025ab3f21644a441d7c146cdc", - "reference": "ca6647ffddd2add025ab3f21644a441d7c146cdc", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-xmlwriter": "*", - "php": "^7.3", - "phpunit/php-file-iterator": "^3.0", - "phpunit/php-text-template": "^2.0", - "phpunit/php-token-stream": "^4.0", - "sebastian/code-unit-reverse-lookup": "^2.0", - "sebastian/environment": "^5.0", - "sebastian/version": "^3.0", - "theseer/tokenizer": "^1.1.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "8.0-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" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-05-23T08:02:54+00:00" - }, - { - "name": "phpunit/php-file-iterator", - "version": "3.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/aa4be8575f26070b100fccb67faabb28f21f66f8", - "reference": "aa4be8575f26070b100fccb67faabb28f21f66f8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "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": "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" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:57:25+00:00" - }, - { - "name": "phpunit/php-invoker", - "version": "3.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-invoker.git", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "ext-pcntl": "*", - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-pcntl": "*" - }, - "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", - "role": "lead" - } - ], - "description": "Invoke callables with a timeout", - "homepage": "https://github.com/sebastianbergmann/php-invoker/", - "keywords": [ - "process" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:58:55+00:00" - }, - { - "name": "phpunit/php-text-template", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "18c887016e60e52477e54534956d7b47bc52cd84" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/18c887016e60e52477e54534956d7b47bc52cd84", - "reference": "18c887016e60e52477e54534956d7b47bc52cd84", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "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", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:03:05+00:00" - }, - { - "name": "phpunit/php-timer", - "version": "5.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "c9ff14f493699e2f6adee9fd06a0245b276643b7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/c9ff14f493699e2f6adee9fd06a0245b276643b7", - "reference": "c9ff14f493699e2f6adee9fd06a0245b276643b7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.0-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" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:00:25+00:00" - }, - { - "name": "phpunit/php-token-stream", - "version": "4.0.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": "^7.3 || ^8.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-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" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "abandoned": true, - "time": "2020-08-04T08:28:15+00:00" - }, - { - "name": "phpunit/phpunit", - "version": "9.2.6", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1c6a9e4312e209e659f1fce3ce88dd197c2448f6", - "reference": "1c6a9e4312e209e659f1fce3ce88dd197c2448f6", - "shasum": "" - }, - "require": { - "doctrine/instantiator": "^1.3.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-xml": "*", - "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.9.5", - "phar-io/manifest": "^1.0.3", - "phar-io/version": "^2.0.1", - "php": "^7.3", - "phpspec/prophecy": "^1.10.3", - "phpunit/php-code-coverage": "^8.0.2", - "phpunit/php-file-iterator": "^3.0.3", - "phpunit/php-invoker": "^3.0.2", - "phpunit/php-text-template": "^2.0.2", - "phpunit/php-timer": "^5.0.1", - "sebastian/code-unit": "^1.0.5", - "sebastian/comparator": "^4.0.3", - "sebastian/diff": "^4.0.1", - "sebastian/environment": "^5.1.2", - "sebastian/exporter": "^4.0.2", - "sebastian/global-state": "^4.0", - "sebastian/object-enumerator": "^4.0.2", - "sebastian/resource-operations": "^3.0.2", - "sebastian/type": "^2.1.1", - "sebastian/version": "^3.0.1" - }, - "require-dev": { - "ext-pdo": "*", - "phpspec/prophecy-phpunit": "^2.0" - }, - "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" - }, - "bin": [ - "phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "9.2-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ], - "files": [ - "src/Framework/Assert/Functions.php" - ] - }, - "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" - ], - "funding": [ - { - "url": "https://phpunit.de/donate.html", - "type": "custom" - }, - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-07-13T17:55:55+00:00" - }, - { - "name": "psr/container", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "time": "2017-02-14T16:28:37+00:00" - }, - { - "name": "psr/log", - "version": "1.1.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/446d54b4cb6bf489fc9d75f55843658e6f25d801", - "reference": "446d54b4cb6bf489fc9d75f55843658e6f25d801", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2019-11-01T11:05:21+00:00" - }, - { - "name": "sebastian/code-unit", - "version": "1.0.7", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit.git", - "reference": "59236be62b1bb9919e6d7f60b0b832dc05cef9ab" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/59236be62b1bb9919e6d7f60b0b832dc05cef9ab", - "reference": "59236be62b1bb9919e6d7f60b0b832dc05cef9ab", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0-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": "Collection of value objects that represent the PHP code units", - "homepage": "https://github.com/sebastianbergmann/code-unit", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-02T14:47:54+00:00" - }, - { - "name": "sebastian/code-unit-reverse-lookup", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "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": "Looks up which function or method a line of code belongs to", - "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:30:19+00:00" - }, - { - "name": "sebastian/comparator", - "version": "4.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "7a8ff306445707539c1a6397372a982a1ec55120" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/7a8ff306445707539c1a6397372a982a1ec55120", - "reference": "7a8ff306445707539c1a6397372a982a1ec55120", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/diff": "^4.0", - "sebastian/exporter": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-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": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - } - ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-30T06:47:25+00:00" - }, - { - "name": "sebastian/diff", - "version": "4.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "ffc949a1a2aae270ea064453d7535b82e4c32092" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ffc949a1a2aae270ea064453d7535b82e4c32092", - "reference": "ffc949a1a2aae270ea064453d7535b82e4c32092", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:32:55+00:00" - }, - { - "name": "sebastian/environment", - "version": "5.1.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/388b6ced16caa751030f6a69e588299fa09200ac", - "reference": "388b6ced16caa751030f6a69e588299fa09200ac", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "suggest": { - "ext-posix": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.1-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" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:52:38+00:00" - }, - { - "name": "sebastian/exporter", - "version": "4.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "reference": "d89cc98761b8cb5a1a235a6b703ae50d34080e65", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-mbstring": "*", - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-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" - ], - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:24:23+00:00" - }, - { - "name": "sebastian/global-state", - "version": "4.0.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bdb1e7c79e592b8c82cb1699be3c8743119b8a72", - "reference": "bdb1e7c79e592b8c82cb1699be3c8743119b8a72", - "shasum": "" - }, - "require": { - "php": "^7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "ext-dom": "*", - "phpunit/phpunit": "^9.0" - }, - "suggest": { - "ext-uopz": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.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": "2020-02-07T06:11:37+00:00" - }, - { - "name": "sebastian/object-enumerator", - "version": "4.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "f6f5957013d84725427d361507e13513702888a4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f6f5957013d84725427d361507e13513702888a4", - "reference": "f6f5957013d84725427d361507e13513702888a4", - "shasum": "" - }, - "require": { - "php": ">=7.3", - "sebastian/object-reflector": "^2.0", - "sebastian/recursion-context": "^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-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/", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:55:06+00:00" - }, - { - "name": "sebastian/object-reflector", - "version": "2.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "d9d0ab3b12acb1768bc1e0a89b23c90d2043cbe5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/d9d0ab3b12acb1768bc1e0a89b23c90d2043cbe5", - "reference": "d9d0ab3b12acb1768bc1e0a89b23c90d2043cbe5", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "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": "Allows reflection of object attributes, including inherited and non-public ones", - "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:56:16+00:00" - }, - { - "name": "sebastian/recursion-context", - "version": "4.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "ed8c9cd355089134bc9cba421b5cfdd58f0eaef7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/ed8c9cd355089134bc9cba421b5cfdd58f0eaef7", - "reference": "ed8c9cd355089134bc9cba421b5cfdd58f0eaef7", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.0-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": "Adam Harvey", - "email": "aharvey@php.net" - } - ], - "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T05:17:32+00:00" - }, - { - "name": "sebastian/resource-operations", - "version": "3.0.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.0" - }, - "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": "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", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:45:17+00:00" - }, - { - "name": "sebastian/type", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fa592377f3923946cb90bf1f6a71ba2e5f229909" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fa592377f3923946cb90bf1f6a71ba2e5f229909", - "reference": "fa592377f3923946cb90bf1f6a71ba2e5f229909", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-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": "Collection of value objects that represent the types of the PHP type system", - "homepage": "https://github.com/sebastianbergmann/type", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-06T08:41:03+00:00" - }, - { - "name": "sebastian/version", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "c6c1022351a901512170118436c764e473f6de8c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", - "reference": "c6c1022351a901512170118436c764e473f6de8c", - "shasum": "" - }, - "require": { - "php": ">=7.3" - }, - "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": "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", - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-09-28T06:39:44+00:00" - }, - { - "name": "slevomat/coding-standard", - "version": "6.4.1", - "source": { - "type": "git", - "url": "https://github.com/slevomat/coding-standard.git", - "reference": "696dcca217d0c9da2c40d02731526c1e25b65346" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/696dcca217d0c9da2c40d02731526c1e25b65346", - "reference": "696dcca217d0c9da2c40d02731526c1e25b65346", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7", - "php": "^7.1 || ^8.0", - "phpstan/phpdoc-parser": "0.4.5 - 0.4.9", - "squizlabs/php_codesniffer": "^3.5.6" - }, - "require-dev": { - "phing/phing": "2.16.3", - "php-parallel-lint/php-parallel-lint": "1.2.0", - "phpstan/phpstan": "0.12.48", - "phpstan/phpstan-deprecation-rules": "0.12.5", - "phpstan/phpstan-phpunit": "0.12.16", - "phpstan/phpstan-strict-rules": "0.12.5", - "phpunit/phpunit": "7.5.20|8.5.5|9.4.0" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-master": "6.x-dev" - } - }, - "autoload": { - "psr-4": { - "SlevomatCodingStandard\\": "SlevomatCodingStandard" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", - "funding": [ - { - "url": "https://github.com/kukulich", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", - "type": "tidelift" - } - ], - "time": "2020-10-05T12:39:37+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.5.6", - "source": { - "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "e97627871a7eab2f70e59166072a6b767d5834e0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/e97627871a7eab2f70e59166072a6b767d5834e0", - "reference": "e97627871a7eab2f70e59166072a6b767d5834e0", - "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": "2020-08-10T04:50:15+00:00" - }, - { - "name": "symfony/console", - "version": "v4.4.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "f0aea3df20d15635b3cb9730ca5eea1c65b7f201" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/f0aea3df20d15635b3cb9730ca5eea1c65b7f201", - "reference": "f0aea3df20d15635b3cb9730ca5eea1c65b7f201", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.8", - "symfony/service-contracts": "^1.1|^2" - }, - "conflict": { - "symfony/dependency-injection": "<3.4", - "symfony/event-dispatcher": "<4.3|>=5", - "symfony/lock": "<4.4", - "symfony/process": "<3.3" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "^3.4|^4.0|^5.0", - "symfony/dependency-injection": "^3.4|^4.0|^5.0", - "symfony/event-dispatcher": "^4.3", - "symfony/lock": "^4.4|^5.0", - "symfony/process": "^3.4|^4.0|^5.0", - "symfony/var-dumper": "^4.3|^5.0" - }, - "suggest": { - "psr/log": "For using the console logger", - "symfony/event-dispatcher": "", - "symfony/lock": "", - "symfony/process": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Console Component", - "homepage": "https://symfony.com", - "time": "2019-12-01T10:06:17+00:00" - }, - { - "name": "symfony/finder", - "version": "v4.4.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "ce8743441da64c41e2a667b8eb66070444ed911e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ce8743441da64c41e2a667b8eb66070444ed911e", - "reference": "ce8743441da64c41e2a667b8eb66070444ed911e", - "shasum": "" - }, - "require": { - "php": "^7.1.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.4-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony Finder Component", - "homepage": "https://symfony.com", - "time": "2019-11-17T21:56:56+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.18.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", - "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.18-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "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" - ], - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2020-07-14T12:35:20+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f", - "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "time": "2019-11-27T14:18:11+00:00" - }, - { - "name": "symfony/polyfill-php73", - "version": "v1.13.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f", - "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.13-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "files": [ - "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "time": "2019-11-27T16:25:15+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v1.1.8", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/ffc7f5692092df31515df2a5ecf3b7302b3ddacf", - "reference": "ffc7f5692092df31515df2a5ecf3b7302b3ddacf", - "shasum": "" - }, - "require": { - "php": "^7.1.3", - "psr/container": "^1.0" - }, - "suggest": { - "symfony/service-implementation": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "time": "2019-10-14T12:27:06+00:00" - }, - { - "name": "theseer/tokenizer", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/theseer/tokenizer.git", - "reference": "75a63c33a8577608444246075ea0af0d052e452a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", - "reference": "75a63c33a8577608444246075ea0af0d052e452a", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": "^7.2 || ^8.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", - "funding": [ - { - "url": "https://github.com/theseer", - "type": "github" - } - ], - "time": "2020-07-12T23:59:07+00:00" - }, - { - "name": "vimeo/psalm", - "version": "3.11.2", - "source": { - "type": "git", - "url": "https://github.com/vimeo/psalm.git", - "reference": "d470903722cfcbc1cd04744c5491d3e6d13ec3d9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/d470903722cfcbc1cd04744c5491d3e6d13ec3d9", - "reference": "d470903722cfcbc1cd04744c5491d3e6d13ec3d9", - "shasum": "" - }, - "require": { - "amphp/amp": "^2.1", - "amphp/byte-stream": "^1.5", - "composer/semver": "^1.4", - "composer/xdebug-handler": "^1.1", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "felixfbecker/advanced-json-rpc": "^3.0.3", - "felixfbecker/language-server-protocol": "^1.4", - "netresearch/jsonmapper": "^1.0 || ^2.0", - "nikic/php-parser": "^4.3", - "ocramius/package-versions": "^1.2", - "openlss/lib-array2xml": "^1.0", - "php": "^7.1.3|^8", - "sebastian/diff": "^3.0 || ^4.0", - "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0", - "webmozart/glob": "^4.1", - "webmozart/path-util": "^2.3" - }, - "provide": { - "psalm/psalm": "self.version" - }, - "require-dev": { - "amphp/amp": "^2.4.2", - "bamarni/composer-bin-plugin": "^1.2", - "brianium/paratest": "^4.0.0", - "ext-curl": "*", - "php-coveralls/php-coveralls": "^2.2", - "phpmyadmin/sql-parser": "5.1.0", - "phpspec/prophecy": ">=1.9.0", - "phpunit/phpunit": "^7.5.16 || ^8.5 || ^9.0", - "psalm/plugin-phpunit": "^0.10", - "slevomat/coding-standard": "^5.0", - "squizlabs/php_codesniffer": "^3.5", - "symfony/process": "^4.3" - }, - "suggest": { - "ext-igbinary": "^2.0.5" - }, - "bin": [ - "psalm", - "psalm-language-server", - "psalm-plugin", - "psalm-refactor", - "psalter" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev", - "dev-2.x": "2.x-dev", - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psalm\\Plugin\\": "src/Psalm/Plugin", - "Psalm\\": "src/Psalm" - }, - "files": [ - "src/functions.php", - "src/spl_object_id.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Brown" - } - ], - "description": "A static analysis tool for finding errors in PHP applications", - "keywords": [ - "code", - "inspection", - "php" - ], - "time": "2020-04-13T12:47:11+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.9.1", - "source": { - "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", - "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", - "shasum": "" - }, - "require": { - "php": "^5.3.3 || ^7.0 || ^8.0", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "phpstan/phpstan": "<0.12.20", - "vimeo/psalm": "<3.9.1" - }, - "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": "2020-07-08T17:02:28+00:00" - }, - { - "name": "webmozart/glob", - "version": "4.1.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/glob.git", - "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/glob/zipball/3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", - "reference": "3cbf63d4973cf9d780b93d2da8eec7e4a9e63bbe", - "shasum": "" - }, - "require": { - "php": "^5.3.3|^7.0", - "webmozart/path-util": "^2.2" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1", - "symfony/filesystem": "^2.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "4.1-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Glob\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "A PHP implementation of Ant's glob.", - "support": { - "issues": "https://github.com/webmozart/glob/issues", - "source": "https://github.com/webmozart/glob/tree/master" - }, - "time": "2015-12-29T11:14:33+00:00" - }, - { - "name": "webmozart/path-util", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/webmozart/path-util.git", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "webmozart/assert": "~1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\PathUtil\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", - "support": { - "issues": "https://github.com/webmozart/path-util/issues", - "source": "https://github.com/webmozart/path-util/tree/2.3.0" - }, - "time": "2015-12-17T08:42:14+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^7.1 || ^8.0" - }, - "platform-dev": [], - "plugin-api-version": "1.1.0" -} From b180613fa488f85162c235e2fcfc893233285a46 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Fri, 12 Feb 2021 22:05:41 +0100 Subject: [PATCH 05/36] Sync static analysis psalm job With https://github.com/doctrine/.github --- .github/workflows/static-analysis.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 5c419c91..91710d75 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -52,10 +52,19 @@ jobs: - "7.4" steps: - - name: Checkout code - uses: actions/checkout@v2 + - name: "Checkout code" + uses: "actions/checkout@v2" - - name: Psalm - uses: docker://vimeo/psalm-github-actions + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" with: - composer_require_dev: true + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: "Install dependencies with Composer" + uses: "ramsey/composer-install@v1" + with: + dependency-versions: "highest" + + - name: "Run a static analysis with vimeo/psalm" + run: "vendor/bin/psalm --show-info=false --stats --output-format=github --threads=$(nproc)" From 5aa5403a3250f976e3d9b2d3ebacee4a6a117aba Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Fri, 12 Feb 2021 22:07:56 +0100 Subject: [PATCH 06/36] Ignore psalm issue Psalm is reporting an apparenlty unexistent issue reported in https://github.com/vimeo/psalm/issues/5193, for now this ignores those issues. --- psalm.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/psalm.xml b/psalm.xml index d92c3445..548475e0 100644 --- a/psalm.xml +++ b/psalm.xml @@ -20,5 +20,17 @@ + + + + + + + + + + + + From 23869a2a3c7c2bdcd2c55a84fe9ff7cf9274189d Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 27 Nov 2020 14:07:59 +0100 Subject: [PATCH 07/36] Deprecate using doctrine/cache in favour of PSR-6 --- UPGRADE-2.2.md | 11 ++ composer.json | 4 +- .../Mapping/AbstractClassMetadataFactory.php | 64 ++++++++- .../Mapping/ClassMetadataFactoryTest.php | 122 +++++++++++++++--- .../Mapping/TestClassMetadataFactory.php | 5 + 5 files changed, 179 insertions(+), 27 deletions(-) create mode 100644 UPGRADE-2.2.md diff --git a/UPGRADE-2.2.md b/UPGRADE-2.2.md new file mode 100644 index 00000000..9b06aba4 --- /dev/null +++ b/UPGRADE-2.2.md @@ -0,0 +1,11 @@ +UPGRADE FROM 2.1 to 2.2 +======================= + +* Deprecated using doctrine/cache for metadata caching. The `setCacheDriver` and + `getCacheDriver` methods in `Doctrine\Persistence\Mapping\AbstractMetadata` + have been deprecated. Please use `getCache` and `setCache` with a PSR-6 + implementation instead. Note that even after switching to PSR-6, + `getCacheDriver` will return a cache instance that wraps the PSR-6 cache. + Note that if you use a custom implementation of doctrine/cache, the library + may not be able to provide a forward compatibility layer. The cache + implementation MUST extend the `Doctrine\Common\Cache\CacheProvider` class. diff --git a/composer.json b/composer.json index eade123e..87b2e4e7 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,9 @@ "doctrine/annotations": "^1.0", "doctrine/cache": "^1.0", "doctrine/collections": "^1.0", - "doctrine/event-manager": "^1.0" + "doctrine/event-manager": "^1.0", + "psr/cache": "^1.0", + "symfony/cache": "^4.4|^5.0" }, "require-dev": { "composer/package-versions-deprecated": "^1.11", diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 89dfdbb1..1852a05d 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -2,17 +2,27 @@ namespace Doctrine\Persistence\Mapping; +use BadMethodCallException; use Doctrine\Common\Cache\Cache; +use Doctrine\Common\Cache\CacheProvider; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Proxy; +use Psr\Cache\CacheItemPoolInterface; use ReflectionException; +use Symfony\Component\Cache\Adapter\DoctrineAdapter; +use Symfony\Component\Cache\DoctrineProvider; use function array_reverse; use function array_unshift; use function explode; +use function sprintf; +use function str_replace; use function strpos; use function strrpos; use function substr; +use function trigger_error; + +use const E_USER_DEPRECATED; /** * The ClassMetadataFactory is used to create ClassMetadata objects that contain all the @@ -28,11 +38,14 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory * * @var string */ - protected $cacheSalt = '$CLASSMETADATA'; + protected $cacheSalt = '__CLASSMETADATA__'; /** @var Cache|null */ private $cacheDriver; + /** @var CacheItemPoolInterface|null */ + private $cache; + /** @var ClassMetadata[] */ private $loadedMetadata = []; @@ -45,23 +58,54 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory /** * Sets the cache driver used by the factory to cache ClassMetadata instances. * + * @deprecated setCacheDriver was deprecated in doctrine/persistence 2.2 and will be removed in 3.0. Use setCache instead + * * @return void */ public function setCacheDriver(?Cache $cacheDriver = null) { + @trigger_error(sprintf('%s is deprecated. Use setCache() with a PSR-6 cache instead.', __METHOD__), E_USER_DEPRECATED); + $this->cacheDriver = $cacheDriver; + + if ($cacheDriver === null) { + $this->cache = null; + + return; + } + + if (! $cacheDriver instanceof CacheProvider) { + throw new BadMethodCallException('Cannot convert cache to PSR-6 cache'); + } + + $this->cache = new DoctrineAdapter($cacheDriver); } /** * Gets the cache driver used by the factory to cache ClassMetadata instances. * + * @deprecated getCacheDriver was deprecated in doctrine/persistence 2.2 and will be removed in 3.0. Use getCache instead + * * @return Cache|null */ public function getCacheDriver() { + @trigger_error(sprintf('%s is deprecated. Use getCache() instead.', __METHOD__), E_USER_DEPRECATED); + return $this->cacheDriver; } + public function setCache(CacheItemPoolInterface $cache): void + { + $this->cache = $cache; + $this->cacheDriver = new DoctrineProvider($cache); + } + + public function getCache(): ?CacheItemPoolInterface + { + return $this->cache; + } + /** * Returns an array of all the loaded metadata currently in memory. * @@ -174,19 +218,20 @@ public function getMetadataFor($className) $loadingException = null; try { - if ($this->cacheDriver) { - $cached = $this->cacheDriver->fetch($realClassName . $this->cacheSalt); + if ($this->cache) { + $cached = $this->cache->getItem($this->getCacheKey($realClassName))->get(); if ($cached instanceof ClassMetadata) { $this->loadedMetadata[$realClassName] = $cached; $this->wakeupReflection($cached, $this->getReflectionService()); } else { foreach ($this->loadMetadata($realClassName) as $loadedClassName) { - $this->cacheDriver->save( - $loadedClassName . $this->cacheSalt, - $this->loadedMetadata[$loadedClassName] - ); + $item = $this->cache->getItem($this->getCacheKey($loadedClassName)); + $item->set($this->loadedMetadata[$loadedClassName]); + $this->cache->saveDeferred($item); } + + $this->cache->commit(); } } else { $this->loadMetadata($realClassName); @@ -400,6 +445,11 @@ public function getReflectionService() return $this->reflectionService; } + protected function getCacheKey(string $realClassName): string + { + return str_replace('\\', '__', $realClassName) . $this->cacheSalt; + } + /** * Gets the real class name of a class name that could be a proxy. */ diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index 4e91999e..ac18a8f5 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -3,14 +3,16 @@ namespace Doctrine\Tests\Persistence\Mapping; use Doctrine\Common\Cache\ArrayCache; -use Doctrine\Common\Cache\Cache; use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\MappingException; use Doctrine\Tests\DoctrineTestCase; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\CacheItemPoolInterface; use stdClass; - -use function assert; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\DoctrineAdapter; +use Symfony\Component\Cache\DoctrineProvider; /** * @covers \Doctrine\Persistence\Mapping\AbstractClassMetadataFactory @@ -27,12 +29,31 @@ protected function setUp(): void $this->cmf = new TestClassMetadataFactory($driver, $metadata); } - public function testGetCacheDriver(): void + public function testSetGetCacheDriver(): void { self::assertNull($this->cmf->getCacheDriver()); + self::assertNull($this->cmf->getCache()); + $cache = new ArrayCache(); $this->cmf->setCacheDriver($cache); + self::assertSame($cache, $this->cmf->getCacheDriver()); + self::assertInstanceOf(DoctrineAdapter::class, $this->cmf->getCache()); + + $this->cmf->setCacheDriver(null); + self::assertNull($this->cmf->getCacheDriver()); + self::assertNull($this->cmf->getCache()); + } + + public function testSetGetCache(): void + { + self::assertNull($this->cmf->getCache()); + self::assertNull($this->cmf->getCacheDriver()); + + $cache = new ArrayAdapter(); + $this->cmf->setCache($cache); + self::assertSame($cache, $this->cmf->getCache()); + self::assertInstanceOf(DoctrineProvider::class, $this->cmf->getCacheDriver()); } public function testGetMetadataFor(): void @@ -61,22 +82,26 @@ public function testGetParentMetadata(): void public function testGetCachedMetadata(): void { $metadata = $this->createMock(ClassMetadata::class); - $cache = new ArrayCache(); - $cache->save(ChildEntity::class . '$CLASSMETADATA', $metadata); + $cache = new ArrayAdapter(); + $item = $cache->getItem($this->cmf->getCacheKey(ChildEntity::class)); + $item->set($metadata); + $cache->save($item); - $this->cmf->setCacheDriver($cache); + $this->cmf->setCache($cache); - self::assertSame($metadata, $this->cmf->getMetadataFor(ChildEntity::class)); + self::assertEquals($metadata, $this->cmf->getMetadataFor(ChildEntity::class)); } public function testCacheGetMetadataFor(): void { - $cache = new ArrayCache(); - $this->cmf->setCacheDriver($cache); + $cache = new ArrayAdapter(); + $this->cmf->setCache($cache); $loadedMetadata = $this->cmf->getMetadataFor(ChildEntity::class); - self::assertSame($loadedMetadata, $cache->fetch(ChildEntity::class . '$CLASSMETADATA')); + $item = $cache->getItem($this->cmf->getCacheKey(ChildEntity::class)); + self::assertTrue($item->isHit()); + self::assertEquals($loadedMetadata, $item->get()); } public function testGetAliasedMetadata(): void @@ -139,18 +164,77 @@ public function testWillFailOnFallbackFailureWithNotLoadedMetadata(): void */ public function testWillIgnoreCacheEntriesThatAreNotMetadataInstances(): void { - $cacheDriver = $this->createMock(Cache::class); - - $this->cmf->setCacheDriver($cacheDriver); - - $cacheDriver->expects(self::once())->method('fetch')->with('Foo$CLASSMETADATA')->willReturn(new stdClass()); + $key = $this->cmf->getCacheKey(RootEntity::class); + + $metadata = $this->cmf->metadata; + + $item = $this->createMock(CacheItemInterface::class); + + $item + ->expects(self::any()) + ->method('get') + ->willReturn(new stdClass()); + $item + ->expects(self::once()) + ->method('set') + ->with($metadata); + + $cacheDriver = $this->createMock(CacheItemPoolInterface::class); + $cacheDriver + ->expects(self::any()) + ->method('getItem') + ->with($key) + ->willReturn($item); + $cacheDriver + ->expects(self::once()) + ->method('saveDeferred') + ->with($item); + $cacheDriver + ->expects(self::once()) + ->method('commit'); + + $this->cmf->setCache($cacheDriver); + + self::assertSame($metadata, $this->cmf->getMetadataFor(RootEntity::class)); + } - $metadata = $this->createMock(ClassMetadata::class); - assert($metadata instanceof ClassMetadata); + public function testWillNotCacheFallbackMetadata(): void + { + $key = $this->cmf->getCacheKey('Foo'); + + $metadata = $this->cmf->metadata; + + $item = $this->createMock(CacheItemInterface::class); + + $item + ->expects(self::any()) + ->method('get') + ->willReturn(null); + $item + ->expects(self::never()) + ->method('set'); + + $cacheDriver = $this->createMock(CacheItemPoolInterface::class); + $cacheDriver + ->expects(self::once()) + ->method('getItem') + ->with($key) + ->willReturn($item); + $cacheDriver + ->expects(self::never()) + ->method('saveDeferred'); + $cacheDriver + ->expects(self::never()) + ->method('commit'); + + $this->cmf->setCache($cacheDriver); $fallbackCallback = $this->getMockBuilder(stdClass::class)->setMethods(['__invoke'])->getMock(); - $fallbackCallback->expects(self::any())->method('__invoke')->willReturn($metadata); + $fallbackCallback + ->expects(self::any()) + ->method('__invoke') + ->willReturn($metadata); $this->cmf->fallbackCallback = $fallbackCallback; diff --git a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php index 4faee70d..ddce6767 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php @@ -98,4 +98,9 @@ public function isTransient($class): bool return $class !== $name; } + + public function getCacheKey(string $realClassName): string + { + return parent::getCacheKey($realClassName); + } } From 9d16e4bfb2dc07d0585a5b5641e5a49ffc2efcf5 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Fri, 27 Nov 2020 15:09:06 +0100 Subject: [PATCH 08/36] Optimise storing metadata in cache --- .../Mapping/AbstractClassMetadataFactory.php | 18 +++++++++++++++--- .../Mapping/ClassMetadataFactoryTest.php | 9 +++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 1852a05d..4a2a6ad3 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -12,6 +12,9 @@ use Symfony\Component\Cache\Adapter\DoctrineAdapter; use Symfony\Component\Cache\DoctrineProvider; +use function array_combine; +use function array_keys; +use function array_map; use function array_reverse; use function array_unshift; use function explode; @@ -225,9 +228,18 @@ public function getMetadataFor($className) $this->wakeupReflection($cached, $this->getReflectionService()); } else { - foreach ($this->loadMetadata($realClassName) as $loadedClassName) { - $item = $this->cache->getItem($this->getCacheKey($loadedClassName)); - $item->set($this->loadedMetadata[$loadedClassName]); + $loadedMetadata = $this->loadMetadata($realClassName); + $classNames = array_combine( + array_map([$this, 'getCacheKey'], $loadedMetadata), + $loadedMetadata + ); + + foreach ($this->cache->getItems(array_keys($classNames)) as $item) { + if (! isset($classNames[$item->getKey()])) { + continue; + } + + $item->set($this->loadedMetadata[$classNames[$item->getKey()]]); $this->cache->saveDeferred($item); } diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index ac18a8f5..025d0b65 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -170,6 +170,10 @@ public function testWillIgnoreCacheEntriesThatAreNotMetadataInstances(): void $item = $this->createMock(CacheItemInterface::class); + $item + ->expects(self::any()) + ->method('getKey') + ->willReturn($key); $item ->expects(self::any()) ->method('get') @@ -185,6 +189,11 @@ public function testWillIgnoreCacheEntriesThatAreNotMetadataInstances(): void ->method('getItem') ->with($key) ->willReturn($item); + $cacheDriver + ->expects(self::once()) + ->method('getItems') + ->with([$key]) + ->willReturn([$item]); $cacheDriver ->expects(self::once()) ->method('saveDeferred') From 86f51b2eb738e51b424ccb77de548fb3e288e1e6 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Sat, 12 Dec 2020 15:21:16 +0100 Subject: [PATCH 09/36] Remove unnecessary invocation count matchers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grรฉgoire Paris --- .../Tests/Persistence/Mapping/ClassMetadataFactoryTest.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index 025d0b65..ceadd69d 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -171,11 +171,9 @@ public function testWillIgnoreCacheEntriesThatAreNotMetadataInstances(): void $item = $this->createMock(CacheItemInterface::class); $item - ->expects(self::any()) ->method('getKey') ->willReturn($key); $item - ->expects(self::any()) ->method('get') ->willReturn(new stdClass()); $item @@ -185,7 +183,6 @@ public function testWillIgnoreCacheEntriesThatAreNotMetadataInstances(): void $cacheDriver = $this->createMock(CacheItemPoolInterface::class); $cacheDriver - ->expects(self::any()) ->method('getItem') ->with($key) ->willReturn($item); @@ -216,7 +213,6 @@ public function testWillNotCacheFallbackMetadata(): void $item = $this->createMock(CacheItemInterface::class); $item - ->expects(self::any()) ->method('get') ->willReturn(null); $item @@ -241,7 +237,6 @@ public function testWillNotCacheFallbackMetadata(): void $fallbackCallback = $this->getMockBuilder(stdClass::class)->setMethods(['__invoke'])->getMock(); $fallbackCallback - ->expects(self::any()) ->method('__invoke') ->willReturn($metadata); From 3ee8ca742dbcb7d8c1c06820f1677c1f38582f7b Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 10 Feb 2021 09:28:18 +0100 Subject: [PATCH 10/36] Accept all major versions of psr/cache Co-authored-by: Alexander M. Turek --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 87b2e4e7..70ac3221 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "doctrine/cache": "^1.0", "doctrine/collections": "^1.0", "doctrine/event-manager": "^1.0", - "psr/cache": "^1.0", + "psr/cache": "^1.0|^2.0|^3.0", "symfony/cache": "^4.4|^5.0" }, "require-dev": { From 340f728e6fb39b4c5e1671e7c27dac2cef649cb1 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 23:21:41 +0100 Subject: [PATCH 11/36] Analyse tests directory with psalm --- psalm.xml | 2 ++ .../Persistence/Mapping/ClassMetadataFactoryTest.php | 8 +++----- .../Tests/Persistence/Mapping/SymfonyFileLocatorTest.php | 1 + .../Persistence/Mapping/TestClassMetadataFactory.php | 4 ++-- .../Persistence/RuntimePublicReflectionPropertyTest.php | 6 ++---- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/psalm.xml b/psalm.xml index 548475e0..da3a2cf1 100644 --- a/psalm.xml +++ b/psalm.xml @@ -9,8 +9,10 @@ > + + diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index 4e91999e..a256a4b5 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -148,11 +148,9 @@ public function testWillIgnoreCacheEntriesThatAreNotMetadataInstances(): void $metadata = $this->createMock(ClassMetadata::class); assert($metadata instanceof ClassMetadata); - $fallbackCallback = $this->getMockBuilder(stdClass::class)->setMethods(['__invoke'])->getMock(); - - $fallbackCallback->expects(self::any())->method('__invoke')->willReturn($metadata); - - $this->cmf->fallbackCallback = $fallbackCallback; + $this->cmf->fallbackCallback = static function () use ($metadata): ClassMetadata { + return $metadata; + }; self::assertSame($metadata, $this->cmf->getMetadataFor('Foo')); } diff --git a/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php b/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php index 82bdd4ab..45b62bb1 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php @@ -84,6 +84,7 @@ public function testInvalidCustomNamespaceSeparator(): void $path = __DIR__ . '/_files'; $prefix = 'Foo'; + /** @psalm-suppress NullArgument */ new SymfonyFileLocator([$path => $prefix], '.yml', null); } diff --git a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php index 4faee70d..d13dae89 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php @@ -14,13 +14,13 @@ class TestClassMetadataFactory extends AbstractClassMetadataFactory /** @var MappingDriver */ public $driver; - /** @var ClassMetadata|null */ + /** @var ClassMetadata */ public $metadata; /** @var callable|null */ public $fallbackCallback; - public function __construct(MappingDriver $driver, ?ClassMetadata $metadata) + public function __construct(MappingDriver $driver, ClassMetadata $metadata) { $this->driver = $driver; $this->metadata = $metadata; diff --git a/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php b/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php index 32bf2abf..7ef700a5 100644 --- a/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php +++ b/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php @@ -40,10 +40,8 @@ public function testSetValue(): void public function testGetValueOnProxyPublicProperty(): void { - $getCheckMock = $this->getMockBuilder('stdClass')->setMethods(['callGet'])->getMock(); - $getCheckMock->expects($this->never())->method('callGet'); - $initializer = static function () use ($getCheckMock): void { - call_user_func($getCheckMock); + $initializer = static function (): void { + self::fail('The initializer should not be called.'); }; $mockProxy = new RuntimePublicReflectionPropertyTestProxyMock(); From d2f7858c29acf146e16ff91cccb4685faa185815 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 23:22:48 +0100 Subject: [PATCH 12/36] Use proper fixtures for tests Instead of returning strings, TestFileDriver::loadMappingFile now returns array as the interface says. --- phpstan-baseline.neon | 5 - .../Mapping/ClassMetadataFactoryTest.php | 4 - .../Persistence/Mapping/FileDriverTest.php | 45 +++--- .../Mapping/Fixtures/AnotherGlobalClass.php | 9 ++ .../Mapping/Fixtures/GlobalClass.php | 9 ++ .../Mapping/Fixtures/TestClassMetadata.php | 151 ++++++++++++++++++ 6 files changed, 195 insertions(+), 28 deletions(-) create mode 100644 tests/Doctrine/Tests/Persistence/Mapping/Fixtures/AnotherGlobalClass.php create mode 100644 tests/Doctrine/Tests/Persistence/Mapping/Fixtures/GlobalClass.php create mode 100644 tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 549a86da..ca4f755a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2,11 +2,6 @@ parameters: ignoreErrors: - "#^Call to an undefined method Doctrine\\\\Tests\\\\Persistence\\\\TestObject\\:\\:.+\\(\\)\\.$#" - - - message: "#^Method Doctrine\\\\Tests\\\\Persistence\\\\Mapping\\\\TestFileDriver\\:\\:loadMappingFile\\(\\) should return array\\ but returns array\\\\.$#" - count: 2 - path: tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php - - message: "#^Parameter \\#3 \\$nsSeparator of class Doctrine\\\\Persistence\\\\Mapping\\\\Driver\\\\SymfonyFileLocator constructor expects string, null given\\.$#" count: 1 diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index a256a4b5..962b62a3 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -116,8 +116,6 @@ public function testWillFallbackOnNotLoadedMetadata(): void return $classMetadata; }; - $this->cmf->metadata = null; - self::assertSame($classMetadata, $this->cmf->getMetadataFor('Foo')); } @@ -127,8 +125,6 @@ public function testWillFailOnFallbackFailureWithNotLoadedMetadata(): void return null; }; - $this->cmf->metadata = null; - $this->expectException(MappingException::class); $this->cmf->getMetadataFor('Foo'); diff --git a/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php b/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php index b77a0185..12b480cd 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php @@ -6,7 +6,11 @@ use Doctrine\Persistence\Mapping\Driver\FileDriver; use Doctrine\Persistence\Mapping\Driver\FileLocator; use Doctrine\Tests\DoctrineTestCase; +use Doctrine\Tests\Persistence\Mapping\Fixtures\AnotherGlobalClass; +use Doctrine\Tests\Persistence\Mapping\Fixtures\GlobalClass; +use Doctrine\Tests\Persistence\Mapping\Fixtures\TestClassMetadata; use PHPUnit\Framework\MockObject\MockObject; +use stdClass; use function strpos; @@ -27,9 +31,9 @@ public function testGetElementFromGlobalFile(): void $driver = new TestFileDriver($this->newLocator()); $driver->setGlobalBasename('global'); - $element = $driver->getElement('stdGlobal'); + $element = $driver->getElement(GlobalClass::class); - self::assertSame('stdGlobal', $element); + self::assertSame(GlobalClass::class, $element->getName()); } public function testGetElementFromFile(): void @@ -37,12 +41,12 @@ public function testGetElementFromFile(): void $locator = $this->newLocator(); $locator->expects($this->once()) ->method('findMappingFile') - ->with($this->equalTo('stdClass')) + ->with($this->equalTo(stdClass::class)) ->will($this->returnValue(__DIR__ . '/_files/stdClass.yml')); $driver = new TestFileDriver($locator); - self::assertSame('stdClass', $driver->getElement('stdClass')); + self::assertSame(stdClass::class, $driver->getElement(stdClass::class)->getName()); } public function testGetElementUpdatesClassCache(): void @@ -52,16 +56,16 @@ public function testGetElementUpdatesClassCache(): void // findMappingFile should only be called once $locator->expects($this->once()) ->method('findMappingFile') - ->with($this->equalTo('stdClass')) + ->with($this->equalTo(stdClass::class)) ->will($this->returnValue(__DIR__ . '/_files/stdClass.yml')); $driver = new TestFileDriver($locator); // not cached - self::assertSame('stdClass', $driver->getElement('stdClass')); + self::assertSame(stdClass::class, $driver->getElement(stdClass::class)->getName()); // cached call - self::assertSame('stdClass', $driver->getElement('stdClass')); + self::assertSame(stdClass::class, $driver->getElement(stdClass::class)->getName()); } public function testGetAllClassNamesGlobalBasename(): void @@ -71,7 +75,7 @@ public function testGetAllClassNamesGlobalBasename(): void $classNames = $driver->getAllClassNames(); - self::assertSame(['stdGlobal', 'stdGlobal2'], $classNames); + self::assertSame([GlobalClass::class, AnotherGlobalClass::class], $classNames); } public function testGetAllClassNamesFromMappingFile(): void @@ -94,13 +98,13 @@ public function testGetAllClassNamesBothSources(): void $locator->expects($this->any()) ->method('getAllClassNames') ->with($this->equalTo('global')) - ->will($this->returnValue(['stdClass'])); + ->will($this->returnValue([stdClass::class])); $driver = new TestFileDriver($locator); $driver->setGlobalBasename('global'); $classNames = $driver->getAllClassNames(); - self::assertSame(['stdGlobal', 'stdGlobal2', 'stdClass'], $classNames); + self::assertSame([GlobalClass::class, AnotherGlobalClass::class, stdClass::class], $classNames); } public function testGetAllClassNamesBothSourcesNoDupes(): void @@ -109,14 +113,14 @@ public function testGetAllClassNamesBothSourcesNoDupes(): void $locator->expects($this->once()) ->method('getAllClassNames') ->with($this->equalTo('global')) - ->willReturn(['stdClass']); + ->willReturn([stdClass::class]); $driver = new TestFileDriver($locator); $driver->setGlobalBasename('global'); - $driver->getElement('stdClass'); + $driver->getElement(stdClass::class); $classNames = $driver->getAllClassNames(); - self::assertSame(['stdGlobal', 'stdGlobal2', 'stdClass'], $classNames); + self::assertSame([GlobalClass::class, AnotherGlobalClass::class, stdClass::class], $classNames); } public function testIsNotTransient(): void @@ -124,15 +128,15 @@ public function testIsNotTransient(): void $locator = $this->newLocator(); $locator->expects($this->once()) ->method('fileExists') - ->with($this->equalTo('stdClass')) + ->with($this->equalTo(stdClass::class)) ->will($this->returnValue(true)); $driver = new TestFileDriver($locator); $driver->setGlobalBasename('global'); - self::assertFalse($driver->isTransient('stdClass')); - self::assertFalse($driver->isTransient('stdGlobal')); - self::assertFalse($driver->isTransient('stdGlobal2')); + self::assertFalse($driver->isTransient(stdClass::class)); + self::assertFalse($driver->isTransient(GlobalClass::class)); + self::assertFalse($driver->isTransient(AnotherGlobalClass::class)); } public function testIsTransient(): void @@ -176,10 +180,13 @@ class TestFileDriver extends FileDriver protected function loadMappingFile($file) { if (strpos($file, 'global.yml') !== false) { - return ['stdGlobal' => 'stdGlobal', 'stdGlobal2' => 'stdGlobal2']; + return [ + GlobalClass::class => new TestClassMetadata(GlobalClass::class), + AnotherGlobalClass::class => new TestClassMetadata(AnotherGlobalClass::class), + ]; } - return ['stdClass' => 'stdClass']; + return [stdClass::class => new TestClassMetadata(stdClass::class)]; } /** diff --git a/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/AnotherGlobalClass.php b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/AnotherGlobalClass.php new file mode 100644 index 00000000..5f20aec3 --- /dev/null +++ b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/AnotherGlobalClass.php @@ -0,0 +1,9 @@ +className = $className; + } + + /** + * @psalm-return class-string + */ + public function getName(): string + { + return $this->className; + } + + /** + * @return string[] + */ + public function getIdentifier(): array + { + return ['id']; + } + + public function getReflectionClass(): ReflectionClass + { + return new ReflectionClass($this->getName()); + } + + /** + * {@inheritDoc} + */ + public function isIdentifier($fieldName): bool + { + return false; + } + + /** + * {@inheritDoc} + */ + public function hasField($fieldName): bool + { + return false; + } + + /** + * {@inheritDoc} + */ + public function hasAssociation($fieldName) + { + return false; + } + + /** + * {@inheritDoc} + */ + public function isSingleValuedAssociation($fieldName) + { + return false; + } + + /** + * {@inheritDoc} + */ + public function isCollectionValuedAssociation($fieldName) + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getFieldNames(): array + { + return []; + } + + /** + * {@inheritDoc} + */ + public function getIdentifierFieldNames(): array + { + return []; + } + + /** + * {@inheritDoc} + */ + public function getAssociationNames(): array + { + return []; + } + + /** + * {@inheritDoc} + */ + public function getTypeOfField($fieldName) + { + throw new LogicException('Not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getAssociationTargetClass($assocName) + { + throw new LogicException('Not implemented'); + } + + /** + * {@inheritDoc} + */ + public function isAssociationInverseSide($assocName): bool + { + return false; + } + + /** + * {@inheritDoc} + */ + public function getAssociationMappedByTargetField($assocName) + { + throw new LogicException('Not implemented'); + } + + /** + * {@inheritDoc} + */ + public function getIdentifierValues($object): array + { + return []; + } +} From 7d98c1956d62687c9e5f391e6011b2995636d21a Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 19 Dec 2020 23:29:43 +0100 Subject: [PATCH 13/36] Add missing return type declarations --- lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php | 2 ++ lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php | 4 ++++ .../Reflection/TypedNoDefaultReflectionProperty.php | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php index 8ea1b053..bb977896 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php @@ -113,6 +113,8 @@ public function getPaths() * Append exclude lookup paths to metadata driver. * * @param string[] $paths + * + * @return void */ public function addExcludePaths(array $paths) { diff --git a/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php index 208a3341..00cf4397 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php @@ -141,6 +141,8 @@ public function getAllClassNames() * @param string $file The mapping file to load. * * @return ClassMetadata[] + * + * @psalm-return array */ abstract protected function loadMappingFile($file); @@ -187,6 +189,8 @@ public function getLocator() /** * Sets the locator used to discover mapping files by className. + * + * @return void */ public function setLocator(FileLocator $locator) { diff --git a/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php b/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php index 8c0479c1..3a54cb85 100644 --- a/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php +++ b/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php @@ -34,7 +34,7 @@ public function setValue($object, $value = null) if ($value === null && $this->hasType() && ! $this->getType()->allowsNull()) { $propertyName = $this->getName(); - $unsetter = function () use ($propertyName) { + $unsetter = function () use ($propertyName): void { unset($this->$propertyName); }; $unsetter = $unsetter->bindTo($object, $this->getDeclaringClass()->getName()); From ef5b70d5a1a8e24970f346f38c30dcc10f8c15c2 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 2 Jan 2021 11:43:24 +0100 Subject: [PATCH 14/36] Move Psalm issue to Psalm config --- psalm.xml | 5 +++++ .../Tests/Persistence/Mapping/SymfonyFileLocatorTest.php | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/psalm.xml b/psalm.xml index da3a2cf1..e0dc9e68 100644 --- a/psalm.xml +++ b/psalm.xml @@ -34,5 +34,10 @@ + + + + + diff --git a/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php b/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php index 45b62bb1..82bdd4ab 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php @@ -84,7 +84,6 @@ public function testInvalidCustomNamespaceSeparator(): void $path = __DIR__ . '/_files'; $prefix = 'Foo'; - /** @psalm-suppress NullArgument */ new SymfonyFileLocator([$path => $prefix], '.yml', null); } From 12a05f8d1ca070f491b25a82ba1b8e9448da9f21 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 17 Feb 2021 18:02:42 +0100 Subject: [PATCH 15/36] Introduce proxy class name resolvers (#145) --- .../Mapping/AbstractClassMetadataFactory.php | 32 ++++++++++++++++--- .../Mapping/ProxyClassNameResolver.php | 12 +++++++ 2 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 4a2a6ad3..20b254a9 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -58,6 +58,9 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory /** @var ReflectionService|null */ private $reflectionService = null; + /** @var ProxyClassNameResolver|null */ + private $proxyClassNameResolver = null; + /** * Sets the cache driver used by the factory to cache ClassMetadata instances. * @@ -140,6 +143,11 @@ public function getAllMetadata() return $metadata; } + public function setProxyClassNameResolver(ProxyClassNameResolver $resolver): void + { + $this->proxyClassNameResolver = $resolver; + } + /** * Lazy initialization of this stuff, especially the metadata driver, * since these are not needed at all when a metadata cache is active. @@ -467,12 +475,26 @@ protected function getCacheKey(string $realClassName): string */ private function getRealClass(string $class): string { - $pos = strrpos($class, '\\' . Proxy::MARKER . '\\'); - - if ($pos === false) { - return $class; + if ($this->proxyClassNameResolver === null) { + $this->createDefaultProxyClassNameResolver(); } - return substr($class, $pos + Proxy::MARKER_LENGTH + 2); + return $this->proxyClassNameResolver->resolveClassName($class); + } + + private function createDefaultProxyClassNameResolver(): void + { + $this->proxyClassNameResolver = new class implements ProxyClassNameResolver { + public function resolveClassName(string $className): string + { + $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); + + if ($pos === false) { + return $className; + } + + return substr($className, $pos + Proxy::MARKER_LENGTH + 2); + } + }; } } diff --git a/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php b/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php new file mode 100644 index 00000000..8df7a536 --- /dev/null +++ b/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php @@ -0,0 +1,12 @@ + Date: Sat, 20 Mar 2021 20:46:00 +0100 Subject: [PATCH 16/36] Remove unnecessary github actions branch filters --- .github/workflows/coding-standards.yml | 2 -- .github/workflows/static-analysis.yml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index e325475b..85d61d1c 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -5,11 +5,9 @@ on: pull_request: branches: - "*.x" - - "master" push: branches: - "*.x" - - "master" env: COMPOSER_ROOT_VERSION: "2.1" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 91710d75..19fa6b0a 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -5,11 +5,9 @@ on: pull_request: branches: - "*.x" - - "master" push: branches: - "*.x" - - "master" env: COMPOSER_ROOT_VERSION: "2.1" From 1529f39f59b75d0aab33b38ef3f94df267293057 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Thu, 1 Apr 2021 20:00:39 +0200 Subject: [PATCH 17/36] Add class-string typehint --- lib/Doctrine/Persistence/Mapping/ClassMetadata.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php index 7dc556c8..5b60d2cd 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php @@ -120,6 +120,8 @@ public function getTypeOfField($fieldName); * @param string $assocName * * @return string + * + * @psalm-return class-string */ public function getAssociationTargetClass($assocName); From 098b4b3d3b7e048ac1b5724c47271fe4d0d0e1c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Sat, 3 Apr 2021 12:27:30 +0200 Subject: [PATCH 18/36] Describe $orderBy more accurately --- lib/Doctrine/Persistence/ObjectRepository.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Doctrine/Persistence/ObjectRepository.php b/lib/Doctrine/Persistence/ObjectRepository.php index 1450e95e..dbfad989 100644 --- a/lib/Doctrine/Persistence/ObjectRepository.php +++ b/lib/Doctrine/Persistence/ObjectRepository.php @@ -47,6 +47,7 @@ public function findAll(); * * @throws UnexpectedValueException * + * @psalm-param array $orderBy * @psalm-return T[] */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null); From f6575c2e7f5a76a5387207736be49c1cb5c7161a Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Fri, 2 Apr 2021 19:17:31 +0200 Subject: [PATCH 19/36] Add generics to Proxy --- .../Mapping/AbstractClassMetadataFactory.php | 11 +++++++++++ .../Persistence/Mapping/ProxyClassNameResolver.php | 7 +++++-- lib/Doctrine/Persistence/Proxy.php | 2 ++ phpstan-baseline.neon | 6 ++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 20b254a9..4bd2741e 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -472,6 +472,10 @@ protected function getCacheKey(string $realClassName): string /** * Gets the real class name of a class name that could be a proxy. + * + * @template T of object + * @psalm-param class-string>|class-string $class + * @psalm-return class-string */ private function getRealClass(string $class): string { @@ -485,14 +489,21 @@ private function getRealClass(string $class): string private function createDefaultProxyClassNameResolver(): void { $this->proxyClassNameResolver = new class implements ProxyClassNameResolver { + /** + * @template T of object + * @psalm-param class-string>|class-string $className + * @psalm-return class-string + */ public function resolveClassName(string $className): string { $pos = strrpos($className, '\\' . Proxy::MARKER . '\\'); if ($pos === false) { + /** @psalm-var class-string */ return $className; } + /** @psalm-var class-string */ return substr($className, $pos + Proxy::MARKER_LENGTH + 2); } }; diff --git a/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php b/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php index 8df7a536..bfb433ff 100644 --- a/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php +++ b/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php @@ -2,11 +2,14 @@ namespace Doctrine\Persistence\Mapping; +use Doctrine\Persistence\Proxy; + interface ProxyClassNameResolver { /** - * @psalm-param class-string $className - * @psalm-return class-string + * @template T of object + * @psalm-param class-string>|class-string $className + * @psalm-return class-string */ public function resolveClassName(string $className): string; } diff --git a/lib/Doctrine/Persistence/Proxy.php b/lib/Doctrine/Persistence/Proxy.php index 0d21a708..677e4795 100644 --- a/lib/Doctrine/Persistence/Proxy.php +++ b/lib/Doctrine/Persistence/Proxy.php @@ -4,6 +4,8 @@ /** * Interface for proxy classes. + * + * @template T of object */ interface Proxy { diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ca4f755a..02cdbc1d 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6,3 +6,9 @@ parameters: message: "#^Parameter \\#3 \\$nsSeparator of class Doctrine\\\\Persistence\\\\Mapping\\\\Driver\\\\SymfonyFileLocator constructor expects string, null given\\.$#" count: 1 path: tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php + + - + # Remove it when https://github.com/phpstan/phpstan/issues/4803 is solved + message: "#^Method Doctrine\\\\Persistence\\\\Mapping\\\\AbstractClassMetadataFactory\\:\\:getRealClass\\(\\) should return class\\-string\\ but returns class\\-string\\\\|T of object\\>\\.$#" + count: 1 + path: lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php From c0fbcd8b549fe43cd1e945011e209bf947ccb7a1 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 13 Apr 2021 12:29:47 +0200 Subject: [PATCH 20/36] Make getCache method internal (#166) --- .../Mapping/AbstractClassMetadataFactory.php | 4 ++-- .../Mapping/ClassMetadataFactoryTest.php | 20 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 4bd2741e..0242ce0b 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -90,7 +90,7 @@ public function setCacheDriver(?Cache $cacheDriver = null) /** * Gets the cache driver used by the factory to cache ClassMetadata instances. * - * @deprecated getCacheDriver was deprecated in doctrine/persistence 2.2 and will be removed in 3.0. Use getCache instead + * @deprecated getCacheDriver was deprecated in doctrine/persistence 2.2 and will be removed in 3.0. * * @return Cache|null */ @@ -107,7 +107,7 @@ public function setCache(CacheItemPoolInterface $cache): void $this->cacheDriver = new DoctrineProvider($cache); } - public function getCache(): ?CacheItemPoolInterface + final protected function getCache(): ?CacheItemPoolInterface { return $this->cache; } diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index 2cb60117..560006c3 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -3,12 +3,14 @@ namespace Doctrine\Tests\Persistence\Mapping; use Doctrine\Common\Cache\ArrayCache; +use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory; use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\MappingException; use Doctrine\Tests\DoctrineTestCase; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; +use ReflectionMethod; use stdClass; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\DoctrineAdapter; @@ -32,27 +34,27 @@ protected function setUp(): void public function testSetGetCacheDriver(): void { self::assertNull($this->cmf->getCacheDriver()); - self::assertNull($this->cmf->getCache()); + self::assertNull(self::getCache($this->cmf)); $cache = new ArrayCache(); $this->cmf->setCacheDriver($cache); self::assertSame($cache, $this->cmf->getCacheDriver()); - self::assertInstanceOf(DoctrineAdapter::class, $this->cmf->getCache()); + self::assertInstanceOf(DoctrineAdapter::class, self::getCache($this->cmf)); $this->cmf->setCacheDriver(null); self::assertNull($this->cmf->getCacheDriver()); - self::assertNull($this->cmf->getCache()); + self::assertNull(self::getCache($this->cmf)); } public function testSetGetCache(): void { - self::assertNull($this->cmf->getCache()); + self::assertNull(self::getCache($this->cmf)); self::assertNull($this->cmf->getCacheDriver()); $cache = new ArrayAdapter(); $this->cmf->setCache($cache); - self::assertSame($cache, $this->cmf->getCache()); + self::assertSame($cache, self::getCache($this->cmf)); self::assertInstanceOf(DoctrineProvider::class, $this->cmf->getCacheDriver()); } @@ -236,6 +238,14 @@ public function testWillNotCacheFallbackMetadata(): void self::assertSame($metadata, $this->cmf->getMetadataFor('Foo')); } + + private static function getCache(AbstractClassMetadataFactory $classMetadataFactory): ?CacheItemPoolInterface + { + $method = new ReflectionMethod($classMetadataFactory, 'getCache'); + $method->setAccessible(true); + + return $method->invoke($classMetadataFactory); + } } class RootEntity From 7ed67dfa4e72f7781e6c18bdf610854687ba53e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Mon, 19 Apr 2021 20:30:53 +0200 Subject: [PATCH 21/36] Upgrade to doctrine/coding-standard 9 --- composer.json | 2 +- lib/Doctrine/Persistence/ManagerRegistry.php | 4 ++-- .../Persistence/Mapping/AbstractClassMetadataFactory.php | 8 ++++++-- lib/Doctrine/Persistence/Mapping/ClassMetadata.php | 1 - lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php | 1 - .../Persistence/Mapping/ProxyClassNameResolver.php | 4 +++- lib/Doctrine/Persistence/ObjectManager.php | 8 ++++---- lib/Doctrine/Persistence/ObjectRepository.php | 8 ++------ phpcs.xml.dist | 8 -------- 9 files changed, 18 insertions(+), 26 deletions(-) diff --git a/composer.json b/composer.json index 70ac3221..3b6eed4f 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "require-dev": { "composer/package-versions-deprecated": "^1.11", "phpstan/phpstan": "^0.12", - "doctrine/coding-standard": "^6.0 || ^8.0", + "doctrine/coding-standard": "^6.0 || ^9.0", "doctrine/common": "^3.0", "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", "vimeo/psalm": "^4.3.1" diff --git a/lib/Doctrine/Persistence/ManagerRegistry.php b/lib/Doctrine/Persistence/ManagerRegistry.php index 6f89e0c6..38e36a96 100644 --- a/lib/Doctrine/Persistence/ManagerRegistry.php +++ b/lib/Doctrine/Persistence/ManagerRegistry.php @@ -72,12 +72,12 @@ public function getManagerNames(); * * @param string $persistentObject The name of the persistent object. * @param string $persistentManagerName The object manager name (null for the default one). + * @psalm-param class-string $persistentObject * * @return ObjectRepository + * @psalm-return ObjectRepository * * @template T - * @psalm-param class-string $persistentObject - * @psalm-return ObjectRepository */ public function getRepository($persistentObject, $persistentManagerName = null); diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 0242ce0b..3d85d70e 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -473,9 +473,11 @@ protected function getCacheKey(string $realClassName): string /** * Gets the real class name of a class name that could be a proxy. * - * @template T of object * @psalm-param class-string>|class-string $class + * * @psalm-return class-string + * + * @template T of object */ private function getRealClass(string $class): string { @@ -490,9 +492,11 @@ private function createDefaultProxyClassNameResolver(): void { $this->proxyClassNameResolver = new class implements ProxyClassNameResolver { /** - * @template T of object * @psalm-param class-string>|class-string $className + * * @psalm-return class-string + * + * @template T of object */ public function resolveClassName(string $className): string { diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php index 5b60d2cd..daaa0954 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php @@ -120,7 +120,6 @@ public function getTypeOfField($fieldName); * @param string $assocName * * @return string - * * @psalm-return class-string */ public function getAssociationTargetClass($assocName); diff --git a/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php index 00cf4397..3f32aba3 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/FileDriver.php @@ -141,7 +141,6 @@ public function getAllClassNames() * @param string $file The mapping file to load. * * @return ClassMetadata[] - * * @psalm-return array */ abstract protected function loadMappingFile($file); diff --git a/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php b/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php index bfb433ff..a8a3fcc8 100644 --- a/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php +++ b/lib/Doctrine/Persistence/Mapping/ProxyClassNameResolver.php @@ -7,9 +7,11 @@ interface ProxyClassNameResolver { /** - * @template T of object * @psalm-param class-string>|class-string $className + * * @psalm-return class-string + * + * @template T of object */ public function resolveClassName(string $className): string; } diff --git a/lib/Doctrine/Persistence/ObjectManager.php b/lib/Doctrine/Persistence/ObjectManager.php index 1d6dc0f3..70f9e431 100644 --- a/lib/Doctrine/Persistence/ObjectManager.php +++ b/lib/Doctrine/Persistence/ObjectManager.php @@ -17,12 +17,12 @@ interface ObjectManager * * @param string $className The class name of the object to find. * @param mixed $id The identity of the object to find. + * @psalm-param class-string $className * * @return object|null The found object. + * @psalm-return T|null * * @template T - * @psalm-param class-string $className - * @psalm-return T|null */ public function find($className, $id); @@ -115,12 +115,12 @@ public function flush(); * Gets the repository for a class. * * @param string $className + * @psalm-param class-string $className * * @return ObjectRepository + * @psalm-return ObjectRepository * * @template T - * @psalm-param class-string $className - * @psalm-return ObjectRepository */ public function getRepository($className); diff --git a/lib/Doctrine/Persistence/ObjectRepository.php b/lib/Doctrine/Persistence/ObjectRepository.php index dbfad989..e6a2f550 100644 --- a/lib/Doctrine/Persistence/ObjectRepository.php +++ b/lib/Doctrine/Persistence/ObjectRepository.php @@ -17,7 +17,6 @@ interface ObjectRepository * @param mixed $id The identifier. * * @return object|null The object. - * * @psalm-return T|null */ public function find($id); @@ -26,7 +25,6 @@ public function find($id); * Finds all objects in the repository. * * @return array The objects. - * * @psalm-return T[] */ public function findAll(); @@ -42,13 +40,12 @@ public function findAll(); * @param string[]|null $orderBy * @param int|null $limit * @param int|null $offset + * @psalm-param array $orderBy * * @return object[] The objects. + * @psalm-return T[] * * @throws UnexpectedValueException - * - * @psalm-param array $orderBy - * @psalm-return T[] */ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $offset = null); @@ -58,7 +55,6 @@ public function findBy(array $criteria, ?array $orderBy = null, $limit = null, $ * @param mixed[] $criteria The criteria. * * @return object|null The object. - * * @psalm-return T|null */ public function findOneBy(array $criteria); diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 8f33cb41..1376d0e2 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -52,12 +52,4 @@ lib/Doctrine/Persistence/Mapping/MappingException.php - - - RuntimeReflectionServiceTest - - - - tests/Doctrine/Tests_PHP74/Persistence/Reflection/TypedNoDefaultReflectionPropertyTest.php - From b2845c1d405c135df444cd412d1fdb1397530db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Mon, 19 Apr 2021 20:32:48 +0200 Subject: [PATCH 22/36] Follow removal instructions --- phpstan-baseline.neon | 6 ------ 1 file changed, 6 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 02cdbc1d..ca4f755a 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6,9 +6,3 @@ parameters: message: "#^Parameter \\#3 \\$nsSeparator of class Doctrine\\\\Persistence\\\\Mapping\\\\Driver\\\\SymfonyFileLocator constructor expects string, null given\\.$#" count: 1 path: tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php - - - - # Remove it when https://github.com/phpstan/phpstan/issues/4803 is solved - message: "#^Method Doctrine\\\\Persistence\\\\Mapping\\\\AbstractClassMetadataFactory\\:\\:getRealClass\\(\\) should return class\\-string\\ but returns class\\-string\\\\|T of object\\>\\.$#" - count: 1 - path: lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php From b066680b62da651c2bd03555a18b4dfbc20f208a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Mon, 19 Apr 2021 20:48:34 +0200 Subject: [PATCH 23/36] Make the class metadata factory generic This should make a lot of static analysis issues vanish, because tools will be able to understand that they are guaranteed to receive some specialization of ClassMetadata, or that they should provide it. --- composer.json | 2 +- .../Mapping/AbstractClassMetadataFactory.php | 40 +++++++++++-------- .../Mapping/ClassMetadataFactory.php | 5 +++ 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/composer.json b/composer.json index 3b6eed4f..0872acb6 100644 --- a/composer.json +++ b/composer.json @@ -30,7 +30,7 @@ }, "require-dev": { "composer/package-versions-deprecated": "^1.11", - "phpstan/phpstan": "^0.12", + "phpstan/phpstan": "^0.12.84", "doctrine/coding-standard": "^6.0 || ^9.0", "doctrine/common": "^3.0", "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 3d85d70e..a9670e3c 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -33,6 +33,9 @@ * to a relational database. * * This class was abstracted from the ORM ClassMetadataFactory. + * + * @template CMTemplate of ClassMetadata + * @template-implements ClassMetadataFactory */ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory { @@ -49,7 +52,10 @@ abstract class AbstractClassMetadataFactory implements ClassMetadataFactory /** @var CacheItemPoolInterface|null */ private $cache; - /** @var ClassMetadata[] */ + /** + * @var ClassMetadata[] + * @psalm-var CMTemplate[] + */ private $loadedMetadata = []; /** @var bool */ @@ -116,6 +122,7 @@ final protected function getCache(): ?CacheItemPoolInterface * Returns an array of all the loaded metadata currently in memory. * * @return ClassMetadata[] + * @psalm-return CMTemplate[] */ public function getLoadedMetadata() { @@ -123,10 +130,7 @@ public function getLoadedMetadata() } /** - * Forces the factory to load the metadata of all classes known to the underlying - * mapping driver. - * - * @return ClassMetadata[] The ClassMetadata instances of all mapped classes. + * {@inheritDoc} */ public function getAllMetadata() { @@ -176,6 +180,8 @@ abstract protected function getDriver(); /** * Wakes up reflection after ClassMetadata gets unserialized from cache. * + * @psalm-param CMTemplate $class + * * @return void */ abstract protected function wakeupReflection(ClassMetadata $class, ReflectionService $reflService); @@ -183,6 +189,8 @@ abstract protected function wakeupReflection(ClassMetadata $class, ReflectionSer /** * Initializes Reflection after ClassMetadata was constructed. * + * @psalm-param CMTemplate $class + * * @return void */ abstract protected function initializeReflection(ClassMetadata $class, ReflectionService $reflService); @@ -192,16 +200,14 @@ abstract protected function initializeReflection(ClassMetadata $class, Reflectio * * This method should return false for mapped superclasses or embedded classes. * + * @psalm-param CMTemplate $class + * * @return bool */ abstract protected function isEntity(ClassMetadata $class); /** - * Gets the class metadata descriptor for a class. - * - * @param string $className The name of the class. - * - * @return ClassMetadata + * {@inheritDoc} * * @throws ReflectionException * @throws MappingException @@ -232,6 +238,7 @@ public function getMetadataFor($className) if ($this->cache) { $cached = $this->cache->getItem($this->getCacheKey($realClassName))->get(); if ($cached instanceof ClassMetadata) { + /** @psalm-var CMTemplate $cached */ $this->loadedMetadata[$realClassName] = $cached; $this->wakeupReflection($cached, $this->getReflectionService()); @@ -275,11 +282,7 @@ public function getMetadataFor($className) } /** - * Checks whether the factory has the metadata for a class loaded already. - * - * @param string $className - * - * @return bool TRUE if the metadata of the class in question is already loaded, FALSE otherwise. + * {@inheritDoc} */ public function hasMetadataFor($className) { @@ -291,8 +294,7 @@ public function hasMetadataFor($className) * * NOTE: This is only useful in very special cases, like when generating proxy classes. * - * @param string $className - * @param ClassMetadata $class + * {@inheritDoc} * * @return void */ @@ -395,6 +397,7 @@ protected function loadMetadata($name) * @param string $className * * @return ClassMetadata|null + * @psalm-return CMTemplate|null */ protected function onNotFoundMetadata($className) { @@ -409,6 +412,8 @@ protected function onNotFoundMetadata($className) * @param bool $rootEntityFound * @param string[] $nonSuperclassParents All parent class names * that are not marked as mapped superclasses. + * @psalm-param CMTemplate $class + * @psalm-param CMTemplate|null $parent * * @return void */ @@ -420,6 +425,7 @@ abstract protected function doLoadMetadata($class, $parent, $rootEntityFound, ar * @param string $className * * @return ClassMetadata + * @psalm-return CMTemplate */ abstract protected function newClassMetadataInstance($className); diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php index 8b78239f..f748f52e 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php @@ -4,6 +4,8 @@ /** * Contract for a Doctrine persistence layer ClassMetadata class to implement. + * + * @template T of ClassMetadata */ interface ClassMetadataFactory { @@ -12,6 +14,7 @@ interface ClassMetadataFactory * mapping driver. * * @return ClassMetadata[] The ClassMetadata instances of all mapped classes. + * @psalm-return T[] */ public function getAllMetadata(); @@ -21,6 +24,7 @@ public function getAllMetadata(); * @param string $className The name of the class. * * @return ClassMetadata + * @psalm-return T */ public function getMetadataFor($className); @@ -38,6 +42,7 @@ public function hasMetadataFor($className); * * @param string $className * @param ClassMetadata $class + * @psalm-param T $class */ public function setMetadataFor($className, $class); From b1219acc0497c6ff0f911ae17f6991d1b48dafa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Paris?= Date: Tue, 20 Apr 2021 22:47:31 +0200 Subject: [PATCH 24/36] Pin SA tools to a specific version This ensures baseline files are generated with the same version by everyone, and should stabilize the build. --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 0872acb6..0da82d9b 100644 --- a/composer.json +++ b/composer.json @@ -30,11 +30,11 @@ }, "require-dev": { "composer/package-versions-deprecated": "^1.11", - "phpstan/phpstan": "^0.12.84", + "phpstan/phpstan": "0.12.84", "doctrine/coding-standard": "^6.0 || ^9.0", "doctrine/common": "^3.0", "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", - "vimeo/psalm": "^4.3.1" + "vimeo/psalm": "4.7.0" }, "conflict": { "doctrine/common": "<2.10@dev" From 554f03fbeca5b5c9a6d4a4d04155bcbc1738d455 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Wed, 21 Apr 2021 00:16:29 +0200 Subject: [PATCH 25/36] Use class-string for parameters and vars --- .../Persistence/AbstractManagerRegistry.php | 6 +++++- .../Mapping/AbstractClassMetadataFactory.php | 5 +++++ lib/Doctrine/Persistence/Mapping/ClassMetadata.php | 1 + .../Persistence/Mapping/ClassMetadataFactory.php | 1 + .../Persistence/Mapping/Driver/AnnotationDriver.php | 2 +- .../Persistence/Mapping/Driver/MappingDriver.php | 1 + .../Persistence/Mapping/ReflectionService.php | 7 +++++++ phpstan-baseline.neon | 5 +++++ .../Persistence/Mapping/AnnotationDriverTest.php | 2 +- .../Tests/Persistence/Mapping/DriverChainTest.php | 11 +++++++---- .../Tests/Persistence/Mapping/FileDriverTest.php | 13 +++++++------ .../Mapping/Fixtures/Manager/Manager.php | 9 +++++++++ .../Tests/Persistence/Mapping/Fixtures/Model.php | 9 +++++++++ .../Persistence/Mapping/Fixtures/NotLoadedClass.php | 9 +++++++++ .../Mapping/RuntimeReflectionServiceTest.php | 3 ++- .../Mapping/TestClassMetadataFactory.php | 1 + .../Tests/Persistence/PersistentObjectTest.php | 4 ++-- .../RuntimePublicReflectionPropertyTest.php | 5 +++-- 18 files changed, 76 insertions(+), 18 deletions(-) create mode 100644 tests/Doctrine/Tests/Persistence/Mapping/Fixtures/Manager/Manager.php create mode 100644 tests/Doctrine/Tests/Persistence/Mapping/Fixtures/Model.php create mode 100644 tests/Doctrine/Tests/Persistence/Mapping/Fixtures/NotLoadedClass.php diff --git a/lib/Doctrine/Persistence/AbstractManagerRegistry.php b/lib/Doctrine/Persistence/AbstractManagerRegistry.php index 63ff9b02..4fb8af7e 100644 --- a/lib/Doctrine/Persistence/AbstractManagerRegistry.php +++ b/lib/Doctrine/Persistence/AbstractManagerRegistry.php @@ -29,7 +29,10 @@ abstract class AbstractManagerRegistry implements ManagerRegistry /** @var string */ private $defaultManager; - /** @var string */ + /** + * @var string + * @psalm-var class-string + */ private $proxyInterfaceName; /** @@ -39,6 +42,7 @@ abstract class AbstractManagerRegistry implements ManagerRegistry * @param string $defaultConnection * @param string $defaultManager * @param string $proxyInterfaceName + * @psalm-param class-string $proxyInterfaceName */ public function __construct($name, array $connections, array $managers, $defaultConnection, $defaultManager, $proxyInterfaceName) { diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index a9670e3c..f4c06e40 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -167,6 +167,7 @@ abstract protected function initialize(); * @param string $simpleClassName * * @return string + * @psalm-return class-string */ abstract protected function getFqcnFromAlias($namespaceAlias, $simpleClassName); @@ -307,6 +308,7 @@ public function setMetadataFor($className, $class) * Gets an array of parent classes for the given entity class. * * @param string $name + * @psalm-param class-string $name * * @return string[] */ @@ -337,6 +339,7 @@ protected function getParentClasses($name) * should be used for reflection. * * @param string $name The name of the class for which the metadata should get loaded. + * @psalm-param class-string $name * * @return string[] */ @@ -431,6 +434,8 @@ abstract protected function newClassMetadataInstance($className); /** * {@inheritDoc} + * + * @psalm-param class-string|string $class */ public function isTransient($class) { diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php index daaa0954..60525b12 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php @@ -13,6 +13,7 @@ interface ClassMetadata * Gets the fully-qualified class name of this persistent class. * * @return string + * @psalm-return class-string */ public function getName(); diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php index f748f52e..a3d3babb 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php @@ -51,6 +51,7 @@ public function setMetadataFor($className, $class); * This is only the case if it is either mapped directly or as a MappedSuperclass. * * @param string $className + * @psalm-param class-string $className * * @return bool */ diff --git a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php index bb977896..96c21bf5 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php @@ -66,7 +66,7 @@ abstract class AnnotationDriver implements MappingDriver /** * Name of the entity annotations as keys. * - * @var string[] + * @var array */ protected $entityAnnotationClasses = []; diff --git a/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php index 2c395721..b54d528f 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/MappingDriver.php @@ -30,6 +30,7 @@ public function getAllClassNames(); * This is only the case if it is either mapped as an Entity or a MappedSuperclass. * * @param string $className + * @psalm-param class-string $className * * @return bool */ diff --git a/lib/Doctrine/Persistence/Mapping/ReflectionService.php b/lib/Doctrine/Persistence/Mapping/ReflectionService.php index bdc414be..47cdbeed 100644 --- a/lib/Doctrine/Persistence/Mapping/ReflectionService.php +++ b/lib/Doctrine/Persistence/Mapping/ReflectionService.php @@ -17,8 +17,10 @@ interface ReflectionService * Returns an array of the parent classes (not interfaces) for the given class. * * @param string $class + * @psalm-param class-string $class * * @return string[] + * @psalm-return class-string[] * * @throws MappingException */ @@ -28,6 +30,7 @@ public function getParentClasses($class); * Returns the shortname of a class. * * @param string $class + * @psalm-param class-string $class * * @return string */ @@ -35,6 +38,7 @@ public function getClassShortName($class); /** * @param string $class + * @psalm-param class-string $class * * @return string */ @@ -44,6 +48,7 @@ public function getClassNamespace($class); * Returns a reflection class instance or null. * * @param string $class + * @psalm-param class-string $class * * @return ReflectionClass|null */ @@ -54,6 +59,7 @@ public function getClass($class); * * @param string $class * @param string $property + * @psalm-param class-string $class * * @return ReflectionProperty|null */ @@ -64,6 +70,7 @@ public function getAccessibleProperty($class, $property); * * @param mixed $class * @param mixed $method + * @psalm-param class-string $class * * @return bool */ diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ca4f755a..62fe4543 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -6,3 +6,8 @@ parameters: message: "#^Parameter \\#3 \\$nsSeparator of class Doctrine\\\\Persistence\\\\Mapping\\\\Driver\\\\SymfonyFileLocator constructor expects string, null given\\.$#" count: 1 path: tests/Doctrine/Tests/Persistence/Mapping/SymfonyFileLocatorTest.php + + - # On purpose to make a test fail. + message: "#^Parameter \\#1 \\$class of method Doctrine\\\\Persistence\\\\Mapping\\\\RuntimeReflectionService\\:\\:getParentClasses\\(\\) expects class-string, string given.$#" + count: 1 + path: tests/Doctrine/Tests/Persistence/Mapping/RuntimeReflectionServiceTest.php diff --git a/tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php b/tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php index 04d454b5..97ad945e 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/AnnotationDriverTest.php @@ -24,7 +24,7 @@ public function testGetAllClassNames(): void class SimpleAnnotationDriver extends AnnotationDriver { - /** @var bool[] */ + /** @var array */ protected $entityAnnotationClasses = [Entity::class => true]; /** diff --git a/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php b/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php index e762c354..abef8a04 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php @@ -7,6 +7,9 @@ use Doctrine\Persistence\Mapping\Driver\MappingDriverChain; use Doctrine\Persistence\Mapping\MappingException; use Doctrine\Tests\DoctrineTestCase; +use Doctrine\Tests\Persistence\Mapping\Fixtures\Manager\Manager; +use Doctrine\Tests\Persistence\Mapping\Fixtures\Model; +use stdClass; class DriverChainTest extends DoctrineTestCase { @@ -84,7 +87,7 @@ public function testIsTransient(): void $chain = new MappingDriverChain(); $chain->addDriver($driver1, 'Doctrine\Tests\Models\CMS'); - self::assertTrue($chain->isTransient('stdClass'), 'stdClass isTransient'); + self::assertTrue($chain->isTransient(stdClass::class), 'stdClass isTransient'); } /** @@ -94,8 +97,8 @@ public function testDefaultDriver(): void { $companyDriver = $this->createMock(MappingDriver::class); $defaultDriver = $this->createMock(MappingDriver::class); - $entityClassName = 'Doctrine\Tests\ORM\Mapping\DriverChainEntity'; - $managerClassName = 'Doctrine\Tests\Models\Company\CompanyManager'; + $entityClassName = Model::class; + $managerClassName = Manager::class; $chain = new MappingDriverChain(); $companyDriver->expects($this->never()) @@ -115,7 +118,7 @@ public function testDefaultDriver(): void self::assertNull($chain->getDefaultDriver()); $chain->setDefaultDriver($defaultDriver); - $chain->addDriver($companyDriver, 'Doctrine\Tests\Models\Company'); + $chain->addDriver($companyDriver, 'Doctrine\Tests\Persistence\Mapping\Fixtures\Manager'); self::assertSame($defaultDriver, $chain->getDefaultDriver()); diff --git a/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php b/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php index 12b480cd..d3be444d 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/FileDriverTest.php @@ -8,6 +8,7 @@ use Doctrine\Tests\DoctrineTestCase; use Doctrine\Tests\Persistence\Mapping\Fixtures\AnotherGlobalClass; use Doctrine\Tests\Persistence\Mapping\Fixtures\GlobalClass; +use Doctrine\Tests\Persistence\Mapping\Fixtures\NotLoadedClass; use Doctrine\Tests\Persistence\Mapping\Fixtures\TestClassMetadata; use PHPUnit\Framework\MockObject\MockObject; use stdClass; @@ -84,12 +85,12 @@ public function testGetAllClassNamesFromMappingFile(): void $locator->expects($this->any()) ->method('getAllClassNames') ->with($this->equalTo(null)) - ->will($this->returnValue(['stdClass'])); + ->will($this->returnValue([stdClass::class])); $driver = new TestFileDriver($locator); $classNames = $driver->getAllClassNames(); - self::assertSame(['stdClass'], $classNames); + self::assertSame([stdClass::class], $classNames); } public function testGetAllClassNamesBothSources(): void @@ -144,19 +145,19 @@ public function testIsTransient(): void $locator = $this->newLocator(); $locator->expects($this->once()) ->method('fileExists') - ->with($this->equalTo('stdClass2')) + ->with($this->equalTo(NotLoadedClass::class)) ->will($this->returnValue(false)); $driver = new TestFileDriver($locator); - self::assertTrue($driver->isTransient('stdClass2')); + self::assertTrue($driver->isTransient(NotLoadedClass::class)); } public function testNonLocatorFallback(): void { $driver = new TestFileDriver(__DIR__ . '/_files', '.yml'); - self::assertTrue($driver->isTransient('stdClass2')); - self::assertFalse($driver->isTransient('stdClass')); + self::assertTrue($driver->isTransient(NotLoadedClass::class)); + self::assertFalse($driver->isTransient(stdClass::class)); } /** diff --git a/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/Manager/Manager.php b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/Manager/Manager.php new file mode 100644 index 00000000..8a891bc8 --- /dev/null +++ b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/Manager/Manager.php @@ -0,0 +1,9 @@ +reflectionService->getClass(self::class); - self::assertInstanceOf('ReflectionClass', $class); + self::assertInstanceOf(ReflectionClass::class, $class); } public function testGetMethods(): void diff --git a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php index b73d3a22..9420b4b8 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php @@ -38,6 +38,7 @@ protected function doLoadMetadata($class, $parent, $rootEntityFound, array $nonS */ protected function getFqcnFromAlias($namespaceAlias, $simpleClassName) { + /** @psalm-var class-string */ return __NAMESPACE__ . '\\' . $simpleClassName; } diff --git a/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php b/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php index ad9f7073..29e01c73 100644 --- a/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php +++ b/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php @@ -191,7 +191,7 @@ public function getAssociationNames(): array */ public function getAssociationTargetClass($assocName): string { - return __NAMESPACE__ . '\TestObject'; + return TestObject::class; } /** @@ -212,7 +212,7 @@ public function getIdentifier(): array public function getName(): string { - return __NAMESPACE__ . '\TestObject'; + return TestObject::class; } public function getReflectionClass(): ReflectionClass diff --git a/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php b/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php index 7ef700a5..341ba0b6 100644 --- a/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php +++ b/tests/Doctrine/Tests/Persistence/RuntimePublicReflectionPropertyTest.php @@ -7,6 +7,7 @@ use Doctrine\Persistence\Reflection\RuntimePublicReflectionProperty; use LogicException; use PHPUnit\Framework\TestCase; +use stdClass; use function call_user_func; @@ -59,7 +60,7 @@ public function testGetValueOnProxyPublicProperty(): void public function testSetValueOnProxyPublicProperty(): void { - $setCheckMock = $this->getMockBuilder('stdClass')->setMethods(['neverCallSet'])->getMock(); + $setCheckMock = $this->getMockBuilder(stdClass::class)->setMethods(['neverCallSet'])->getMock(); $setCheckMock->expects($this->never())->method('neverCallSet'); $initializer = static function () use ($setCheckMock): void { call_user_func([$setCheckMock, 'neverCallSet']); @@ -80,7 +81,7 @@ public function testSetValueOnProxyPublicProperty(): void $reflProperty->setValue($mockProxy, 'otherNewValue'); self::assertSame('otherNewValue', $mockProxy->checkedProperty); - $setCheckMock = $this->getMockBuilder('stdClass')->setMethods(['callSet'])->getMock(); + $setCheckMock = $this->getMockBuilder(stdClass::class)->setMethods(['callSet'])->getMock(); $setCheckMock->expects($this->once())->method('callSet'); $initializer = static function () use ($setCheckMock): void { call_user_func([$setCheckMock, 'callSet']); From aa78e4ad79f100a43662096ba12c50aaff4400f8 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Wed, 21 Apr 2021 19:25:54 +0200 Subject: [PATCH 26/36] Fix possible falsy arguments --- .../Persistence/Mapping/Driver/SymfonyFileLocator.php | 2 +- .../Persistence/Mapping/StaticReflectionService.php | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php b/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php index c7ea1ac7..5d91b80c 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/SymfonyFileLocator.php @@ -227,6 +227,6 @@ public function findMappingFile($className) } } - throw MappingException::mappingFileNotFound($className, substr($className, strrpos($className, '\\') + 1) . $this->fileExtension); + throw MappingException::mappingFileNotFound($className, substr($className, (int) strrpos($className, '\\') + 1) . $this->fileExtension); } } diff --git a/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php b/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php index b2c33ba1..56886e65 100644 --- a/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php +++ b/lib/Doctrine/Persistence/Mapping/StaticReflectionService.php @@ -25,8 +25,10 @@ public function getParentClasses($class) */ public function getClassShortName($className) { - if (strpos($className, '\\') !== false) { - $className = substr($className, strrpos($className, '\\') + 1); + $nsSeparatorLastPosition = strrpos($className, '\\'); + + if ($nsSeparatorLastPosition !== false) { + $className = substr($className, $nsSeparatorLastPosition + 1); } return $className; @@ -39,7 +41,7 @@ public function getClassNamespace($className) { $namespace = ''; if (strpos($className, '\\') !== false) { - $namespace = strrev(substr(strrev($className), strpos(strrev($className), '\\') + 1)); + $namespace = strrev(substr(strrev($className), (int) strpos(strrev($className), '\\') + 1)); } return $namespace; From 5bb4b3e5001b589ef39a53e3c27030d6639a5e2c Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Wed, 21 Apr 2021 19:29:43 +0200 Subject: [PATCH 27/36] Fix className and alias issues Some methods are able to handle classname and classname alias, so they could receive a class-string or a string. Adding phpdoc to the variables makes psalm able to understand them. --- .../Persistence/AbstractManagerRegistry.php | 29 ++++++++++++++----- .../Mapping/AbstractClassMetadataFactory.php | 2 ++ .../Mapping/Driver/AnnotationDriver.php | 4 +-- 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/Doctrine/Persistence/AbstractManagerRegistry.php b/lib/Doctrine/Persistence/AbstractManagerRegistry.php index 4fb8af7e..ddc8b67d 100644 --- a/lib/Doctrine/Persistence/AbstractManagerRegistry.php +++ b/lib/Doctrine/Persistence/AbstractManagerRegistry.php @@ -162,13 +162,9 @@ public function getManager($name = null) */ public function getManagerForClass($class) { - // Check for namespace alias - if (strpos($class, ':') !== false) { - [$namespaceAlias, $simpleClassName] = explode(':', $class, 2); - $class = $this->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName; - } + $className = $this->getRealClassName($class); - $proxyClass = new ReflectionClass($class); + $proxyClass = new ReflectionClass($className); if ($proxyClass->implementsInterface($this->proxyInterfaceName)) { $parentClass = $proxyClass->getParentClass(); @@ -177,13 +173,13 @@ public function getManagerForClass($class) return null; } - $class = $parentClass->getName(); + $className = $parentClass->getName(); } foreach ($this->managers as $id) { $manager = $this->getService($id); - if (! $manager->getMetadataFactory()->isTransient($class)) { + if (! $manager->getMetadataFactory()->isTransient($className)) { return $manager; } } @@ -250,4 +246,21 @@ private function selectManager(string $persistentObjectName, ?string $persistent return $this->getManagerForClass($persistentObjectName) ?? $this->getManager(); } + + /** + * @psalm-return class-string + */ + private function getRealClassName(string $classNameOrAlias): string + { + // Check for namespace alias + if (strpos($classNameOrAlias, ':') !== false) { + [$namespaceAlias, $simpleClassName] = explode(':', $classNameOrAlias, 2); + + /** @psalm-var class-string */ + return $this->getAliasNamespace($namespaceAlias) . '\\' . $simpleClassName; + } + + /** @psalm-var class-string */ + return $classNameOrAlias; + } } diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index f4c06e40..495a4fac 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -225,6 +225,7 @@ public function getMetadataFor($className) $realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName); } else { + /** @psalm-var class-string $className */ $realClassName = $this->getRealClass($className); } @@ -449,6 +450,7 @@ public function isTransient($class) $class = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName); } + /** @psalm-var class-string $class */ return $this->getDriver()->isTransient($class); } diff --git a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php index 96c21bf5..fb461a3d 100644 --- a/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php +++ b/lib/Doctrine/Persistence/Mapping/Driver/AnnotationDriver.php @@ -170,9 +170,7 @@ public function setFileExtension($fileExtension) * A class is non-transient if it is annotated with an annotation * from the {@see AnnotationDriver::entityAnnotationClasses}. * - * @param string $className - * - * @return bool + * {@inheritDoc} */ public function isTransient($className) { From a29f2bf065223321f531b59f8226be73dce11053 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Wed, 21 Apr 2021 19:36:49 +0200 Subject: [PATCH 28/36] Raise Psalm to level 3 This includes: - adding assertions to avoid nullable values - Override phpdoc to be more specific Apart from ignore some issues. --- .../Mapping/AbstractClassMetadataFactory.php | 3 +++ .../Persistence/Mapping/MappingException.php | 2 +- .../Mapping/RuntimeReflectionService.php | 5 ++++- .../TypedNoDefaultReflectionProperty.php | 6 ++++++ psalm.xml | 17 ++++++++++++++--- .../Persistence/ObjectManagerDecoratorTest.php | 2 +- 6 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 495a4fac..d7e945db 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -17,6 +17,7 @@ use function array_map; use function array_reverse; use function array_unshift; +use function assert; use function explode; use function sprintf; use function str_replace; @@ -498,6 +499,8 @@ private function getRealClass(string $class): string $this->createDefaultProxyClassNameResolver(); } + assert($this->proxyClassNameResolver !== null); + return $this->proxyClassNameResolver->resolveClassName($class); } diff --git a/lib/Doctrine/Persistence/Mapping/MappingException.php b/lib/Doctrine/Persistence/Mapping/MappingException.php index 1c5e0caa..88845596 100644 --- a/lib/Doctrine/Persistence/Mapping/MappingException.php +++ b/lib/Doctrine/Persistence/Mapping/MappingException.php @@ -50,7 +50,7 @@ public static function fileMappingDriversRequireConfiguredDirectoryPath($path = return new self(sprintf( 'File mapping drivers must have a valid directory path, ' . 'however the given path %s seems to be incorrect!', - $path + (string) $path )); } diff --git a/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php b/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php index 241a1ce4..446c2433 100644 --- a/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php +++ b/lib/Doctrine/Persistence/Mapping/RuntimeReflectionService.php @@ -61,7 +61,10 @@ public function getClassNamespace($class) } /** - * {@inheritDoc} + * @param string $class + * @psalm-param class-string $class + * + * @return ReflectionClass */ public function getClass($class) { diff --git a/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php b/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php index 3a54cb85..93e3c92a 100644 --- a/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php +++ b/lib/Doctrine/Persistence/Reflection/TypedNoDefaultReflectionProperty.php @@ -2,8 +2,11 @@ namespace Doctrine\Persistence\Reflection; +use Closure; use ReflectionProperty; +use function assert; + /** * PHP Typed No Default Reflection Property - special override for typed properties without a default value. */ @@ -38,6 +41,9 @@ public function setValue($object, $value = null) unset($this->$propertyName); }; $unsetter = $unsetter->bindTo($object, $this->getDeclaringClass()->getName()); + + assert($unsetter instanceof Closure); + $unsetter(); return; diff --git a/psalm.xml b/psalm.xml index e0dc9e68..2b68da1d 100644 --- a/psalm.xml +++ b/psalm.xml @@ -1,8 +1,7 @@ + + + + + + + + + + + + diff --git a/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php b/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php index 64a74f1f..8e6a3486 100644 --- a/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php +++ b/tests/Doctrine/Tests/Persistence/ObjectManagerDecoratorTest.php @@ -22,7 +22,7 @@ public function __construct(ObjectManager $wrapped) class ObjectManagerDecoratorTest extends TestCase { - /** @var MockObject|ObjectManager */ + /** @var MockObject&ObjectManager */ private $wrapped; /** @var NullObjectManagerDecorator */ From 254fc971cdf19dbaf5d01487c05f1ff783e996da Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Thu, 22 Apr 2021 10:19:04 +0200 Subject: [PATCH 29/36] Add missing return type --- lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php index a3d3babb..35066905 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadataFactory.php @@ -43,6 +43,8 @@ public function hasMetadataFor($className); * @param string $className * @param ClassMetadata $class * @psalm-param T $class + * + * @return void */ public function setMetadataFor($className, $class); From 95405e2608c97df97d868a65b9b5f3a25f6fb783 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Thu, 22 Apr 2021 10:20:10 +0200 Subject: [PATCH 30/36] Make ClassMetada generic This allows static analysis tools to understand the underlying type of object that a ClassMetada holds. --- lib/Doctrine/Persistence/Mapping/ClassMetadata.php | 6 ++++-- lib/Doctrine/Persistence/ObjectManager.php | 4 ++++ .../Mapping/Fixtures/TestClassMetadata.php | 11 ++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php index 60525b12..e44e9afd 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php @@ -6,6 +6,8 @@ /** * Contract for a Doctrine persistence layer ClassMetadata class to implement. + * + * @template T of object */ interface ClassMetadata { @@ -13,7 +15,7 @@ interface ClassMetadata * Gets the fully-qualified class name of this persistent class. * * @return string - * @psalm-return class-string + * @psalm-return class-string */ public function getName(); @@ -29,7 +31,7 @@ public function getIdentifier(); /** * Gets the ReflectionClass instance for this mapped class. * - * @return ReflectionClass + * @return ReflectionClass */ public function getReflectionClass(); diff --git a/lib/Doctrine/Persistence/ObjectManager.php b/lib/Doctrine/Persistence/ObjectManager.php index 70f9e431..7a3fffae 100644 --- a/lib/Doctrine/Persistence/ObjectManager.php +++ b/lib/Doctrine/Persistence/ObjectManager.php @@ -131,8 +131,12 @@ public function getRepository($className); * (as it is returned by get_class($obj)). * * @param string $className + * @psalm-param class-string $className * * @return ClassMetadata + * @psalm-return ClassMetadata + * + * @template T of object */ public function getClassMetadata($className); diff --git a/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php index e1d0f614..719d4d8f 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php @@ -8,25 +8,26 @@ use LogicException; use ReflectionClass; +/** + * @template T of object + * @implements ClassMetadata + */ final class TestClassMetadata implements ClassMetadata { /** * @var string - * @psalm-var class-string + * @psalm-var class-string */ private $className; /** - * @psalm-param class-string $className + * @psalm-param class-string $className */ public function __construct(string $className) { $this->className = $className; } - /** - * @psalm-return class-string - */ public function getName(): string { return $this->className; From e2d6be12c0aacadf9f34d693d353efaee91e9174 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Thu, 22 Apr 2021 11:24:14 +0200 Subject: [PATCH 31/36] Use PSR-6 compatibility classes from doctrine/cache (#172) --- composer.json | 6 +++--- .../Persistence/Mapping/AbstractClassMetadataFactory.php | 8 ++++---- .../Persistence/Mapping/ClassMetadataFactoryTest.php | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 0da82d9b..7269f462 100644 --- a/composer.json +++ b/composer.json @@ -22,11 +22,10 @@ "require": { "php": "^7.1 || ^8.0", "doctrine/annotations": "^1.0", - "doctrine/cache": "^1.0", + "doctrine/cache": "^1.11 || ^2.0", "doctrine/collections": "^1.0", "doctrine/event-manager": "^1.0", - "psr/cache": "^1.0|^2.0|^3.0", - "symfony/cache": "^4.4|^5.0" + "psr/cache": "^1.0|^2.0|^3.0" }, "require-dev": { "composer/package-versions-deprecated": "^1.11", @@ -34,6 +33,7 @@ "doctrine/coding-standard": "^6.0 || ^9.0", "doctrine/common": "^3.0", "phpunit/phpunit": "^7.5.20 || ^8.0 || ^9.0", + "symfony/cache": "^4.4|^5.0", "vimeo/psalm": "4.7.0" }, "conflict": { diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index d7e945db..4310bbd6 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -5,12 +5,12 @@ use BadMethodCallException; use Doctrine\Common\Cache\Cache; use Doctrine\Common\Cache\CacheProvider; +use Doctrine\Common\Cache\Psr6\CacheAdapter; +use Doctrine\Common\Cache\Psr6\DoctrineProvider; use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Proxy; use Psr\Cache\CacheItemPoolInterface; use ReflectionException; -use Symfony\Component\Cache\Adapter\DoctrineAdapter; -use Symfony\Component\Cache\DoctrineProvider; use function array_combine; use function array_keys; @@ -91,7 +91,7 @@ public function setCacheDriver(?Cache $cacheDriver = null) throw new BadMethodCallException('Cannot convert cache to PSR-6 cache'); } - $this->cache = new DoctrineAdapter($cacheDriver); + $this->cache = CacheAdapter::wrap($cacheDriver); } /** @@ -111,7 +111,7 @@ public function getCacheDriver() public function setCache(CacheItemPoolInterface $cache): void { $this->cache = $cache; - $this->cacheDriver = new DoctrineProvider($cache); + $this->cacheDriver = DoctrineProvider::wrap($cache); } final protected function getCache(): ?CacheItemPoolInterface diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index 560006c3..92fecde9 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -3,6 +3,8 @@ namespace Doctrine\Tests\Persistence\Mapping; use Doctrine\Common\Cache\ArrayCache; +use Doctrine\Common\Cache\Psr6\CacheAdapter; +use Doctrine\Common\Cache\Psr6\DoctrineProvider; use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory; use Doctrine\Persistence\Mapping\ClassMetadata; use Doctrine\Persistence\Mapping\Driver\MappingDriver; @@ -13,8 +15,6 @@ use ReflectionMethod; use stdClass; use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Cache\Adapter\DoctrineAdapter; -use Symfony\Component\Cache\DoctrineProvider; /** * @covers \Doctrine\Persistence\Mapping\AbstractClassMetadataFactory @@ -40,7 +40,7 @@ public function testSetGetCacheDriver(): void $this->cmf->setCacheDriver($cache); self::assertSame($cache, $this->cmf->getCacheDriver()); - self::assertInstanceOf(DoctrineAdapter::class, self::getCache($this->cmf)); + self::assertInstanceOf(CacheAdapter::class, self::getCache($this->cmf)); $this->cmf->setCacheDriver(null); self::assertNull($this->cmf->getCacheDriver()); From 388c19a8134c6abeade08a673a75ea4568e3ce9b Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 24 Apr 2021 10:26:07 +0200 Subject: [PATCH 32/36] Fix @template-implements annotation --- .../Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php index 719d4d8f..2ef68e17 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/Fixtures/TestClassMetadata.php @@ -10,7 +10,7 @@ /** * @template T of object - * @implements ClassMetadata + * @template-implements ClassMetadata */ final class TestClassMetadata implements ClassMetadata { From ce5afb305f8e43e3835183c9d01e9cc6086e3849 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 24 Apr 2021 10:28:01 +0200 Subject: [PATCH 33/36] Add more specific phpdoc --- .../Persistence/Mapping/AbstractClassMetadataFactory.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php index 4310bbd6..f378503c 100644 --- a/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php +++ b/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php @@ -313,6 +313,7 @@ public function setMetadataFor($className, $class) * @psalm-param class-string $name * * @return string[] + * @psalm-return class-string[] */ protected function getParentClasses($name) { @@ -428,9 +429,12 @@ abstract protected function doLoadMetadata($class, $parent, $rootEntityFound, ar * Creates a new ClassMetadata instance for the given class name. * * @param string $className + * @psalm-param class-string $className * - * @return ClassMetadata + * @return ClassMetadata * @psalm-return CMTemplate + * + * @template T of object */ abstract protected function newClassMetadataInstance($className); From bf2097f33a4b437e4fb16b89f0d3af0233d82fc8 Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Sat, 24 Apr 2021 10:28:24 +0200 Subject: [PATCH 34/36] Apply generics to tests --- .../Persistence/Mapping/TestClassMetadataFactory.php | 12 +++++++++++- .../Tests/Persistence/PersistentObjectTest.php | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php index 9420b4b8..4877e1e3 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/TestClassMetadataFactory.php @@ -9,17 +9,27 @@ use Doctrine\Persistence\Mapping\Driver\MappingDriver; use Doctrine\Persistence\Mapping\ReflectionService; +/** + * @template CMTemplate of ClassMetadata + * @template-extends AbstractClassMetadataFactory + */ class TestClassMetadataFactory extends AbstractClassMetadataFactory { /** @var MappingDriver */ public $driver; - /** @var ClassMetadata */ + /** + * @var ClassMetadata + * @psalm-var CMTemplate + */ public $metadata; /** @var callable|null */ public $fallbackCallback; + /** + * @psalm-param CMTemplate $metadata + */ public function __construct(MappingDriver $driver, ClassMetadata $metadata) { $this->driver = $driver; diff --git a/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php b/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php index 29e01c73..126700c5 100644 --- a/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php +++ b/tests/Doctrine/Tests/Persistence/PersistentObjectTest.php @@ -166,6 +166,9 @@ public function testAddInvalidCollection(): void } } +/** + * @template-implements ClassMetadata + */ class TestObjectMetadata implements ClassMetadata { /** From c73f7047d246d7f9e7b77dde905266571147ccbb Mon Sep 17 00:00:00 2001 From: Fran Moreno Date: Fri, 30 Apr 2021 10:31:41 +0200 Subject: [PATCH 35/36] Make ClassMetadata use template-covariant ClassMetadata is supposed to only deal with subtypes of object. --- lib/Doctrine/Persistence/Mapping/ClassMetadata.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php index e44e9afd..cce22daa 100644 --- a/lib/Doctrine/Persistence/Mapping/ClassMetadata.php +++ b/lib/Doctrine/Persistence/Mapping/ClassMetadata.php @@ -7,7 +7,7 @@ /** * Contract for a Doctrine persistence layer ClassMetadata class to implement. * - * @template T of object + * @template-covariant T of object */ interface ClassMetadata { From 653d54d5297039e12cf1c241eb230e79f95570a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 15 May 2021 20:30:33 +0200 Subject: [PATCH 36/36] Merge release 2.1.1 into 2.2.x (#177) * Remove use of deprecated TestCase::at() method For that test it does not add value to check the order of calls. * Support Doctrine Cache 2 (#175) * Fix Psalm and PHPStan errors for Doctrine Cache 2 (#176) * Fix missing use statement * Fix invalid assertion Co-authored-by: Fran Moreno Co-authored-by: Alexander M. Turek Co-authored-by: Andreas Braun --- phpstan-baseline.neon | 2 ++ psalm.xml | 6 ++++++ .../Mapping/ClassMetadataFactoryTest.php | 19 ++++++++++++++++--- .../Persistence/Mapping/DriverChainTest.php | 6 +++--- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 62fe4543..569468ee 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2,6 +2,8 @@ parameters: ignoreErrors: - "#^Call to an undefined method Doctrine\\\\Tests\\\\Persistence\\\\TestObject\\:\\:.+\\(\\)\\.$#" + - "#^Instantiated class Doctrine\\\\Common\\\\Cache\\\\ArrayCache not found\\.$#" + - message: "#^Parameter \\#3 \\$nsSeparator of class Doctrine\\\\Persistence\\\\Mapping\\\\Driver\\\\SymfonyFileLocator constructor expects string, null given\\.$#" count: 1 diff --git a/psalm.xml b/psalm.xml index 2b68da1d..c80b2938 100644 --- a/psalm.xml +++ b/psalm.xml @@ -38,6 +38,12 @@ + + + + + + diff --git a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php index 92fecde9..e8cdd775 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/ClassMetadataFactoryTest.php @@ -3,7 +3,7 @@ namespace Doctrine\Tests\Persistence\Mapping; use Doctrine\Common\Cache\ArrayCache; -use Doctrine\Common\Cache\Psr6\CacheAdapter; +use Doctrine\Common\Cache\Cache; use Doctrine\Common\Cache\Psr6\DoctrineProvider; use Doctrine\Persistence\Mapping\AbstractClassMetadataFactory; use Doctrine\Persistence\Mapping\ClassMetadata; @@ -16,6 +16,9 @@ use stdClass; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use function assert; +use function class_exists; + /** * @covers \Doctrine\Persistence\Mapping\AbstractClassMetadataFactory */ @@ -36,11 +39,11 @@ public function testSetGetCacheDriver(): void self::assertNull($this->cmf->getCacheDriver()); self::assertNull(self::getCache($this->cmf)); - $cache = new ArrayCache(); + $cache = $this->getArrayCache(); $this->cmf->setCacheDriver($cache); self::assertSame($cache, $this->cmf->getCacheDriver()); - self::assertInstanceOf(CacheAdapter::class, self::getCache($this->cmf)); + self::assertInstanceOf(CacheItemPoolInterface::class, self::getCache($this->cmf)); $this->cmf->setCacheDriver(null); self::assertNull($this->cmf->getCacheDriver()); @@ -246,6 +249,16 @@ private static function getCache(AbstractClassMetadataFactory $classMetadataFact return $method->invoke($classMetadataFactory); } + + private function getArrayCache(): Cache + { + $cache = class_exists(DoctrineProvider::class) + ? DoctrineProvider::wrap(new ArrayAdapter()) + : new ArrayCache(); + assert($cache instanceof Cache); + + return $cache; + } } class RootEntity diff --git a/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php b/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php index abef8a04..437be982 100644 --- a/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php +++ b/tests/Doctrine/Tests/Persistence/Mapping/DriverChainTest.php @@ -27,13 +27,13 @@ public function testDelegateToMatchingNamespaceDriver(): void ->method('isTransient'); $driver2 = $this->createMock(MappingDriver::class); - $driver2->expects($this->at(0)) + $driver2->expects($this->once()) ->method('loadMetadataForClass') ->with($this->equalTo($className), $this->equalTo($classMetadata)); - $driver2->expects($this->at(1)) + $driver2->expects($this->once()) ->method('isTransient') ->with($this->equalTo($className)) - ->will($this->returnValue(true)); + ->willReturn(true); $chain->addDriver($driver1, 'Doctrine\Tests\Models\Company'); $chain->addDriver($driver2, 'Doctrine\Tests\Persistence\Mapping');