diff --git a/classes/local/execution/logging/mtrace_handler.php b/classes/local/execution/logging/mtrace_handler.php index 205329a9..bb35356e 100644 --- a/classes/local/execution/logging/mtrace_handler.php +++ b/classes/local/execution/logging/mtrace_handler.php @@ -17,6 +17,7 @@ namespace tool_dataflows\local\execution\logging; use Monolog\Handler\AbstractHandler; +use Monolog\Handler\AbstractProcessingHandler; /** * An environment for logging information about dataflow execution. @@ -26,17 +27,29 @@ * @copyright Catalyst IT, 2023 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -class mtrace_handler extends AbstractHandler { +class mtrace_handler extends AbstractProcessingHandler { /** * Default handler for Moodle. * * @param array $record the log record **/ - public function handle(array $record) { + public function handle(array $record): bool { if ($this->isHandling($record)) { $record['formatted'] = trim($this->getFormatter()->format($record)); - mtrace($record['formatted']); + $this->write($record); + return true; } + return $this->handler->handle($record); + } + + /** + * Writes the record down to the log of the implementing handler + * + * @param array $record + * @return void + */ + protected function write(array $record): void { + mtrace($record['formatted']); } } diff --git a/composer.json b/composer.json index c058878b..b4418485 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,11 @@ { "config": { "platform": { - "php": "7.1" + "php": "7.4" } }, "require": { - "php": ">=7.1", + "php": ">=7.4", "symfony/yaml": "^3.4", "symfony/expression-language": "^3.4", "phpseclib/phpseclib": "~3.0", diff --git a/composer.lock b/composer.lock index cabe3581..8cf31d45 100644 --- a/composer.lock +++ b/composer.lock @@ -4,55 +4,71 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3cb8b1d50889cf289e670db632b3c62e", + "content-hash": "27004af2480967797bba3972c1dd7743", "packages": [ { "name": "monolog/monolog", - "version": "1.27.1", + "version": "2.9.1", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", - "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "php-amqplib/php-amqplib": "~2.4", - "php-console/php-console": "^3.1.3", - "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "^5.3|^6.0" + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "autoload": { "psr-4": { "Monolog\\": "src/Monolog" @@ -66,11 +82,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -78,7 +94,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" }, "funding": [ { @@ -90,7 +106,7 @@ "type": "tidelift" } ], - "time": "2022-06-09T08:53:42+00:00" + "time": "2023-02-06T13:44:46+00:00" }, { "name": "paragonie/constant_time_encoding", @@ -211,16 +227,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.21", + "version": "3.0.23", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1" + "reference": "866cc78fbd82462ffd880e3f65692afe928bed50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4580645d3fc05c189024eb3b834c6c1e4f0f30a1", - "reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/866cc78fbd82462ffd880e3f65692afe928bed50", + "reference": "866cc78fbd82462ffd880e3f65692afe928bed50", "shasum": "" }, "require": { @@ -301,7 +317,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.21" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.23" }, "funding": [ { @@ -317,7 +333,7 @@ "type": "tidelift" } ], - "time": "2023-07-09T15:24:48+00:00" + "time": "2023-09-18T17:22:01+00:00" }, { "name": "psr/cache", @@ -370,27 +386,22 @@ }, { "name": "psr/container", - "version": "1.0.0", + "version": "1.1.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.4.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -403,7 +414,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -417,9 +428,9 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2017-02-14T16:28:37+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { "name": "psr/log", @@ -472,32 +483,60 @@ "time": "2021-05-03T11:20:27+00:00" }, { - "name": "psr/simple-cache", - "version": "1.0.1", + "name": "symfony/cache", + "version": "v4.4.48", "source": { "type": "git", - "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "type": "library", "autoload": { "psr-4": { - "Psr\\SimpleCache\\": "src/" - } + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -505,65 +544,74 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interfaces for simple caching", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", "keywords": [ - "cache", "caching", - "psr", - "psr-16", - "simple-cache" + "psr6" ], "support": { - "source": "https://github.com/php-fig/simple-cache/tree/master" + "source": "https://github.com/symfony/cache/tree/v4.4.48" }, - "time": "2017-10-23T01:57:42+00:00" + "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": "2022-10-17T20:21:54+00:00" }, { - "name": "symfony/cache", - "version": "v3.4.47", + "name": "symfony/cache-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a7a14c4832760bd1fbd31be2859ffedc9b6ff813", - "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/cache": "~1.0", - "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/polyfill-apcu": "~1.1" + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" }, - "conflict": { - "symfony/var-dumper": "<3.3" - }, - "provide": { - "psr/cache-implementation": "1.0", - "psr/simple-cache-implementation": "1.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/cache": "^1.6", - "doctrine/dbal": "^2.4|^3.0", - "predis/predis": "^1.0" + "suggest": { + "symfony/cache-implementation": "" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, "autoload": { "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\Cache\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -579,14 +627,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "description": "Generic abstractions related to caching", "homepage": "https://symfony.com", "keywords": [ - "caching", - "psr6" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/cache/tree/v3.4.47" + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" }, "funding": [ { @@ -602,36 +654,38 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { "name": "symfony/config", - "version": "v3.4.47", + "version": "v4.4.44", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f" + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f", - "reference": "bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" }, "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" @@ -659,10 +713,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Config Component", + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v3.4.47" + "source": "https://github.com/symfony/config/tree/v4.4.44" }, "funding": [ { @@ -678,31 +732,31 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-07-20T09:59:04+00:00" }, { "name": "symfony/debug", - "version": "v3.4.47", + "version": "v4.4.44", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "ab42889de57fdfcfcc0759ab102e2fd4ea72dcae" + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/ab42889de57fdfcfcc0759ab102e2fd4ea72dcae", - "reference": "ab42889de57fdfcfcc0759ab102e2fd4ea72dcae", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "type": "library", "autoload": { @@ -727,10 +781,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Provides tools to ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v3.4.47" + "source": "https://github.com/symfony/debug/tree/v4.4.44" }, "funding": [ { @@ -747,39 +801,42 @@ } ], "abandoned": "symfony/error-handler", - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-07-28T16:29:46+00:00" }, { "name": "symfony/dependency-injection", - "version": "v3.4.47", + "version": "v4.4.37", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "51d2a2708c6ceadad84393f8581df1dcf9e5e84b" + "reference": "c00a23904b42f140087d36e1d22c88801bb39689" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/51d2a2708c6ceadad84393f8581df1dcf9e5e84b", - "reference": "51d2a2708c6ceadad84393f8581df1dcf9e5e84b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c00a23904b42f140087d36e1d22c88801bb39689", + "reference": "c00a23904b42f140087d36e1d22c88801bb39689", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/config": "", @@ -811,10 +868,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DependencyInjection Component", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v3.4.47" + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.37" }, "funding": [ { @@ -830,47 +887,38 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-01-24T17:17:45+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.47", + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "31fde73757b6bad247c54597beef974919ec6860" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/31fde73757b6bad247c54597beef974919ec6860", - "reference": "31fde73757b6bad247c54597beef974919ec6860", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/debug": "~3.4|~4.4", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "php": ">=7.1" }, "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" }, - "exclude-from-classmap": [ - "/Tests/" + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -879,18 +927,18 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v3.4.47" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -906,31 +954,36 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { - "name": "symfony/expression-language", - "version": "v3.4.47", + "name": "symfony/error-handler", + "version": "v4.4.44", "source": { "type": "git", - "url": "https://github.com/symfony/expression-language.git", - "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f" + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/de38e66398fca1fcb9c48e80279910e6889cb28f", - "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/cache": "~3.1|~4.0", - "symfony/polyfill-php70": "~1.6" + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\ExpressionLanguage\\": "" + "Symfony\\Component\\ErrorHandler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -950,10 +1003,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony ExpressionLanguage Component", + "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v3.4.47" + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" }, "funding": [ { @@ -969,30 +1022,52 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-07-28T16:29:46+00:00" }, { - "name": "symfony/filesystem", - "version": "v3.4.47", + "name": "symfony/event-dispatcher", + "version": "v4.4.44", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/e58d7841cddfed6e846829040dca2cca0ebbbbb3", - "reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1012,10 +1087,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v3.4.47" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" }, "funding": [ { @@ -1031,38 +1106,43 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-07-20T09:59:04+00:00" }, { - "name": "symfony/http-foundation", - "version": "v3.4.47", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "b9885fcce6fe494201da4f70a9309770e9d13dc8" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b9885fcce6fe494201da4f70a9309770e9d13dc8", - "reference": "b9885fcce6fe494201da4f70a9309770e9d13dc8", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": ">=7.1.3" }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, "autoload": { "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1070,18 +1150,26 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "source": "https://github.com/symfony/http-foundation/tree/v3.4.47" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" }, "funding": [ { @@ -1097,70 +1185,31 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2022-01-02T09:41:36+00:00" }, { - "name": "symfony/http-kernel", - "version": "v3.4.49", + "name": "symfony/expression-language", + "version": "v3.4.47", "source": { "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "5aa72405f5bd5583c36ed6e756acb17d3f98ac40" + "url": "https://github.com/symfony/expression-language.git", + "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/5aa72405f5bd5583c36ed6e756acb17d3f98ac40", - "reference": "5aa72405f5bd5583c36ed6e756acb17d3f98ac40", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/de38e66398fca1fcb9c48e80279910e6889cb28f", + "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0", - "symfony/debug": "^3.3.3|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php56": "~1.8" - }, - "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", - "twig/twig": "<1.34|<2.4,>=2" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" + "symfony/cache": "~3.1|~4.0", + "symfony/polyfill-php70": "~1.6" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" + "Symfony\\Component\\ExpressionLanguage\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1180,10 +1229,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpKernel Component", + "description": "Symfony ExpressionLanguage Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v3.4.49" + "source": "https://github.com/symfony/expression-language/tree/v3.4.47" }, "funding": [ { @@ -1199,47 +1248,32 @@ "type": "tidelift" } ], - "time": "2021-05-19T12:06:59+00:00" + "time": "2020-10-24T10:57:07+00:00" }, { - "name": "symfony/monolog-bridge", - "version": "v3.4.47", + "name": "symfony/filesystem", + "version": "v5.4.25", "source": { "type": "git", - "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "93915f0d981bc166dfa475698124435327f6ee63" + "url": "https://github.com/symfony/filesystem.git", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/93915f0d981bc166dfa475698124435327f6ee63", - "reference": "93915f0d981bc166dfa475698124435327f6ee63", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", "shasum": "" }, "require": { - "monolog/monolog": "~1.19", - "php": "^5.5.9|>=7.0.8", - "symfony/http-kernel": "~2.8|~3.0|~4.0" - }, - "conflict": { - "symfony/console": "<2.8", - "symfony/http-foundation": "<3.3" - }, - "require-dev": { - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/security-core": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" - }, - "suggest": { - "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings. You need version ^2.8 of the console for it.", - "symfony/event-dispatcher": "Needed when using log messages in console commands.", - "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", - "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" }, - "type": "symfony-bridge", + "type": "library", "autoload": { "psr-4": { - "Symfony\\Bridge\\Monolog\\": "" + "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1259,10 +1293,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Monolog Bridge", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v3.4.47" + "source": "https://github.com/symfony/filesystem/tree/v5.4.25" }, "funding": [ { @@ -1278,48 +1312,42 @@ "type": "tidelift" } ], - "time": "2020-10-24T10:57:07+00:00" + "time": "2023-05-31T13:04:02+00:00" }, { - "name": "symfony/monolog-bundle", - "version": "v3.6.0", + "name": "symfony/http-client-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e495f5c7e4e672ffef4357d4a4d85f010802f940", - "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", "shasum": "" }, "require": { - "monolog/monolog": "~1.22 || ~2.0", - "php": ">=5.6", - "symfony/config": "~3.4 || ~4.0 || ^5.0", - "symfony/dependency-injection": "~3.4.10 || ^4.0.10 || ^5.0", - "symfony/http-kernel": "~3.4 || ~4.0 || ^5.0", - "symfony/monolog-bridge": "~3.4 || ~4.0 || ^5.0" + "php": ">=7.2.5" }, - "require-dev": { - "symfony/console": "~3.4 || ~4.0 || ^5.0", - "symfony/phpunit-bridge": "^4.4 || ^5.0", - "symfony/yaml": "~3.4 || ~4.0 || ^5.0" + "suggest": { + "symfony/http-client-implementation": "" }, - "type": "symfony-bundle", + "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "psr-4": { - "Symfony\\Bundle\\MonologBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\HttpClient\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1327,23 +1355,26 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony MonologBundle", - "homepage": "http://symfony.com", + "description": "Generic abstractions related to HTTP clients", + "homepage": "https://symfony.com", "keywords": [ - "log", - "logging" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.6.0" + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" }, "funding": [ { @@ -1359,68 +1390,335 @@ "type": "tidelift" } ], - "time": "2020-10-06T15:12:11+00:00" + "time": "2022-04-12T15:48:08+00:00" }, { - "name": "symfony/polyfill-apcu", - "version": "v1.27.0", + "name": "symfony/http-foundation", + "version": "v5.4.28", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-apcu.git", - "reference": "6e7f6ed2168779a2b3927e606a9768860a8bdfa0" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/6e7f6ed2168779a2b3927e606a9768860a8bdfa0", - "reference": "6e7f6ed2168779a2b3927e606a9768860a8bdfa0", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/365992c83a836dfe635f1e903ccca43ee03d3dd2", + "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "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": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v5.4.28" + }, + "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": "2023-08-21T07:23:18+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v4.4.50", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", + "shasum": "" + }, + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" + }, + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "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": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "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": "2023-02-01T08:01:31+00:00" + }, + { + "name": "symfony/monolog-bridge", + "version": "v5.2.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "2c3943d7c0100983f9c0a82807555273353e3539" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/2c3943d7c0100983f9c0a82807555273353e3539", + "reference": "2c3943d7c0100983f9c0a82807555273353e3539", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1|^2", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<4.4", + "symfony/http-foundation": "<4.4" + }, + "require-dev": { + "symfony/console": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + }, + "type": "symfony-bridge", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Apcu\\": "" + "Symfony\\Bridge\\Monolog\\": "" + }, + "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": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v5.2.12" + }, + "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": "2021-07-23T15:54:19+00:00" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" } }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions", + "description": "Symfony MonologBundle", "homepage": "https://symfony.com", "keywords": [ - "apcu", - "compatibility", - "polyfill", - "portable", - "shim" + "log", + "logging" ], "support": { - "source": "https://github.com/symfony/polyfill-apcu/tree/v1.27.0" + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" }, "funding": [ { @@ -1436,20 +1734,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2022-05-10T14:24:36+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -1464,7 +1762,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1502,7 +1800,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -1518,20 +1816,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", + "version": "v1.28.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -1546,7 +1844,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1585,7 +1883,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -1601,20 +1899,20 @@ "type": "tidelift" } ], - "time": "2022-11-03T14:55:06+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { - "name": "symfony/polyfill-php56", + "name": "symfony/polyfill-php70", "version": "v1.20.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675" + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", - "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644", "shasum": "" }, "require": { @@ -1644,7 +1942,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1653,7 +1951,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php56/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0" }, "funding": [ { @@ -1672,32 +1970,43 @@ "time": "2020-10-23T14:02:19+00:00" }, { - "name": "symfony/polyfill-php70", - "version": "v1.20.0", + "name": "symfony/polyfill-php73", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644", - "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", "shasum": "" }, "require": { "php": ">=7.1" }, - "type": "metapackage", + "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -1712,7 +2021,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1721,7 +2030,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" }, "funding": [ { @@ -1737,7 +2046,414 @@ "type": "tidelift" } ], - "time": "2020-10-23T14:02:19+00:00" + "time": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + }, + "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": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "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 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + }, + "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": "2023-01-26T09:26:14+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "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" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "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": "2022-05-30T19:17:29+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v5.4.29", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6172e4ae3534d25ee9e07eb487c20be7760fcc65", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v5.4.29" + }, + "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": "2023-09-12T10:09:58+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v5.4.26", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "11401fe94f960249b3c63a488c63ba73091c1e4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/11401fe94f960249b3c63a488c63ba73091c1e4a", + "reference": "11401fe94f960249b3c63a488c63ba73091c1e4a", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.4.26" + }, + "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": "2023-07-20T07:21:16+00:00" }, { "name": "symfony/yaml", @@ -1818,11 +2534,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.1" + "php": ">=7.4" }, "platform-dev": [], "platform-overrides": { - "php": "7.1" + "php": "7.4" }, "plugin-api-version": "2.3.0" } diff --git a/thirdpartylibs.xml b/thirdpartylibs.xml index 83f969ab..c20b71a1 100644 --- a/thirdpartylibs.xml +++ b/thirdpartylibs.xml @@ -3,105 +3,112 @@ vendor/symfony/http-foundation http-foundation - v3.4.47 + v5.4.28 MIT vendor/symfony/filesystem filesystem - v3.4.47 + v5.4.25 MIT vendor/symfony/event-dispatcher event-dispatcher - v3.4.47 + v4.4.44 MIT vendor/symfony/debug debug - v3.4.47 + v4.4.44 MIT vendor/psr/container container - 1.0.0 + 1.1.2 MIT vendor/symfony/polyfill-mbstring polyfill-mbstring - v1.27.0 + v1.28.0 MIT vendor/symfony/monolog-bridge monolog-bridge - v3.4.47 + v5.2.12 MIT vendor/symfony/monolog-bundle monolog-bundle - v3.6.0 + v3.8.0 + MIT + + + + vendor/symfony/http-client-contracts + http-client-contracts + v2.5.2 MIT vendor/symfony/http-kernel http-kernel - v3.4.49 + v4.4.50 MIT vendor/symfony/dependency-injection dependency-injection - v3.4.47 + v4.4.37 MIT vendor/monolog/monolog monolog - 1.27.1 + 2.9.1 MIT vendor/symfony/config config - v3.4.47 + v4.4.44 MIT vendor/symfony/expression-language expression-language - v3.4 + v3.4.47 MIT vendor/symfony/yaml yaml - v3.4 + v3.4.47 MIT vendor/phpseclib/phpseclib PHP Secure Communications Library - 3.0 + 3.0.23 MIT @@ -134,30 +141,72 @@ - vendor/psr/simple-cache - Common interfaces for simple caching - 1.0.1 + vendor/symfony/cache + Provides extended PSR-6, PSR-16 (and tags) implementations + v4.4.48 MIT - vendor/symfony/cache - Provides extended PSR-6, PSR-16 (and tags) implementations - 3.4.47 + vendor/symfony/error-handler + error-handler + v4.4.44 + MIT + + + + vendor/symfony/deprecation-contracts + error-handler + v2.5.2 + MIT + + + + vendor/symfony/polyfill-php80 + provides features added to PHP 8.0 core + v1.28.0 MIT - vendor/symfony/polyfill-apcu - Symfony polyfill backporting apcu_* functions to lower PHP versions - 1.26.0 + vendor/symfony/polyfill-php81 + provides features added to PHP 8.1 core + v1.28.0 + MIT + + + + vendor/symfony/polyfill-php73 + provides features added to PHP 7.3 core + v1.28.0 MIT vendor/symfony/polyfill-ctype Symfony polyfill for ctype functions - 1.26.0 + 1.28.0 + MIT + + + + vendor/symfony/service-contracts + A set of abstractions extracted out of the Symfony components. + v2.5.2 + MIT + + + + vendor/symfony/var-dumper + provides mechanisms for walking through any arbitrary PHP variable + v5.4.29 + MIT + + + + vendor/symfony/var-exporter + var-exporter + v5.4.26 MIT @@ -169,4 +218,4 @@ MIT - + \ No newline at end of file diff --git a/vendor/autoload.php b/vendor/autoload.php index 43793ea4..b855fff9 100644 --- a/vendor/autoload.php +++ b/vendor/autoload.php @@ -22,4 +22,4 @@ require_once __DIR__ . '/composer/autoload_real.php'; -return ComposerAutoloaderInit1b7a03c03ab553765e4ca44f392844bb::getLoader(); +return ComposerAutoloaderInitcda14bec2947bfd5c514478cf54ecddd::getLoader(); diff --git a/vendor/bin/var-dump-server b/vendor/bin/var-dump-server new file mode 100755 index 00000000..18db1c1e --- /dev/null +++ b/vendor/bin/var-dump-server @@ -0,0 +1,119 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'); + } +} + +return include __DIR__ . '/..'.'/symfony/var-dumper/Resources/bin/var-dump-server'; diff --git a/vendor/composer/ClassLoader.php b/vendor/composer/ClassLoader.php index a72151c7..7824d8f7 100644 --- a/vendor/composer/ClassLoader.php +++ b/vendor/composer/ClassLoader.php @@ -45,35 +45,34 @@ class ClassLoader /** @var \Closure(string):void */ private static $includeFile; - /** @var ?string */ + /** @var string|null */ private $vendorDir; // PSR-4 /** - * @var array[] - * @psalm-var array> + * @var array> */ private $prefixLengthsPsr4 = array(); /** - * @var array[] - * @psalm-var array> + * @var array> */ private $prefixDirsPsr4 = array(); /** - * @var array[] - * @psalm-var array + * @var list */ private $fallbackDirsPsr4 = array(); // PSR-0 /** - * @var array[] - * @psalm-var array> + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> */ private $prefixesPsr0 = array(); /** - * @var array[] - * @psalm-var array + * @var list */ private $fallbackDirsPsr0 = array(); @@ -81,8 +80,7 @@ class ClassLoader private $useIncludePath = false; /** - * @var string[] - * @psalm-var array + * @var array */ private $classMap = array(); @@ -90,21 +88,20 @@ class ClassLoader private $classMapAuthoritative = false; /** - * @var bool[] - * @psalm-var array + * @var array */ private $missingClasses = array(); - /** @var ?string */ + /** @var string|null */ private $apcuPrefix; /** - * @var self[] + * @var array */ private static $registeredLoaders = array(); /** - * @param ?string $vendorDir + * @param string|null $vendorDir */ public function __construct($vendorDir = null) { @@ -113,7 +110,7 @@ public function __construct($vendorDir = null) } /** - * @return string[] + * @return array> */ public function getPrefixes() { @@ -125,8 +122,7 @@ public function getPrefixes() } /** - * @return array[] - * @psalm-return array> + * @return array> */ public function getPrefixesPsr4() { @@ -134,8 +130,7 @@ public function getPrefixesPsr4() } /** - * @return array[] - * @psalm-return array + * @return list */ public function getFallbackDirs() { @@ -143,8 +138,7 @@ public function getFallbackDirs() } /** - * @return array[] - * @psalm-return array + * @return list */ public function getFallbackDirsPsr4() { @@ -152,8 +146,7 @@ public function getFallbackDirsPsr4() } /** - * @return string[] Array of classname => path - * @psalm-return array + * @return array Array of classname => path */ public function getClassMap() { @@ -161,8 +154,7 @@ public function getClassMap() } /** - * @param string[] $classMap Class to filename map - * @psalm-param array $classMap + * @param array $classMap Class to filename map * * @return void */ @@ -179,24 +171,25 @@ public function addClassMap(array $classMap) * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories * * @return void */ public function add($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, - (array) $paths + $paths ); } @@ -205,19 +198,19 @@ public function add($prefix, $paths, $prepend = false) $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; + $this->prefixesPsr0[$first][$prefix] = $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], - (array) $paths + $paths ); } } @@ -226,9 +219,9 @@ public function add($prefix, $paths, $prepend = false) * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException * @@ -236,17 +229,18 @@ public function add($prefix, $paths, $prepend = false) */ public function addPsr4($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, - (array) $paths + $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { @@ -256,18 +250,18 @@ public function addPsr4($prefix, $paths, $prepend = false) throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; + $this->prefixDirsPsr4[$prefix] = $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], - (array) $paths + $paths ); } } @@ -276,8 +270,8 @@ public function addPsr4($prefix, $paths, $prepend = false) * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories * * @return void */ @@ -294,8 +288,8 @@ public function set($prefix, $paths) * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException * @@ -481,9 +475,9 @@ public function findFile($class) } /** - * Returns the currently registered loaders indexed by their corresponding vendor directories. + * Returns the currently registered loaders keyed by their corresponding vendor directories. * - * @return self[] + * @return array */ public static function getRegisteredLoaders() { diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php index c6b54af7..51e734a7 100644 --- a/vendor/composer/InstalledVersions.php +++ b/vendor/composer/InstalledVersions.php @@ -98,7 +98,7 @@ public static function isInstalled($packageName, $includeDevRequirements = true) { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ public static function isInstalled($packageName, $includeDevRequirements = true) */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -328,7 +328,9 @@ private static function getInstalled() if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ private static function getInstalled() // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 0fb0a2c1..de9959c3 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,5 +6,13 @@ $baseDir = dirname($vendorDir); return array( + 'Attribute' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'CURLStringFile' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', + 'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'PhpToken' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'ReturnTypeWillChange' => $vendorDir . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php', + 'Stringable' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => $vendorDir . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 82f506f7..8e597ba6 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,8 +6,12 @@ $baseDir = dirname($vendorDir); return array( - '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => $vendorDir . '/symfony/polyfill-php80/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => $vendorDir . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', - '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => $vendorDir . '/symfony/var-dumper/Resources/functions/dump.php', + '23c18046f52bef3eea034657bafda50f' => $vendorDir . '/symfony/polyfill-php81/bootstrap.php', 'decc78cc4436b1292c6c0d151b19445c' => $vendorDir . '/phpseclib/phpseclib/phpseclib/bootstrap.php', ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index cfaa53cf..d1611656 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -7,22 +7,30 @@ return array( 'phpseclib3\\' => array($vendorDir . '/phpseclib/phpseclib/phpseclib'), + 'Symfony\\Polyfill\\Php81\\' => array($vendorDir . '/symfony/polyfill-php81'), + 'Symfony\\Polyfill\\Php80\\' => array($vendorDir . '/symfony/polyfill-php80'), + 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), - 'Symfony\\Polyfill\\Apcu\\' => array($vendorDir . '/symfony/polyfill-apcu'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\HttpClient\\' => array($vendorDir . '/symfony/http-client-contracts'), + 'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'), + 'Symfony\\Contracts\\Cache\\' => array($vendorDir . '/symfony/cache-contracts'), 'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'), + 'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'), + 'Symfony\\Component\\VarDumper\\' => array($vendorDir . '/symfony/var-dumper'), 'Symfony\\Component\\HttpKernel\\' => array($vendorDir . '/symfony/http-kernel'), 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), 'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'), 'Symfony\\Component\\ExpressionLanguage\\' => array($vendorDir . '/symfony/expression-language'), 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), + 'Symfony\\Component\\ErrorHandler\\' => array($vendorDir . '/symfony/error-handler'), 'Symfony\\Component\\DependencyInjection\\' => array($vendorDir . '/symfony/dependency-injection'), 'Symfony\\Component\\Debug\\' => array($vendorDir . '/symfony/debug'), 'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'), 'Symfony\\Component\\Cache\\' => array($vendorDir . '/symfony/cache'), 'Symfony\\Bundle\\MonologBundle\\' => array($vendorDir . '/symfony/monolog-bundle'), 'Symfony\\Bridge\\Monolog\\' => array($vendorDir . '/symfony/monolog-bridge'), - 'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'), 'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), 'Psr\\Cache\\' => array($vendorDir . '/psr/cache/src'), diff --git a/vendor/composer/autoload_real.php b/vendor/composer/autoload_real.php index 8907379d..281bf5eb 100644 --- a/vendor/composer/autoload_real.php +++ b/vendor/composer/autoload_real.php @@ -2,7 +2,7 @@ // autoload_real.php @generated by Composer -class ComposerAutoloaderInit1b7a03c03ab553765e4ca44f392844bb +class ComposerAutoloaderInitcda14bec2947bfd5c514478cf54ecddd { private static $loader; @@ -24,16 +24,16 @@ public static function getLoader() require __DIR__ . '/platform_check.php'; - spl_autoload_register(array('ComposerAutoloaderInit1b7a03c03ab553765e4ca44f392844bb', 'loadClassLoader'), true, true); + spl_autoload_register(array('ComposerAutoloaderInitcda14bec2947bfd5c514478cf54ecddd', 'loadClassLoader'), true, true); self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); - spl_autoload_unregister(array('ComposerAutoloaderInit1b7a03c03ab553765e4ca44f392844bb', 'loadClassLoader')); + spl_autoload_unregister(array('ComposerAutoloaderInitcda14bec2947bfd5c514478cf54ecddd', 'loadClassLoader')); require __DIR__ . '/autoload_static.php'; - call_user_func(\Composer\Autoload\ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb::getInitializer($loader)); + call_user_func(\Composer\Autoload\ComposerStaticInitcda14bec2947bfd5c514478cf54ecddd::getInitializer($loader)); $loader->register(true); - $filesToLoad = \Composer\Autoload\ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb::$files; + $filesToLoad = \Composer\Autoload\ComposerStaticInitcda14bec2947bfd5c514478cf54ecddd::$files; $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 657b72be..5275d43e 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -4,12 +4,16 @@ namespace Composer\Autoload; -class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb +class ComposerStaticInitcda14bec2947bfd5c514478cf54ecddd { public static $files = array ( - '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + 'a4a119a56e50fbb293281d9a48007e0e' => __DIR__ . '/..' . '/symfony/polyfill-php80/bootstrap.php', + '6e3fae29631ef280660b3cdad06f25a8' => __DIR__ . '/..' . '/symfony/deprecation-contracts/function.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', - '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php', + '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', + '667aeda72477189d0494fecd327c3641' => __DIR__ . '/..' . '/symfony/var-dumper/Resources/functions/dump.php', + '23c18046f52bef3eea034657bafda50f' => __DIR__ . '/..' . '/symfony/polyfill-php81/bootstrap.php', 'decc78cc4436b1292c6c0d151b19445c' => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib/bootstrap.php', ); @@ -20,15 +24,24 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb ), 'S' => array ( + 'Symfony\\Polyfill\\Php81\\' => 23, + 'Symfony\\Polyfill\\Php80\\' => 23, + 'Symfony\\Polyfill\\Php73\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, 'Symfony\\Polyfill\\Ctype\\' => 23, - 'Symfony\\Polyfill\\Apcu\\' => 22, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\HttpClient\\' => 29, + 'Symfony\\Contracts\\EventDispatcher\\' => 34, + 'Symfony\\Contracts\\Cache\\' => 24, 'Symfony\\Component\\Yaml\\' => 23, + 'Symfony\\Component\\VarExporter\\' => 30, + 'Symfony\\Component\\VarDumper\\' => 28, 'Symfony\\Component\\HttpKernel\\' => 29, 'Symfony\\Component\\HttpFoundation\\' => 33, 'Symfony\\Component\\Filesystem\\' => 29, 'Symfony\\Component\\ExpressionLanguage\\' => 37, 'Symfony\\Component\\EventDispatcher\\' => 34, + 'Symfony\\Component\\ErrorHandler\\' => 31, 'Symfony\\Component\\DependencyInjection\\' => 38, 'Symfony\\Component\\Debug\\' => 24, 'Symfony\\Component\\Config\\' => 25, @@ -38,7 +51,6 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb ), 'P' => array ( - 'Psr\\SimpleCache\\' => 16, 'Psr\\Log\\' => 8, 'Psr\\Container\\' => 14, 'Psr\\Cache\\' => 10, @@ -55,6 +67,18 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb array ( 0 => __DIR__ . '/..' . '/phpseclib/phpseclib/phpseclib', ), + 'Symfony\\Polyfill\\Php81\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php81', + ), + 'Symfony\\Polyfill\\Php80\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php80', + ), + 'Symfony\\Polyfill\\Php73\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', + ), 'Symfony\\Polyfill\\Mbstring\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', @@ -63,14 +87,34 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', ), - 'Symfony\\Polyfill\\Apcu\\' => + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\HttpClient\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/http-client-contracts', + ), + 'Symfony\\Contracts\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts', + ), + 'Symfony\\Contracts\\Cache\\' => array ( - 0 => __DIR__ . '/..' . '/symfony/polyfill-apcu', + 0 => __DIR__ . '/..' . '/symfony/cache-contracts', ), 'Symfony\\Component\\Yaml\\' => array ( 0 => __DIR__ . '/..' . '/symfony/yaml', ), + 'Symfony\\Component\\VarExporter\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-exporter', + ), + 'Symfony\\Component\\VarDumper\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/var-dumper', + ), 'Symfony\\Component\\HttpKernel\\' => array ( 0 => __DIR__ . '/..' . '/symfony/http-kernel', @@ -91,6 +135,10 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb array ( 0 => __DIR__ . '/..' . '/symfony/event-dispatcher', ), + 'Symfony\\Component\\ErrorHandler\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/error-handler', + ), 'Symfony\\Component\\DependencyInjection\\' => array ( 0 => __DIR__ . '/..' . '/symfony/dependency-injection', @@ -115,10 +163,6 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb array ( 0 => __DIR__ . '/..' . '/symfony/monolog-bridge', ), - 'Psr\\SimpleCache\\' => - array ( - 0 => __DIR__ . '/..' . '/psr/simple-cache/src', - ), 'Psr\\Log\\' => array ( 0 => __DIR__ . '/..' . '/psr/log/Psr/Log', @@ -142,15 +186,23 @@ class ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb ); public static $classMap = array ( + 'Attribute' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Attribute.php', + 'CURLStringFile' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php', 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', + 'PhpToken' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/PhpToken.php', + 'ReturnTypeWillChange' => __DIR__ . '/..' . '/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php', + 'Stringable' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/Stringable.php', + 'UnhandledMatchError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php', + 'ValueError' => __DIR__ . '/..' . '/symfony/polyfill-php80/Resources/stubs/ValueError.php', ); public static function getInitializer(ClassLoader $loader) { return \Closure::bind(function () use ($loader) { - $loader->prefixLengthsPsr4 = ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb::$prefixLengthsPsr4; - $loader->prefixDirsPsr4 = ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb::$prefixDirsPsr4; - $loader->classMap = ComposerStaticInit1b7a03c03ab553765e4ca44f392844bb::$classMap; + $loader->prefixLengthsPsr4 = ComposerStaticInitcda14bec2947bfd5c514478cf54ecddd::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitcda14bec2947bfd5c514478cf54ecddd::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitcda14bec2947bfd5c514478cf54ecddd::$classMap; }, null, ClassLoader::class); } diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 61810dca..be7f5fbf 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -2,53 +2,69 @@ "packages": [ { "name": "monolog/monolog", - "version": "1.27.1", - "version_normalized": "1.27.1.0", + "version": "2.9.1", + "version_normalized": "2.9.1.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "904713c5929655dc9b97288b69cfeedad610c9a1" + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/904713c5929655dc9b97288b69cfeedad610c9a1", - "reference": "904713c5929655dc9b97288b69cfeedad610c9a1", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", "shasum": "" }, "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", - "graylog2/gelf-php": "~1.0", - "php-amqplib/php-amqplib": "~2.4", - "php-console/php-console": "^3.1.3", - "phpstan/phpstan": "^0.12.59", - "phpunit/phpunit": "~4.5", - "ruflin/elastica": ">=0.90 <3.0", - "sentry/sentry": "^0.13", - "swiftmailer/swiftmailer": "^5.3|^6.0" + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", - "php-console/php-console": "Allow sending log messages to Google Chrome", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server", - "sentry/sentry": "Allow sending log messages to a Sentry server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, - "time": "2022-06-09T08:53:42+00:00", + "time": "2023-02-06T13:44:46+00:00", "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "installation-source": "dist", "autoload": { "psr-4": { @@ -63,11 +79,11 @@ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "description": "Sends your logs to files, sockets, inboxes, databases and various web services", - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ "log", "logging", @@ -75,7 +91,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/1.27.1" + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" }, "funding": [ { @@ -214,17 +230,17 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.21", - "version_normalized": "3.0.21.0", + "version": "3.0.23", + "version_normalized": "3.0.23.0", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1" + "reference": "866cc78fbd82462ffd880e3f65692afe928bed50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/4580645d3fc05c189024eb3b834c6c1e4f0f30a1", - "reference": "4580645d3fc05c189024eb3b834c6c1e4f0f30a1", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/866cc78fbd82462ffd880e3f65692afe928bed50", + "reference": "866cc78fbd82462ffd880e3f65692afe928bed50", "shasum": "" }, "require": { @@ -242,7 +258,7 @@ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." }, - "time": "2023-07-09T15:24:48+00:00", + "time": "2023-09-18T17:22:01+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -307,7 +323,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.21" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.23" }, "funding": [ { @@ -379,29 +395,24 @@ }, { "name": "psr/container", - "version": "1.0.0", - "version_normalized": "1.0.0.0", + "version": "1.1.2", + "version_normalized": "1.1.2.0", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", - "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.4.0" }, - "time": "2017-02-14T16:28:37+00:00", + "time": "2021-11-05T16:50:12+00:00", "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "installation-source": "dist", "autoload": { "psr-4": { @@ -415,7 +426,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common Container Interface (PHP FIG PSR-11)", @@ -429,7 +440,7 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, "install-path": "../psr/container" }, @@ -487,35 +498,63 @@ "install-path": "../psr/log" }, { - "name": "psr/simple-cache", - "version": "1.0.1", - "version_normalized": "1.0.1.0", + "name": "symfony/cache", + "version": "v4.4.48", + "version_normalized": "4.4.48.0", "source": { "type": "git", - "url": "https://github.com/php-fig/simple-cache.git", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + "url": "https://github.com/symfony/cache.git", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", - "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "url": "https://api.github.com/repos/symfony/cache/zipball/3b98ed664887ad197b8ede3da2432787212eb915", + "reference": "3b98ed664887ad197b8ede3da2432787212eb915", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" }, - "time": "2017-10-23T01:57:42+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "conflict": { + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" + }, + "provide": { + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" + }, + "time": "2022-10-17T20:21:54+00:00", + "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Psr\\SimpleCache\\": "src/" - } + "Symfony\\Component\\Cache\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -523,68 +562,77 @@ ], "authors": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Common interfaces for simple caching", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", "keywords": [ - "cache", "caching", - "psr", - "psr-16", - "simple-cache" + "psr6" ], "support": { - "source": "https://github.com/php-fig/simple-cache/tree/master" + "source": "https://github.com/symfony/cache/tree/v4.4.48" }, - "install-path": "../psr/simple-cache" + "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" + } + ], + "install-path": "../symfony/cache" }, { - "name": "symfony/cache", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "name": "symfony/cache-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a7a14c4832760bd1fbd31be2859ffedc9b6ff813", - "reference": "a7a14c4832760bd1fbd31be2859ffedc9b6ff813", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", + "reference": "64be4a7acb83b6f2bf6de9a02cee6dad41277ebc", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/cache": "~1.0", - "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/polyfill-apcu": "~1.1" - }, - "conflict": { - "symfony/var-dumper": "<3.3" + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" }, - "provide": { - "psr/cache-implementation": "1.0", - "psr/simple-cache-implementation": "1.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/cache": "^1.6", - "doctrine/dbal": "^2.4|^3.0", - "predis/predis": "^1.0" + "suggest": { + "symfony/cache-implementation": "" }, - "time": "2020-10-24T10:57:07+00:00", + "time": "2022-01-02T09:53:40+00:00", "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\Cache\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -600,14 +648,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "description": "Generic abstractions related to caching", "homepage": "https://symfony.com", "keywords": [ - "caching", - "psr6" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/cache/tree/v3.4.47" + "source": "https://github.com/symfony/cache-contracts/tree/v2.5.2" }, "funding": [ { @@ -623,42 +675,44 @@ "type": "tidelift" } ], - "install-path": "../symfony/cache" + "install-path": "../symfony/cache-contracts" }, { "name": "symfony/config", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "version": "v4.4.44", + "version_normalized": "4.4.44.0", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f" + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f", - "reference": "bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f", + "url": "https://api.github.com/repos/symfony/config/zipball/ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", + "reference": "ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" }, "conflict": { - "symfony/dependency-injection": "<3.3", - "symfony/finder": "<3.3" + "symfony/finder": "<3.4" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0", - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0" + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" }, - "time": "2020-10-24T10:57:07+00:00", + "time": "2022-07-20T09:59:04+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -683,10 +737,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Config Component", + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v3.4.47" + "source": "https://github.com/symfony/config/tree/v4.4.44" }, "funding": [ { @@ -706,30 +760,30 @@ }, { "name": "symfony/debug", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "version": "v4.4.44", + "version_normalized": "4.4.44.0", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "ab42889de57fdfcfcc0759ab102e2fd4ea72dcae" + "reference": "1a692492190773c5310bc7877cb590c04c2f05be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/ab42889de57fdfcfcc0759ab102e2fd4ea72dcae", - "reference": "ab42889de57fdfcfcc0759ab102e2fd4ea72dcae", + "url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be", + "reference": "1a692492190773c5310bc7877cb590c04c2f05be", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, - "time": "2020-10-24T10:57:07+00:00", + "time": "2022-07-28T16:29:46+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -754,10 +808,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Debug Component", + "description": "Provides tools to ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/debug/tree/v3.4.47" + "source": "https://github.com/symfony/debug/tree/v4.4.44" }, "funding": [ { @@ -778,36 +832,39 @@ }, { "name": "symfony/dependency-injection", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "version": "v4.4.37", + "version_normalized": "4.4.37.0", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "51d2a2708c6ceadad84393f8581df1dcf9e5e84b" + "reference": "c00a23904b42f140087d36e1d22c88801bb39689" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/51d2a2708c6ceadad84393f8581df1dcf9e5e84b", - "reference": "51d2a2708c6ceadad84393f8581df1dcf9e5e84b", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c00a23904b42f140087d36e1d22c88801bb39689", + "reference": "c00a23904b42f140087d36e1d22c88801bb39689", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" }, "require-dev": { - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/yaml": "~3.4|~4.0" + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/yaml": "^4.4|^5.0" }, "suggest": { "symfony/config": "", @@ -816,7 +873,7 @@ "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them", "symfony/yaml": "" }, - "time": "2020-10-24T10:57:07+00:00", + "time": "2022-01-24T17:17:45+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -841,10 +898,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony DependencyInjection Component", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v3.4.47" + "source": "https://github.com/symfony/dependency-injection/tree/v4.4.37" }, "funding": [ { @@ -863,47 +920,38 @@ "install-path": "../symfony/dependency-injection" }, { - "name": "symfony/event-dispatcher", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "31fde73757b6bad247c54597beef974919ec6860" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/31fde73757b6bad247c54597beef974919ec6860", - "reference": "31fde73757b6bad247c54597beef974919ec6860", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" - }, - "conflict": { - "symfony/dependency-injection": "<3.3" - }, - "require-dev": { - "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/debug": "~3.4|~4.4", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" - }, - "suggest": { - "symfony/dependency-injection": "", - "symfony/http-kernel": "" + "php": ">=7.1" }, - "time": "2020-10-24T10:57:07+00:00", + "time": "2022-01-02T09:53:40+00:00", "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, "installation-source": "dist", "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "function.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -912,18 +960,18 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony EventDispatcher Component", + "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v3.4.47" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" }, "funding": [ { @@ -939,34 +987,39 @@ "type": "tidelift" } ], - "install-path": "../symfony/event-dispatcher" + "install-path": "../symfony/deprecation-contracts" }, { - "name": "symfony/expression-language", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "name": "symfony/error-handler", + "version": "v4.4.44", + "version_normalized": "4.4.44.0", "source": { "type": "git", - "url": "https://github.com/symfony/expression-language.git", - "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f" + "url": "https://github.com/symfony/error-handler.git", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/de38e66398fca1fcb9c48e80279910e6889cb28f", - "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/be731658121ef2d8be88f3a1ec938148a9237291", + "reference": "be731658121ef2d8be88f3a1ec938148a9237291", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/cache": "~3.1|~4.0", - "symfony/polyfill-php70": "~1.6" + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" }, - "time": "2020-10-24T10:57:07+00:00", + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "time": "2022-07-28T16:29:46+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Component\\ExpressionLanguage\\": "" + "Symfony\\Component\\ErrorHandler\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -986,10 +1039,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony ExpressionLanguage Component", + "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v3.4.47" + "source": "https://github.com/symfony/error-handler/tree/v4.4.44" }, "funding": [ { @@ -1005,33 +1058,55 @@ "type": "tidelift" } ], - "install-path": "../symfony/expression-language" + "install-path": "../symfony/error-handler" }, { - "name": "symfony/filesystem", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "name": "symfony/event-dispatcher", + "version": "v4.4.44", + "version_normalized": "4.4.44.0", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/e58d7841cddfed6e846829040dca2cca0ebbbbb3", - "reference": "e58d7841cddfed6e846829040dca2cca0ebbbbb3", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1e866e9e5c1b22168e0ce5f0b467f19bba61266a", + "reference": "1e866e9e5c1b22168e0ce5f0b467f19bba61266a", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" }, - "time": "2020-10-24T10:57:07+00:00", + "conflict": { + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2022-07-20T09:59:04+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Component\\Filesystem\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1051,10 +1126,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Filesystem Component", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v3.4.47" + "source": "https://github.com/symfony/event-dispatcher/tree/v4.4.44" }, "funding": [ { @@ -1070,41 +1145,46 @@ "type": "tidelift" } ], - "install-path": "../symfony/filesystem" + "install-path": "../symfony/event-dispatcher" }, { - "name": "symfony/http-foundation", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.13", + "version_normalized": "1.1.13.0", "source": { "type": "git", - "url": "https://github.com/symfony/http-foundation.git", - "reference": "b9885fcce6fe494201da4f70a9309770e9d13dc8" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/b9885fcce6fe494201da4f70a9309770e9d13dc8", - "reference": "b9885fcce6fe494201da4f70a9309770e9d13dc8", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/1d5cd762abaa6b2a4169d3e77610193a7157129e", + "reference": "1d5cd762abaa6b2a4169d3e77610193a7157129e", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": ">=7.1.3" }, - "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" }, - "time": "2020-10-24T10:57:07+00:00", + "time": "2022-01-02T09:41:36+00:00", "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Component\\HttpFoundation\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1112,18 +1192,26 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpFoundation Component", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], "support": { - "source": "https://github.com/symfony/http-foundation/tree/v3.4.47" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v1.1.13" }, "funding": [ { @@ -1139,73 +1227,34 @@ "type": "tidelift" } ], - "install-path": "../symfony/http-foundation" + "install-path": "../symfony/event-dispatcher-contracts" }, { - "name": "symfony/http-kernel", - "version": "v3.4.49", - "version_normalized": "3.4.49.0", + "name": "symfony/expression-language", + "version": "v3.4.47", + "version_normalized": "3.4.47.0", "source": { "type": "git", - "url": "https://github.com/symfony/http-kernel.git", - "reference": "5aa72405f5bd5583c36ed6e756acb17d3f98ac40" + "url": "https://github.com/symfony/expression-language.git", + "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/5aa72405f5bd5583c36ed6e756acb17d3f98ac40", - "reference": "5aa72405f5bd5583c36ed6e756acb17d3f98ac40", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/de38e66398fca1fcb9c48e80279910e6889cb28f", + "reference": "de38e66398fca1fcb9c48e80279910e6889cb28f", "shasum": "" }, "require": { "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0", - "symfony/debug": "^3.3.3|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php56": "~1.8" - }, - "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", - "twig/twig": "<1.34|<2.4,>=2" - }, - "provide": { - "psr/log-implementation": "1.0" - }, - "require-dev": { - "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" - }, - "suggest": { - "symfony/browser-kit": "", - "symfony/config": "", - "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" + "symfony/cache": "~3.1|~4.0", + "symfony/polyfill-php70": "~1.6" }, - "time": "2021-05-19T12:06:59+00:00", + "time": "2020-10-24T10:57:07+00:00", "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Component\\HttpKernel\\": "" + "Symfony\\Component\\ExpressionLanguage\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1225,10 +1274,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony HttpKernel Component", + "description": "Symfony ExpressionLanguage Component", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v3.4.49" + "source": "https://github.com/symfony/expression-language/tree/v3.4.47" }, "funding": [ { @@ -1244,50 +1293,35 @@ "type": "tidelift" } ], - "install-path": "../symfony/http-kernel" + "install-path": "../symfony/expression-language" }, { - "name": "symfony/monolog-bridge", - "version": "v3.4.47", - "version_normalized": "3.4.47.0", + "name": "symfony/filesystem", + "version": "v5.4.25", + "version_normalized": "5.4.25.0", "source": { "type": "git", - "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "93915f0d981bc166dfa475698124435327f6ee63" + "url": "https://github.com/symfony/filesystem.git", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/93915f0d981bc166dfa475698124435327f6ee63", - "reference": "93915f0d981bc166dfa475698124435327f6ee63", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", + "reference": "0ce3a62c9579a53358d3a7eb6b3dfb79789a6364", "shasum": "" }, "require": { - "monolog/monolog": "~1.19", - "php": "^5.5.9|>=7.0.8", - "symfony/http-kernel": "~2.8|~3.0|~4.0" - }, - "conflict": { - "symfony/console": "<2.8", - "symfony/http-foundation": "<3.3" - }, - "require-dev": { - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/security-core": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" - }, - "suggest": { - "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings. You need version ^2.8 of the console for it.", - "symfony/event-dispatcher": "Needed when using log messages in console commands.", - "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", - "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" }, - "time": "2020-10-24T10:57:07+00:00", - "type": "symfony-bridge", + "time": "2023-05-31T13:04:02+00:00", + "type": "library", "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Bridge\\Monolog\\": "" + "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1307,10 +1341,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony Monolog Bridge", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v3.4.47" + "source": "https://github.com/symfony/filesystem/tree/v5.4.25" }, "funding": [ { @@ -1326,47 +1360,128 @@ "type": "tidelift" } ], - "install-path": "../symfony/monolog-bridge" + "install-path": "../symfony/filesystem" }, { - "name": "symfony/monolog-bundle", - "version": "v3.6.0", - "version_normalized": "3.6.0.0", + "name": "symfony/http-client-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", "source": { "type": "git", - "url": "https://github.com/symfony/monolog-bundle.git", - "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940" + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/e495f5c7e4e672ffef4357d4a4d85f010802f940", - "reference": "e495f5c7e4e672ffef4357d4a4d85f010802f940", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", + "reference": "ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70", "shasum": "" }, "require": { - "monolog/monolog": "~1.22 || ~2.0", - "php": ">=5.6", - "symfony/config": "~3.4 || ~4.0 || ^5.0", - "symfony/dependency-injection": "~3.4.10 || ^4.0.10 || ^5.0", - "symfony/http-kernel": "~3.4 || ~4.0 || ^5.0", - "symfony/monolog-bridge": "~3.4 || ~4.0 || ^5.0" + "php": ">=7.2.5" }, - "require-dev": { - "symfony/console": "~3.4 || ~4.0 || ^5.0", - "symfony/phpunit-bridge": "^4.4 || ^5.0", - "symfony/yaml": "~3.4 || ~4.0 || ^5.0" + "suggest": { + "symfony/http-client-implementation": "" }, - "time": "2020-10-06T15:12:11+00:00", - "type": "symfony-bundle", + "time": "2022-04-12T15:48:08+00:00", + "type": "library", "extra": { "branch-alias": { - "dev-master": "3.x-dev" + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Bundle\\MonologBundle\\": "" + "Symfony\\Contracts\\HttpClient\\": "" + } + }, + "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 HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v2.5.2" + }, + "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" + } + ], + "install-path": "../symfony/http-client-contracts" + }, + { + "name": "symfony/http-foundation", + "version": "v5.4.28", + "version_normalized": "5.4.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/365992c83a836dfe635f1e903ccca43ee03d3dd2", + "reference": "365992c83a836dfe635f1e903ccca43ee03d3dd2", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" + }, + "suggest": { + "symfony/mime": "To use the file extension guesser" + }, + "time": "2023-08-21T07:23:18+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -1383,18 +1498,13 @@ }, { "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony MonologBundle", - "homepage": "http://symfony.com", - "keywords": [ - "log", - "logging" - ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", "support": { - "issues": "https://github.com/symfony/monolog-bundle/issues", - "source": "https://github.com/symfony/monolog-bundle/tree/v3.6.0" + "source": "https://github.com/symfony/http-foundation/tree/v5.4.28" }, "funding": [ { @@ -1410,71 +1520,268 @@ "type": "tidelift" } ], - "install-path": "../symfony/monolog-bundle" + "install-path": "../symfony/http-foundation" }, { - "name": "symfony/polyfill-apcu", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "name": "symfony/http-kernel", + "version": "v4.4.50", + "version_normalized": "4.4.50.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-apcu.git", - "reference": "6e7f6ed2168779a2b3927e606a9768860a8bdfa0" + "url": "https://github.com/symfony/http-kernel.git", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/6e7f6ed2168779a2b3927e606a9768860a8bdfa0", - "reference": "6e7f6ed2168779a2b3927e606a9768860a8bdfa0", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aa6df6c045f034aa13ac752fc234bb300b9488ef", + "reference": "aa6df6c045f034aa13ac752fc234bb300b9488ef", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.1.3", + "psr/log": "^1|^2", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "twig/twig": "^1.43|^2.13|^3.0.4" }, - "time": "2022-11-03T14:55:06+00:00", + "suggest": { + "symfony/browser-kit": "", + "symfony/config": "", + "symfony/console": "", + "symfony/dependency-injection": "" + }, + "time": "2023-02-01T08:01:31+00:00", "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "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": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v4.4.50" + }, + "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" } + ], + "install-path": "../symfony/http-kernel" + }, + { + "name": "symfony/monolog-bridge", + "version": "v5.2.12", + "version_normalized": "5.2.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bridge.git", + "reference": "2c3943d7c0100983f9c0a82807555273353e3539" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/2c3943d7c0100983f9c0a82807555273353e3539", + "reference": "2c3943d7c0100983f9c0a82807555273353e3539", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.25.1|^2", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2" + }, + "conflict": { + "symfony/console": "<4.4", + "symfony/http-foundation": "<4.4" + }, + "require-dev": { + "symfony/console": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0" + }, + "suggest": { + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", + "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", + "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." }, + "time": "2021-07-23T15:54:19+00:00", + "type": "symfony-bridge", "installation-source": "dist", "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Apcu\\": "" + "Symfony\\Bridge\\Monolog\\": "" + }, + "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": "Provides integration for Monolog with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/monolog-bridge/tree/v5.2.12" + }, + "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" + } + ], + "install-path": "../symfony/monolog-bridge" + }, + { + "name": "symfony/monolog-bundle", + "version": "v3.8.0", + "version_normalized": "3.8.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/monolog-bundle.git", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/monolog-bundle/zipball/a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "reference": "a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d", + "shasum": "" + }, + "require": { + "monolog/monolog": "^1.22 || ^2.0 || ^3.0", + "php": ">=7.1.3", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0" + }, + "require-dev": { + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0", + "symfony/yaml": "~4.4 || ^5.0 || ^6.0" + }, + "time": "2022-05-10T14:24:36+00:00", + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" } }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MonologBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions", + "description": "Symfony MonologBundle", "homepage": "https://symfony.com", "keywords": [ - "apcu", - "compatibility", - "polyfill", - "portable", - "shim" + "log", + "logging" ], "support": { - "source": "https://github.com/symfony/polyfill-apcu/tree/v1.27.0" + "issues": "https://github.com/symfony/monolog-bundle/issues", + "source": "https://github.com/symfony/monolog-bundle/tree/v3.8.0" }, "funding": [ { @@ -1490,21 +1797,21 @@ "type": "tidelift" } ], - "install-path": "../symfony/polyfill-apcu" + "install-path": "../symfony/monolog-bundle" }, { "name": "symfony/polyfill-ctype", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", - "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", + "reference": "ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb", "shasum": "" }, "require": { @@ -1516,11 +1823,11 @@ "suggest": { "ext-ctype": "For best performance" }, - "time": "2022-11-03T14:55:06+00:00", + "time": "2023-01-26T09:26:14+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1559,7 +1866,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.28.0" }, "funding": [ { @@ -1579,17 +1886,17 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.27.0", - "version_normalized": "1.27.0.0", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", - "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { @@ -1601,11 +1908,11 @@ "suggest": { "ext-mbstring": "For best performance" }, - "time": "2022-11-03T14:55:06+00:00", + "time": "2023-07-28T09:04:16+00:00", "type": "library", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", @@ -1645,7 +1952,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.27.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, "funding": [ { @@ -1664,18 +1971,18 @@ "install-path": "../symfony/polyfill-mbstring" }, { - "name": "symfony/polyfill-php56", + "name": "symfony/polyfill-php70", "version": "v1.20.0", "version_normalized": "1.20.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675" + "url": "https://github.com/symfony/polyfill-php70.git", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", - "reference": "54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644", + "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644", "shasum": "" }, "require": { @@ -1706,7 +2013,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1715,7 +2022,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php56/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0" }, "funding": [ { @@ -1734,34 +2041,46 @@ "install-path": null }, { - "name": "symfony/polyfill-php70", - "version": "v1.20.0", - "version_normalized": "1.20.0.0", + "name": "symfony/polyfill-php73", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644" + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/5f03a781d984aae42cebd18e7912fa80f02ee644", - "reference": "5f03a781d984aae42cebd18e7912fa80f02ee644", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fe2f306d1d9d346a7fee353d0d5012e401e984b5", + "reference": "fe2f306d1d9d346a7fee353d0d5012e401e984b5", "shasum": "" }, "require": { "php": ">=7.1" }, - "time": "2020-10-23T14:02:19+00:00", - "type": "metapackage", + "time": "2023-01-26T09:26:14+00:00", + "type": "library", "extra": { "branch-alias": { - "dev-main": "1.20-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" } }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" @@ -1776,7 +2095,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1785,7 +2104,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php70/tree/v1.20.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.28.0" }, "funding": [ { @@ -1801,7 +2120,429 @@ "type": "tidelift" } ], - "install-path": null + "install-path": "../symfony/polyfill-php73" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2023-01-26T09:26:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.0" + }, + "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" + } + ], + "install-path": "../symfony/polyfill-php80" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.28.0", + "version_normalized": "1.28.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/7581cd600fa9fd681b797d00b02f068e2f13263b", + "reference": "7581cd600fa9fd681b797d00b02f068e2f13263b", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "time": "2023-01-26T09:26:14+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "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 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.28.0" + }, + "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" + } + ], + "install-path": "../symfony/polyfill-php81" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.2", + "version_normalized": "2.5.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "time": "2022-05-30T19:17:29+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "installation-source": "dist", + "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" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + }, + "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" + } + ], + "install-path": "../symfony/service-contracts" + }, + { + "name": "symfony/var-dumper", + "version": "v5.4.29", + "version_normalized": "5.4.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6172e4ae3534d25ee9e07eb487c20be7760fcc65", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "time": "2023-09-12T10:09:58+00:00", + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v5.4.29" + }, + "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" + } + ], + "install-path": "../symfony/var-dumper" + }, + { + "name": "symfony/var-exporter", + "version": "v5.4.26", + "version_normalized": "5.4.26.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "11401fe94f960249b3c63a488c63ba73091c1e4a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/11401fe94f960249b3c63a488c63ba73091c1e4a", + "reference": "11401fe94f960249b3c63a488c63ba73091c1e4a", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "time": "2023-07-20T07:21:16+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "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": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v5.4.26" + }, + "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" + } + ], + "install-path": "../symfony/var-exporter" }, { "name": "symfony/yaml", diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index d95ca2d2..a89d7d47 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,9 +1,9 @@ array( 'name' => '__root__', - 'pretty_version' => 'dev-add-psr3-logging', - 'version' => 'dev-add-psr3-logging', - 'reference' => '5c5f3514930b256e86485766fc0fb11d7f9ab306', + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'reference' => NULL, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -11,18 +11,18 @@ ), 'versions' => array( '__root__' => array( - 'pretty_version' => 'dev-add-psr3-logging', - 'version' => 'dev-add-psr3-logging', - 'reference' => '5c5f3514930b256e86485766fc0fb11d7f9ab306', + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'reference' => NULL, 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), 'monolog/monolog' => array( - 'pretty_version' => '1.27.1', - 'version' => '1.27.1.0', - 'reference' => '904713c5929655dc9b97288b69cfeedad610c9a1', + 'pretty_version' => '2.9.1', + 'version' => '2.9.1.0', + 'reference' => 'f259e2b15fb95494c83f52d3caad003bbf5ffaa1', 'type' => 'library', 'install_path' => __DIR__ . '/../monolog/monolog', 'aliases' => array(), @@ -47,9 +47,9 @@ 'dev_requirement' => false, ), 'phpseclib/phpseclib' => array( - 'pretty_version' => '3.0.21', - 'version' => '3.0.21.0', - 'reference' => '4580645d3fc05c189024eb3b834c6c1e4f0f30a1', + 'pretty_version' => '3.0.23', + 'version' => '3.0.23.0', + 'reference' => '866cc78fbd82462ffd880e3f65692afe928bed50', 'type' => 'library', 'install_path' => __DIR__ . '/../phpseclib/phpseclib', 'aliases' => array(), @@ -67,13 +67,13 @@ 'psr/cache-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '1.0', + 0 => '1.0|2.0', ), ), 'psr/container' => array( - 'pretty_version' => '1.0.0', - 'version' => '1.0.0.0', - 'reference' => 'b7ce3b176482dbbc1245ebf52b181af44c2cf55f', + 'pretty_version' => '1.1.2', + 'version' => '1.1.2.0', + 'reference' => '513e0666f7216c7459170d56df27dfcefe1689ea', 'type' => 'library', 'install_path' => __DIR__ . '/../psr/container', 'aliases' => array(), @@ -85,6 +85,12 @@ 0 => '1.0', ), ), + 'psr/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0', + ), + ), 'psr/log' => array( 'pretty_version' => '1.1.4', 'version' => '1.1.4.0', @@ -97,70 +103,109 @@ 'psr/log-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '1.0.0', - 1 => '1.0', + 0 => '1.0.0 || 2.0.0 || 3.0.0', + 1 => '1.0|2.0', ), ), - 'psr/simple-cache' => array( - 'pretty_version' => '1.0.1', - 'version' => '1.0.1.0', - 'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b', - 'type' => 'library', - 'install_path' => __DIR__ . '/../psr/simple-cache', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'psr/simple-cache-implementation' => array( 'dev_requirement' => false, 'provided' => array( - 0 => '1.0', + 0 => '1.0|2.0', ), ), 'symfony/cache' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => 'a7a14c4832760bd1fbd31be2859ffedc9b6ff813', + 'pretty_version' => 'v4.4.48', + 'version' => '4.4.48.0', + 'reference' => '3b98ed664887ad197b8ede3da2432787212eb915', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/cache', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/cache-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => '64be4a7acb83b6f2bf6de9a02cee6dad41277ebc', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/cache-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/cache-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0|2.0', + ), + ), 'symfony/config' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => 'bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f', + 'pretty_version' => 'v4.4.44', + 'version' => '4.4.44.0', + 'reference' => 'ed42f8f9da528d2c6cae36fe1f380b0c1d8f0658', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/config', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/debug' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => 'ab42889de57fdfcfcc0759ab102e2fd4ea72dcae', + 'pretty_version' => 'v4.4.44', + 'version' => '4.4.44.0', + 'reference' => '1a692492190773c5310bc7877cb590c04c2f05be', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/debug', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/dependency-injection' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => '51d2a2708c6ceadad84393f8581df1dcf9e5e84b', + 'pretty_version' => 'v4.4.37', + 'version' => '4.4.37.0', + 'reference' => 'c00a23904b42f140087d36e1d22c88801bb39689', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dependency-injection', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/deprecation-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'e8b495ea28c1d97b5e0c121748d6f9b53d075c66', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/deprecation-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/error-handler' => array( + 'pretty_version' => 'v4.4.44', + 'version' => '4.4.44.0', + 'reference' => 'be731658121ef2d8be88f3a1ec938148a9237291', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/error-handler', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'symfony/event-dispatcher' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => '31fde73757b6bad247c54597beef974919ec6860', + 'pretty_version' => 'v4.4.44', + 'version' => '4.4.44.0', + 'reference' => '1e866e9e5c1b22168e0ce5f0b467f19bba61266a', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/event-dispatcher-contracts' => array( + 'pretty_version' => 'v1.1.13', + 'version' => '1.1.13.0', + 'reference' => '1d5cd762abaa6b2a4169d3e77610193a7157129e', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/event-dispatcher-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/event-dispatcher-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.1', + ), + ), 'symfony/expression-language' => array( 'pretty_version' => 'v3.4.47', 'version' => '3.4.47.0', @@ -171,92 +216,143 @@ 'dev_requirement' => false, ), 'symfony/filesystem' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => 'e58d7841cddfed6e846829040dca2cca0ebbbbb3', + 'pretty_version' => 'v5.4.25', + 'version' => '5.4.25.0', + 'reference' => '0ce3a62c9579a53358d3a7eb6b3dfb79789a6364', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/filesystem', 'aliases' => array(), 'dev_requirement' => false, ), + 'symfony/http-client-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => 'ba6a9f0e8f3edd190520ee3b9a958596b6ca2e70', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/http-client-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), 'symfony/http-foundation' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => 'b9885fcce6fe494201da4f70a9309770e9d13dc8', + 'pretty_version' => 'v5.4.28', + 'version' => '5.4.28.0', + 'reference' => '365992c83a836dfe635f1e903ccca43ee03d3dd2', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-foundation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-kernel' => array( - 'pretty_version' => 'v3.4.49', - 'version' => '3.4.49.0', - 'reference' => '5aa72405f5bd5583c36ed6e756acb17d3f98ac40', + 'pretty_version' => 'v4.4.50', + 'version' => '4.4.50.0', + 'reference' => 'aa6df6c045f034aa13ac752fc234bb300b9488ef', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-kernel', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/monolog-bridge' => array( - 'pretty_version' => 'v3.4.47', - 'version' => '3.4.47.0', - 'reference' => '93915f0d981bc166dfa475698124435327f6ee63', + 'pretty_version' => 'v5.2.12', + 'version' => '5.2.12.0', + 'reference' => '2c3943d7c0100983f9c0a82807555273353e3539', 'type' => 'symfony-bridge', 'install_path' => __DIR__ . '/../symfony/monolog-bridge', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/monolog-bundle' => array( - 'pretty_version' => 'v3.6.0', - 'version' => '3.6.0.0', - 'reference' => 'e495f5c7e4e672ffef4357d4a4d85f010802f940', + 'pretty_version' => 'v3.8.0', + 'version' => '3.8.0.0', + 'reference' => 'a41bbcdc1105603b6d73a7d9a43a3788f8e0fb7d', 'type' => 'symfony-bundle', 'install_path' => __DIR__ . '/../symfony/monolog-bundle', 'aliases' => array(), 'dev_requirement' => false, ), - 'symfony/polyfill-apcu' => array( - 'pretty_version' => 'v1.27.0', - 'version' => '1.27.0.0', - 'reference' => '6e7f6ed2168779a2b3927e606a9768860a8bdfa0', - 'type' => 'library', - 'install_path' => __DIR__ . '/../symfony/polyfill-apcu', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'symfony/polyfill-ctype' => array( - 'pretty_version' => 'v1.27.0', - 'version' => '1.27.0.0', - 'reference' => '5bbc823adecdae860bb64756d639ecfec17b050a', + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => 'ea208ce43cbb04af6867b4fdddb1bdbf84cc28cb', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( - 'pretty_version' => 'v1.27.0', - 'version' => '1.27.0.0', - 'reference' => '8ad114f6b39e2c98a8b0e3bd907732c207c2b534', + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => '42292d99c55abe617799667f454222c54c60e229', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => false, ), - 'symfony/polyfill-php56' => array( + 'symfony/polyfill-php70' => array( 'pretty_version' => 'v1.20.0', 'version' => '1.20.0.0', - 'reference' => '54b8cd7e6c1643d78d011f3be89f3ef1f9f4c675', + 'reference' => '5f03a781d984aae42cebd18e7912fa80f02ee644', 'type' => 'metapackage', 'install_path' => NULL, 'aliases' => array(), 'dev_requirement' => false, ), - 'symfony/polyfill-php70' => array( - 'pretty_version' => 'v1.20.0', - 'version' => '1.20.0.0', - 'reference' => '5f03a781d984aae42cebd18e7912fa80f02ee644', - 'type' => 'metapackage', - 'install_path' => NULL, + 'symfony/polyfill-php73' => array( + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => 'fe2f306d1d9d346a7fee353d0d5012e401e984b5', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php73', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php80' => array( + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => '6caa57379c4aec19c0a12a38b59b26487dcfe4b5', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php80', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/polyfill-php81' => array( + 'pretty_version' => 'v1.28.0', + 'version' => '1.28.0.0', + 'reference' => '7581cd600fa9fd681b797d00b02f068e2f13263b', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/polyfill-php81', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/service-contracts' => array( + 'pretty_version' => 'v2.5.2', + 'version' => '2.5.2.0', + 'reference' => '4b426aac47d6427cc1a1d0f7e2ac724627f5966c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/service-contracts', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/service-implementation' => array( + 'dev_requirement' => false, + 'provided' => array( + 0 => '1.0|2.0', + ), + ), + 'symfony/var-dumper' => array( + 'pretty_version' => 'v5.4.29', + 'version' => '5.4.29.0', + 'reference' => '6172e4ae3534d25ee9e07eb487c20be7760fcc65', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-dumper', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'symfony/var-exporter' => array( + 'pretty_version' => 'v5.4.26', + 'version' => '5.4.26.0', + 'reference' => '11401fe94f960249b3c63a488c63ba73091c1e4a', + 'type' => 'library', + 'install_path' => __DIR__ . '/../symfony/var-exporter', 'aliases' => array(), 'dev_requirement' => false, ), diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php index 6d3407db..580fa960 100644 --- a/vendor/composer/platform_check.php +++ b/vendor/composer/platform_check.php @@ -4,8 +4,8 @@ $issues = array(); -if (!(PHP_VERSION_ID >= 70100)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 7.1.0". You are running ' . PHP_VERSION . '.'; +if (!(PHP_VERSION_ID >= 70400)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 7.4.0". You are running ' . PHP_VERSION . '.'; } if ($issues) { diff --git a/vendor/monolog/monolog/CHANGELOG.md b/vendor/monolog/monolog/CHANGELOG.md index a92155ee..8a8c6512 100644 --- a/vendor/monolog/monolog/CHANGELOG.md +++ b/vendor/monolog/monolog/CHANGELOG.md @@ -1,11 +1,202 @@ -### 1.27.1 (2022-06-09) +### 2.9.1 (2023-02-06) - * Fixed MandrillHandler support for SwiftMailer 6 (#1676) - * Fixed StreamHandler chunk size (backport from #1552) + * Fixed Logger not being serializable anymore (#1792) -### 1.27.0 (2022-03-13) +### 2.9.0 (2023-02-05) - * Added $maxDepth / setMaxDepth to NormalizerFormatter / JsonFormatter to configure the maximum depth if the default of 9 does not work for you (#1633) + * Deprecated FlowdockHandler & Formatter as the flowdock service was shutdown (#1748) + * Added support for enum context values in PsrLogMessageProcessor (#1773) + * Added graylog2/gelf-php 2.x support (#1747) + * Improved `BrowserConsoleHandler` logging to use more appropriate methods than just console.log in the browser (#1739) + * Fixed `WhatFailureGroupHandler` not catching errors happening inside `close()` (#1791) + * Fixed datetime field in `GoogleCloudLoggingFormatter` (#1758) + * Fixed infinite loop detection within Fibers (#1753) + * Fixed `AmqpHandler->setExtraAttributes` not working with buffering handler wrappers (#1781) + +### 2.8.0 (2022-07-24) + + * Deprecated `CubeHandler` and `PHPConsoleHandler` as both projects are abandoned and those should not be used anymore (#1734) + * Added RFC 5424 level (`7` to `0`) support to `Logger::log` and `Logger::addRecord` to increase interoperability (#1723) + * Added support for `__toString` for objects which are not json serializable in `JsonFormatter` (#1733) + * Added `GoogleCloudLoggingFormatter` (#1719) + * Added support for Predis 2.x (#1732) + * Added `AmqpHandler->setExtraAttributes` to allow configuring attributes when using an AMQPExchange (#1724) + * Fixed serialization/unserialization of handlers to make sure private properties are included (#1727) + * Fixed allowInlineLineBreaks in LineFormatter causing issues with windows paths containing `\n` or `\r` sequences (#1720) + * Fixed max normalization depth not being taken into account when formatting exceptions with a deep chain of previous exceptions (#1726) + * Fixed PHP 8.2 deprecation warnings (#1722) + * Fixed rare race condition or filesystem issue where StreamHandler is unable to create the directory the log should go into yet it exists already (#1678) + +### 2.7.0 (2022-06-09) + + * Added `$datetime` parameter to `Logger::addRecord` as low level API to allow logging into the past or future (#1682) + * Added `Logger::useLoggingLoopDetection` to allow disabling cyclic logging detection in concurrent frameworks (#1681) + * Fixed handling of fatal errors if callPrevious is disabled in ErrorHandler (#1670) + * Marked the reusable `Monolog\Test\TestCase` class as `@internal` to make sure PHPStorm does not show it above PHPUnit, you may still use it to test your own handlers/etc though (#1677) + * Fixed RotatingFileHandler issue when the date format contained slashes (#1671) + +### 2.6.0 (2022-05-10) + + * Deprecated `SwiftMailerHandler`, use `SymfonyMailerHandler` instead + * Added `SymfonyMailerHandler` (#1663) + * Added ElasticSearch 8.x support to the ElasticsearchHandler (#1662) + * Added a way to filter/modify stack traces in LineFormatter (#1665) + * Fixed UdpSocket not being able to reopen/reconnect after close() + * Fixed infinite loops if a Handler is triggering logging while handling log records + +### 2.5.0 (2022-04-08) + + * Added `callType` to IntrospectionProcessor (#1612) + * Fixed AsMonologProcessor syntax to be compatible with PHP 7.2 (#1651) + +### 2.4.0 (2022-03-14) + + * Added [`Monolog\LogRecord`](src/Monolog/LogRecord.php) interface that can be used to type-hint records like `array|\Monolog\LogRecord $record` to be forward compatible with the upcoming Monolog 3 changes + * Added `includeStacktraces` constructor params to LineFormatter & JsonFormatter (#1603) + * Added `persistent`, `timeout`, `writingTimeout`, `connectionTimeout`, `chunkSize` constructor params to SocketHandler and derivatives (#1600) + * Added `AsMonologProcessor` PHP attribute which can help autowiring / autoconfiguration of processors if frameworks / integrations decide to make use of it. This is useless when used purely with Monolog (#1637) + * Added support for keeping native BSON types as is in MongoDBFormatter (#1620) + * Added support for a `user_agent` key in WebProcessor, disabled by default but you can use it by configuring the $extraFields you want (#1613) + * Added support for username/userIcon in SlackWebhookHandler (#1617) + * Added extension points to BrowserConsoleHandler (#1593) + * Added record message/context/extra info to exceptions thrown when a StreamHandler cannot open its stream to avoid completely losing the data logged (#1630) + * Fixed error handler signature to accept a null $context which happens with internal PHP errors (#1614) + * Fixed a few setter methods not returning `self` (#1609) + * Fixed handling of records going over the max Telegram message length (#1616) + +### 2.3.5 (2021-10-01) + + * Fixed regression in StreamHandler since 2.3.3 on systems with the memory_limit set to >=20GB (#1592) + +### 2.3.4 (2021-09-15) + + * Fixed support for psr/log 3.x (#1589) + +### 2.3.3 (2021-09-14) + + * Fixed memory usage when using StreamHandler and calling stream_get_contents on the resource you passed to it (#1578, #1577) + * Fixed support for psr/log 2.x (#1587) + * Fixed some type annotations + +### 2.3.2 (2021-07-23) + + * Fixed compatibility with PHP 7.2 - 7.4 when experiencing PCRE errors (#1568) + +### 2.3.1 (2021-07-14) + + * Fixed Utils::getClass handling of anonymous classes not being fully compatible with PHP 8 (#1563) + * Fixed some `@inheritDoc` annotations having the wrong case + +### 2.3.0 (2021-07-05) + + * Added a ton of PHPStan type annotations as well as type aliases on Monolog\Logger for Record, Level and LevelName that you can import (#1557) + * Added ability to customize date format when using JsonFormatter (#1561) + * Fixed FilterHandler not calling reset on its internal handler when reset() is called on it (#1531) + * Fixed SyslogUdpHandler not setting the timezone correctly on DateTimeImmutable instances (#1540) + * Fixed StreamHandler thread safety - chunk size set to 2GB now to avoid interlacing when doing concurrent writes (#1553) + +### 2.2.0 (2020-12-14) + + * Added JSON_PARTIAL_OUTPUT_ON_ERROR to default json encoding flags, to avoid dropping entire context data or even records due to an invalid subset of it somewhere + * Added setDateFormat to NormalizerFormatter (and Line/Json formatters by extension) to allow changing this after object creation + * Added RedisPubSubHandler to log records to a Redis channel using PUBLISH + * Added support for Elastica 7, and deprecated the $type argument of ElasticaFormatter which is not in use anymore as of Elastica 7 + * Added support for millisecond write timeouts in SocketHandler, you can now pass floats to setWritingTimeout, e.g. 0.2 is 200ms + * Added support for unix sockets in SyslogUdpHandler (set $port to 0 to make the $host a unix socket) + * Added handleBatch support for TelegramBotHandler + * Added RFC5424e extended date format including milliseconds to SyslogUdpHandler + * Added support for configuring handlers with numeric level values in strings (coming from e.g. env vars) + * Fixed Wildfire/FirePHP/ChromePHP handling of unicode characters + * Fixed PHP 8 issues in SyslogUdpHandler + * Fixed internal type error when mbstring is missing + +### 2.1.1 (2020-07-23) + + * Fixed removing of json encoding options + * Fixed type hint of $level not accepting strings in SendGridHandler and OverflowHandler + * Fixed SwiftMailerHandler not accepting email templates with an empty subject + * Fixed array access on null in RavenHandler + * Fixed unique_id in WebProcessor not being disableable + +### 2.1.0 (2020-05-22) + + * Added `JSON_INVALID_UTF8_SUBSTITUTE` to default json flags, so that invalid UTF8 characters now get converted to [�](https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character) instead of being converted from ISO-8859-15 to UTF8 as it was before, which was hardly a comprehensive solution + * Added `$ignoreEmptyContextAndExtra` option to JsonFormatter to skip empty context/extra entirely from the output + * Added `$parseMode`, `$disableWebPagePreview` and `$disableNotification` options to TelegramBotHandler + * Added tentative support for PHP 8 + * NormalizerFormatter::addJsonEncodeOption and removeJsonEncodeOption are now public to allow modifying default json flags + * Fixed GitProcessor type error when there is no git repo present + * Fixed normalization of SoapFault objects containing deeply nested objects as "detail" + * Fixed support for relative paths in RotatingFileHandler + +### 2.0.2 (2019-12-20) + + * Fixed ElasticsearchHandler swallowing exceptions details when failing to index log records + * Fixed normalization of SoapFault objects containing non-strings as "detail" in LineFormatter + * Fixed formatting of resources in JsonFormatter + * Fixed RedisHandler failing to use MULTI properly when passed a proxied Redis instance (e.g. in Symfony with lazy services) + * Fixed FilterHandler triggering a notice when handleBatch was filtering all records passed to it + * Fixed Turkish locale messing up the conversion of level names to their constant values + +### 2.0.1 (2019-11-13) + + * Fixed normalization of Traversables to avoid traversing them as not all of them are rewindable + * Fixed setFormatter/getFormatter to forward to the nested handler in FilterHandler, FingersCrossedHandler, BufferHandler, OverflowHandler and SamplingHandler + * Fixed BrowserConsoleHandler formatting when using multiple styles + * Fixed normalization of exception codes to be always integers even for PDOException which have them as numeric strings + * Fixed normalization of SoapFault objects containing non-strings as "detail" + * Fixed json encoding across all handlers to always attempt recovery of non-UTF-8 strings instead of failing the whole encoding + * Fixed ChromePHPHandler to avoid sending more data than latest Chrome versions allow in headers (4KB down from 256KB). + * Fixed type error in BrowserConsoleHandler when the context array of log records was not associative. + +### 2.0.0 (2019-08-30) + + * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release + * BC Break: Logger methods log/debug/info/notice/warning/error/critical/alert/emergency now have explicit void return types + * Added FallbackGroupHandler which works like the WhatFailureGroupHandler but stops dispatching log records as soon as one handler accepted it + * Fixed support for UTF-8 when cutting strings to avoid cutting a multibyte-character in half + * Fixed normalizers handling of exception backtraces to avoid serializing arguments in some cases + * Fixed date timezone handling in SyslogUdpHandler + +### 2.0.0-beta2 (2019-07-06) + + * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release + * BC Break: PHP 7.2 is now the minimum required PHP version. + * BC Break: Removed SlackbotHandler, RavenHandler and HipChatHandler, see [UPGRADE.md](UPGRADE.md) for details + * Added OverflowHandler which will only flush log records to its nested handler when reaching a certain amount of logs (i.e. only pass through when things go really bad) + * Added TelegramBotHandler to log records to a [Telegram](https://core.telegram.org/bots/api) bot account + * Added support for JsonSerializable when normalizing exceptions + * Added support for RFC3164 (outdated BSD syslog protocol) to SyslogUdpHandler + * Added SoapFault details to formatted exceptions + * Fixed DeduplicationHandler silently failing to start when file could not be opened + * Fixed issue in GroupHandler and WhatFailureGroupHandler where setting multiple processors would duplicate records + * Fixed GelfFormatter losing some data when one attachment was too long + * Fixed issue in SignalHandler restarting syscalls functionality + * Improved performance of LogglyHandler when sending multiple logs in a single request + +### 2.0.0-beta1 (2018-12-08) + + * BC Break: This is a major release, see [UPGRADE.md](UPGRADE.md) for details if you are coming from a 1.x release + * BC Break: PHP 7.1 is now the minimum required PHP version. + * BC Break: Quite a few interface changes, only relevant if you implemented your own handlers/processors/formatters + * BC Break: Removed non-PSR-3 methods to add records, all the `add*` (e.g. `addWarning`) methods as well as `emerg`, `crit`, `err` and `warn` + * BC Break: The record timezone is now set per Logger instance and not statically anymore + * BC Break: There is no more default handler configured on empty Logger instances + * BC Break: ElasticSearchHandler renamed to ElasticaHandler + * BC Break: Various handler-specific breaks, see [UPGRADE.md](UPGRADE.md) for details + * Added scalar type hints and return hints in all the places it was possible. Switched strict_types on for more reliability. + * Added DateTimeImmutable support, all record datetime are now immutable, and will toString/json serialize with the correct date format, including microseconds (unless disabled) + * Added timezone and microseconds to the default date format + * Added SendGridHandler to use the SendGrid API to send emails + * Added LogmaticHandler to use the Logmatic.io API to store log records + * Added SqsHandler to send log records to an AWS SQS queue + * Added ElasticsearchHandler to send records via the official ES library. Elastica users should now use ElasticaHandler instead of ElasticSearchHandler + * Added NoopHandler which is similar to the NullHandle but does not prevent the bubbling of log records to handlers further down the configuration, useful for temporarily disabling a handler in configuration files + * Added ProcessHandler to write log output to the STDIN of a given process + * Added HostnameProcessor that adds the machine's hostname to log records + * Added a `$dateFormat` option to the PsrLogMessageProcessor which lets you format DateTime instances nicely + * Added support for the PHP 7.x `mongodb` extension in the MongoDBHandler + * Fixed many minor issues in various handlers, and probably added a few regressions too ### 1.26.1 (2021-05-28) @@ -67,7 +258,7 @@ * Added a way to log signals being received using Monolog\SignalHandler * Added ability to customize error handling at the Logger level using Logger::setExceptionHandler * Added InsightOpsHandler to migrate users of the LogEntriesHandler - * Added protection to NormalizerHandler against circular and very deep structures, it now stops normalizing at a depth of 9 + * Added protection to NormalizerFormatter against circular and very deep structures, it now stops normalizing at a depth of 9 * Added capture of stack traces to ErrorHandler when logging PHP errors * Added RavenHandler support for a `contexts` context or extra key to forward that to Sentry's contexts * Added forwarding of context info to FluentdFormatter @@ -107,7 +298,7 @@ * Added SlackbotHandler and SlackWebhookHandler to set up Slack integration more easily * Added MercurialProcessor to add mercurial revision and branch names to log records * Added support for AWS SDK v3 in DynamoDbHandler - * Fixed fatal errors occuring when normalizing generators that have been fully consumed + * Fixed fatal errors occurring when normalizing generators that have been fully consumed * Fixed RollbarHandler to include a level (rollbar level), monolog_level (original name), channel and datetime (unix) * Fixed RollbarHandler not flushing records automatically, calling close() explicitly is not necessary anymore * Fixed SyslogUdpHandler to avoid sending empty frames @@ -117,7 +308,7 @@ * Break: Reverted the addition of $context when the ErrorHandler handles regular php errors from 1.20.0 as it was causing issues * Added support for more formats in RotatingFileHandler::setFilenameFormat as long as they have Y, m and d in order - * Added ability to format the main line of text the SlackHandler sends by explictly setting a formatter on the handler + * Added ability to format the main line of text the SlackHandler sends by explicitly setting a formatter on the handler * Added information about SoapFault instances in NormalizerFormatter * Added $handleOnlyReportedErrors option on ErrorHandler::registerErrorHandler (default true) to allow logging of all errors no matter the error_reporting level @@ -239,7 +430,7 @@ * Added $useShortAttachment to SlackHandler to minify attachment size and $includeExtra to append extra data * Added $host to HipChatHandler for users of private instances * Added $transactionName to NewRelicHandler and support for a transaction_name context value - * Fixed MandrillHandler to avoid outputing API call responses + * Fixed MandrillHandler to avoid outputting API call responses * Fixed some non-standard behaviors in SyslogUdpHandler ### 1.11.0 (2014-09-30) diff --git a/vendor/monolog/monolog/LICENSE b/vendor/monolog/monolog/LICENSE index 16473219..aa2a0426 100644 --- a/vendor/monolog/monolog/LICENSE +++ b/vendor/monolog/monolog/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2016 Jordi Boggiano +Copyright (c) 2011-2020 Jordi Boggiano Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/monolog/monolog/README.md b/vendor/monolog/monolog/README.md index a578eb22..bfcae0c0 100644 --- a/vendor/monolog/monolog/README.md +++ b/vendor/monolog/monolog/README.md @@ -1,4 +1,4 @@ -# Monolog - Logging for PHP [![Build Status](https://img.shields.io/travis/Seldaek/monolog.svg)](https://travis-ci.org/Seldaek/monolog) +# Monolog - Logging for PHP [![Continuous Integration](https://github.com/Seldaek/monolog/workflows/Continuous%20Integration/badge.svg?branch=main)](https://github.com/Seldaek/monolog/actions) [![Total Downloads](https://img.shields.io/packagist/dt/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog) [![Latest Stable Version](https://img.shields.io/packagist/v/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog) @@ -36,16 +36,23 @@ $log = new Logger('name'); $log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING)); // add records to the log -$log->addWarning('Foo'); -$log->addError('Bar'); +$log->warning('Foo'); +$log->error('Bar'); ``` ## Documentation - [Usage Instructions](doc/01-usage.md) - [Handlers, Formatters and Processors](doc/02-handlers-formatters-processors.md) -- [Utility classes](doc/03-utilities.md) +- [Utility Classes](doc/03-utilities.md) - [Extending Monolog](doc/04-extending.md) +- [Log Record Structure](doc/message-structure.md) + +## Support Monolog Financially + +Get supported Monolog and help fund the project with the [Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-monolog-monolog?utm_source=packagist-monolog-monolog&utm_medium=referral&utm_campaign=enterprise) or via [GitHub sponsorship](https://github.com/sponsors/Seldaek). + +Tidelift delivers commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. ## Third Party Packages @@ -57,7 +64,11 @@ can also add your own there if you publish one. ### Requirements -- Monolog works with PHP 5.3 or above, and is also tested to work with HHVM. +- Monolog `^2.0` works with PHP 7.2 or above, use Monolog `^1.25` for PHP 5.3+ support. + +### Support + +Monolog 1.x support is somewhat limited at this point and only important fixes will be done. You should migrate to Monolog 2 where possible to benefit from all the latest features and fixes. ### Submitting bugs and feature requests @@ -67,26 +78,33 @@ Bugs and feature request are tracked on [GitHub](https://github.com/Seldaek/mono - Frameworks and libraries using [PSR-3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) can be used very easily with Monolog since it implements the interface. -- [Symfony2](http://symfony.com) comes out of the box with Monolog. -- [Silex](http://silex.sensiolabs.org/) comes out of the box with Monolog. -- [Laravel 4 & 5](http://laravel.com/) come out of the box with Monolog. +- [Symfony](http://symfony.com) comes out of the box with Monolog. +- [Laravel](http://laravel.com/) comes out of the box with Monolog. - [Lumen](http://lumen.laravel.com/) comes out of the box with Monolog. -- [PPI](http://www.ppi.io/) comes out of the box with Monolog. +- [PPI](https://github.com/ppi/framework) comes out of the box with Monolog. - [CakePHP](http://cakephp.org/) is usable with Monolog via the [cakephp-monolog](https://github.com/jadb/cakephp-monolog) plugin. - [Slim](http://www.slimframework.com/) is usable with Monolog via the [Slim-Monolog](https://github.com/Flynsarmy/Slim-Monolog) log writer. - [XOOPS 2.6](http://xoops.org/) comes out of the box with Monolog. - [Aura.Web_Project](https://github.com/auraphp/Aura.Web_Project) comes out of the box with Monolog. -- [Nette Framework](http://nette.org/en/) can be used with Monolog via [Kdyby/Monolog](https://github.com/Kdyby/Monolog) extension. +- [Nette Framework](http://nette.org/en/) is usable with Monolog via the [contributte/monolog](https://github.com/contributte/monolog) or [orisai/nette-monolog](https://github.com/orisai/nette-monolog) extensions. - [Proton Micro Framework](https://github.com/alexbilbie/Proton) comes out of the box with Monolog. +- [FuelPHP](http://fuelphp.com/) comes out of the box with Monolog. +- [Equip Framework](https://github.com/equip/framework) comes out of the box with Monolog. +- [Yii 2](http://www.yiiframework.com/) is usable with Monolog via the [yii2-monolog](https://github.com/merorafael/yii2-monolog) or [yii2-psr-log-target](https://github.com/samdark/yii2-psr-log-target) plugins. +- [Hawkbit Micro Framework](https://github.com/HawkBitPhp/hawkbit) comes out of the box with Monolog. +- [SilverStripe 4](https://www.silverstripe.org/) comes out of the box with Monolog. +- [Drupal](https://www.drupal.org/) is usable with Monolog via the [monolog](https://www.drupal.org/project/monolog) module. +- [Aimeos ecommerce framework](https://aimeos.org/) is usable with Monolog via the [ai-monolog](https://github.com/aimeos/ai-monolog) extension. +- [Magento](https://magento.com/) comes out of the box with Monolog. ### Author Jordi Boggiano - -
-See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) which participated in this project. +See also the list of [contributors](https://github.com/Seldaek/monolog/contributors) who participated in this project. ### License -Monolog is licensed under the MIT License - see the `LICENSE` file for details +Monolog is licensed under the MIT License - see the [LICENSE](LICENSE) file for details ### Acknowledgements diff --git a/vendor/monolog/monolog/UPGRADE.md b/vendor/monolog/monolog/UPGRADE.md new file mode 100644 index 00000000..84e15e6b --- /dev/null +++ b/vendor/monolog/monolog/UPGRADE.md @@ -0,0 +1,72 @@ +### 2.0.0 + +- `Monolog\Logger::API` can be used to distinguish between a Monolog `1` and `2` + install of Monolog when writing integration code. + +- Removed non-PSR-3 methods to add records, all the `add*` (e.g. `addWarning`) + methods as well as `emerg`, `crit`, `err` and `warn`. + +- DateTime are now formatted with a timezone and microseconds (unless disabled). + Various formatters and log output might be affected, which may mess with log parsing + in some cases. + +- The `datetime` in every record array is now a DateTimeImmutable, not that you + should have been modifying these anyway. + +- The timezone is now set per Logger instance and not statically, either + via ->setTimezone or passed in the constructor. Calls to Logger::setTimezone + should be converted. + +- `HandlerInterface` has been split off and two new interfaces now exist for + more granular controls: `ProcessableHandlerInterface` and + `FormattableHandlerInterface`. Handlers not extending `AbstractHandler` + should make sure to implement the relevant interfaces. + +- `HandlerInterface` now requires the `close` method to be implemented. This + only impacts you if you implement the interface yourself, but you can extend + the new `Monolog\Handler\Handler` base class too. + +- There is no more default handler configured on empty Logger instances, if + you were relying on that you will not get any output anymore, make sure to + configure the handler you need. + +#### LogglyFormatter + +- The records' `datetime` is not sent anymore. Only `timestamp` is sent to Loggly. + +#### AmqpHandler + +- Log levels are not shortened to 4 characters anymore. e.g. a warning record + will be sent using the `warning.channel` routing key instead of `warn.channel` + as in 1.x. +- The exchange name does not default to 'log' anymore, and it is completely ignored + now for the AMQP extension users. Only PHPAmqpLib uses it if provided. + +#### RotatingFileHandler + +- The file name format must now contain `{date}` and the date format must be set + to one of the predefined FILE_PER_* constants to avoid issues with file rotation. + See `setFilenameFormat`. + +#### LogstashFormatter + +- Removed Logstash V0 support +- Context/extra prefix has been removed in favor of letting users configure the exact key being sent +- Context/extra data are now sent as an object instead of single keys + +#### HipChatHandler + +- Removed deprecated HipChat handler, migrate to Slack and use SlackWebhookHandler or SlackHandler instead + +#### SlackbotHandler + +- Removed deprecated SlackbotHandler handler, use SlackWebhookHandler or SlackHandler instead + +#### RavenHandler + +- Removed deprecated RavenHandler handler, use sentry/sentry 2.x and their Sentry\Monolog\Handler instead + +#### ElasticSearchHandler + +- As support for the official Elasticsearch library was added, the former ElasticSearchHandler has been + renamed to ElasticaHandler and the new one added as ElasticsearchHandler. diff --git a/vendor/monolog/monolog/composer.json b/vendor/monolog/monolog/composer.json index aecc40f3..b9437d6d 100644 --- a/vendor/monolog/monolog/composer.json +++ b/vendor/monolog/monolog/composer.json @@ -2,44 +2,55 @@ "name": "monolog/monolog", "description": "Sends your logs to files, sockets, inboxes, databases and various web services", "keywords": ["log", "logging", "psr-3"], - "homepage": "http://github.com/Seldaek/monolog", + "homepage": "https://github.com/Seldaek/monolog", "type": "library", "license": "MIT", "authors": [ { "name": "Jordi Boggiano", "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "homepage": "https://seld.be" } ], "require": { - "php": ">=5.3.0", - "psr/log": "~1.0" + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { - "phpunit/phpunit": "~4.5", - "graylog2/gelf-php": "~1.0", - "sentry/sentry": "^0.13", - "ruflin/elastica": ">=0.90 <3.0", - "doctrine/couchdb": "~1.0@dev", + "ext-json": "*", "aws/aws-sdk-php": "^2.4.9 || ^3.0", - "php-amqplib/php-amqplib": "~2.4", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", "swiftmailer/swiftmailer": "^5.3|^6.0", - "php-console/php-console": "^3.1.3", - "phpstan/phpstan": "^0.12.59" + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" }, "suggest": { "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", - "sentry/sentry": "Allow sending log messages to a Sentry server", "doctrine/couchdb": "Allow sending log messages to a CouchDB server", "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", - "ext-mongo": "Allow sending log messages to a MongoDB server", - "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "php-console/php-console": "Allow sending log messages to Google Chrome" + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-openssl": "Required to send log messages using SSL" }, "autoload": { "psr-4": {"Monolog\\": "src/Monolog"} @@ -48,13 +59,23 @@ "psr-4": {"Monolog\\": "tests/Monolog"} }, "provide": { - "psr/log-implementation": "1.0.0" + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + }, + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } }, "scripts": { - "test": "vendor/bin/phpunit", - "phpstan": "vendor/bin/phpstan analyse" + "test": "@php vendor/bin/phpunit", + "phpstan": "@php vendor/bin/phpstan analyse" }, "config": { - "lock": false + "lock": false, + "sort-packages": true, + "platform-check": false, + "allow-plugins": { + "composer/package-versions-deprecated": true + } } } diff --git a/vendor/monolog/monolog/phpstan.neon.dist b/vendor/monolog/monolog/phpstan.neon.dist deleted file mode 100644 index 1fe45df7..00000000 --- a/vendor/monolog/monolog/phpstan.neon.dist +++ /dev/null @@ -1,16 +0,0 @@ -parameters: - level: 3 - - paths: - - src/ -# - tests/ - - - ignoreErrors: - - '#zend_monitor_|ZEND_MONITOR_#' - - '#RollbarNotifier#' - - '#Predis\\Client#' - - '#^Cannot call method ltrim\(\) on int\|false.$#' - - '#^Access to an undefined property Raven_Client::\$context.$#' - - '#MongoDB\\(Client|Collection)#' - - '#Gelf\\IMessagePublisher#' diff --git a/vendor/monolog/monolog/src/Monolog/Attribute/AsMonologProcessor.php b/vendor/monolog/monolog/src/Monolog/Attribute/AsMonologProcessor.php new file mode 100644 index 00000000..188bbb0d --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Attribute/AsMonologProcessor.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Attribute; + +/** + * A reusable attribute to help configure a class or a method as a processor. + * + * Using it offers no guarantee: it needs to be leveraged by a Monolog third-party consumer. + * + * Using it with the Monolog library only has no effect at all: processors should still be turned into a callable if + * needed and manually pushed to the loggers and to the processable handlers. + */ +#[\Attribute(\Attribute::TARGET_CLASS | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] +class AsMonologProcessor +{ + /** @var string|null */ + public $channel = null; + /** @var string|null */ + public $handler = null; + /** @var string|null */ + public $method = null; + + /** + * @param string|null $channel The logging channel the processor should be pushed to. + * @param string|null $handler The handler the processor should be pushed to. + * @param string|null $method The method that processes the records (if the attribute is used at the class level). + */ + public function __construct( + ?string $channel = null, + ?string $handler = null, + ?string $method = null + ) { + $this->channel = $channel; + $this->handler = $handler; + $this->method = $method; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/DateTimeImmutable.php b/vendor/monolog/monolog/src/Monolog/DateTimeImmutable.php new file mode 100644 index 00000000..6a1ba9b2 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/DateTimeImmutable.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use DateTimeZone; + +/** + * Overrides default json encoding of date time objects + * + * @author Menno Holtkamp + * @author Jordi Boggiano + */ +class DateTimeImmutable extends \DateTimeImmutable implements \JsonSerializable +{ + /** + * @var bool + */ + private $useMicroseconds; + + public function __construct(bool $useMicroseconds, ?DateTimeZone $timezone = null) + { + $this->useMicroseconds = $useMicroseconds; + + parent::__construct('now', $timezone); + } + + public function jsonSerialize(): string + { + if ($this->useMicroseconds) { + return $this->format('Y-m-d\TH:i:s.uP'); + } + + return $this->format('Y-m-d\TH:i:sP'); + } + + public function __toString(): string + { + return $this->jsonSerialize(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/ErrorHandler.php b/vendor/monolog/monolog/src/Monolog/ErrorHandler.php index 5121c2cd..576f1713 100644 --- a/vendor/monolog/monolog/src/Monolog/ErrorHandler.php +++ b/vendor/monolog/monolog/src/Monolog/ErrorHandler.php @@ -1,4 +1,4 @@ - an array of class name to LogLevel::* constant mapping */ + private $uncaughtExceptionLevelMap = []; - private $previousErrorHandler; - private $errorLevelMap; - private $handleOnlyReportedErrors; + /** @var callable|true|null */ + private $previousErrorHandler = null; + /** @var array an array of E_* constant to LogLevel::* constant mapping */ + private $errorLevelMap = []; + /** @var bool */ + private $handleOnlyReportedErrors = true; - private $hasFatalErrorHandler; - private $fatalLevel; - private $reservedMemory; - private $lastFatalTrace; - private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); + /** @var bool */ + private $hasFatalErrorHandler = false; + /** @var LogLevel::* */ + private $fatalLevel = LogLevel::ALERT; + /** @var ?string */ + private $reservedMemory = null; + /** @var ?array{type: int, message: string, file: string, line: int, trace: mixed} */ + private $lastFatalData = null; + /** @var int[] */ + private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR]; public function __construct(LoggerInterface $logger) { @@ -51,24 +61,21 @@ public function __construct(LoggerInterface $logger) * * By default it will handle errors, exceptions and fatal errors * - * @param LoggerInterface $logger - * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling - * @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling - * @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling + * @param LoggerInterface $logger + * @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling + * @param array|false $exceptionLevelMap an array of class name to LogLevel::* constant mapping, or false to disable exception handling + * @param LogLevel::*|null|false $fatalLevel a LogLevel::* constant, null to use the default LogLevel::ALERT or false to disable fatal error handling * @return ErrorHandler */ - public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null) + public static function register(LoggerInterface $logger, $errorLevelMap = [], $exceptionLevelMap = [], $fatalLevel = null): self { - //Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929 - class_exists('\\Psr\\Log\\LogLevel', true); - /** @phpstan-ignore-next-line */ $handler = new static($logger); if ($errorLevelMap !== false) { $handler->registerErrorHandler($errorLevelMap); } - if ($exceptionLevel !== false) { - $handler->registerExceptionHandler($exceptionLevel); + if ($exceptionLevelMap !== false) { + $handler->registerExceptionHandler($exceptionLevelMap); } if ($fatalLevel !== false) { $handler->registerFatalHandler($fatalLevel); @@ -77,38 +84,79 @@ class_exists('\\Psr\\Log\\LogLevel', true); return $handler; } - public function registerExceptionHandler($level = null, $callPrevious = true) + /** + * @param array $levelMap an array of class name to LogLevel::* constant mapping + * @return $this + */ + public function registerExceptionHandler(array $levelMap = [], bool $callPrevious = true): self { - $prev = set_exception_handler(array($this, 'handleException')); - $this->uncaughtExceptionLevel = $level; + $prev = set_exception_handler(function (\Throwable $e): void { + $this->handleException($e); + }); + $this->uncaughtExceptionLevelMap = $levelMap; + foreach ($this->defaultExceptionLevelMap() as $class => $level) { + if (!isset($this->uncaughtExceptionLevelMap[$class])) { + $this->uncaughtExceptionLevelMap[$class] = $level; + } + } if ($callPrevious && $prev) { $this->previousExceptionHandler = $prev; } + + return $this; } - public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1, $handleOnlyReportedErrors = true) + /** + * @param array $levelMap an array of E_* constant to LogLevel::* constant mapping + * @return $this + */ + public function registerErrorHandler(array $levelMap = [], bool $callPrevious = true, int $errorTypes = -1, bool $handleOnlyReportedErrors = true): self { - $prev = set_error_handler(array($this, 'handleError'), $errorTypes); + $prev = set_error_handler([$this, 'handleError'], $errorTypes); $this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap); if ($callPrevious) { $this->previousErrorHandler = $prev ?: true; + } else { + $this->previousErrorHandler = null; } $this->handleOnlyReportedErrors = $handleOnlyReportedErrors; + + return $this; } - public function registerFatalHandler($level = null, $reservedMemorySize = 20) + /** + * @param LogLevel::*|null $level a LogLevel::* constant, null to use the default LogLevel::ALERT + * @param int $reservedMemorySize Amount of KBs to reserve in memory so that it can be freed when handling fatal errors giving Monolog some room in memory to get its job done + */ + public function registerFatalHandler($level = null, int $reservedMemorySize = 20): self { - register_shutdown_function(array($this, 'handleFatalError')); + register_shutdown_function([$this, 'handleFatalError']); $this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize); - $this->fatalLevel = $level; + $this->fatalLevel = null === $level ? LogLevel::ALERT : $level; $this->hasFatalErrorHandler = true; + + return $this; } - protected function defaultErrorLevelMap() + /** + * @return array + */ + protected function defaultExceptionLevelMap(): array { - return array( + return [ + 'ParseError' => LogLevel::CRITICAL, + 'Throwable' => LogLevel::ERROR, + ]; + } + + /** + * @return array + */ + protected function defaultErrorLevelMap(): array + { + return [ E_ERROR => LogLevel::CRITICAL, E_WARNING => LogLevel::WARNING, E_PARSE => LogLevel::ALERT, @@ -124,22 +172,34 @@ protected function defaultErrorLevelMap() E_RECOVERABLE_ERROR => LogLevel::ERROR, E_DEPRECATED => LogLevel::NOTICE, E_USER_DEPRECATED => LogLevel::NOTICE, - ); + ]; } /** - * @private + * @phpstan-return never */ - public function handleException($e) + private function handleException(\Throwable $e): void { + $level = LogLevel::ERROR; + foreach ($this->uncaughtExceptionLevelMap as $class => $candidate) { + if ($e instanceof $class) { + $level = $candidate; + break; + } + } + $this->logger->log( - $this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel, + $level, sprintf('Uncaught Exception %s: "%s" at %s line %s', Utils::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()), - array('exception' => $e) + ['exception' => $e] ); if ($this->previousExceptionHandler) { - call_user_func($this->previousExceptionHandler, $e); + ($this->previousExceptionHandler)($e); + } + + if (!headers_sent() && !ini_get('display_errors')) { + http_response_code(500); } exit(255); @@ -147,59 +207,67 @@ public function handleException($e) /** * @private + * + * @param mixed[] $context */ - public function handleError($code, $message, $file = '', $line = 0, $context = array()) + public function handleError(int $code, string $message, string $file = '', int $line = 0, ?array $context = []): bool { if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) { - return; + return false; } // fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) { - $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL; - $this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line)); + $level = $this->errorLevelMap[$code] ?? LogLevel::CRITICAL; + $this->logger->log($level, self::codeToString($code).': '.$message, ['code' => $code, 'message' => $message, 'file' => $file, 'line' => $line]); } else { - // http://php.net/manual/en/function.debug-backtrace.php - // As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added. - // Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'. - $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); array_shift($trace); // Exclude handleError from trace - $this->lastFatalTrace = $trace; + $this->lastFatalData = ['type' => $code, 'message' => $message, 'file' => $file, 'line' => $line, 'trace' => $trace]; } if ($this->previousErrorHandler === true) { return false; } elseif ($this->previousErrorHandler) { - return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context); + return (bool) ($this->previousErrorHandler)($code, $message, $file, $line, $context); } + + return true; } /** * @private */ - public function handleFatalError() + public function handleFatalError(): void { - $this->reservedMemory = null; + $this->reservedMemory = ''; + + if (is_array($this->lastFatalData)) { + $lastError = $this->lastFatalData; + } else { + $lastError = error_get_last(); + } - $lastError = error_get_last(); if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) { + $trace = $lastError['trace'] ?? null; $this->logger->log( - $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel, + $this->fatalLevel, 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], - array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace) + ['code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $trace] ); if ($this->logger instanceof Logger) { foreach ($this->logger->getHandlers() as $handler) { - if ($handler instanceof AbstractHandler) { - $handler->close(); - } + $handler->close(); } } } } - private static function codeToString($code) + /** + * @param int $code + */ + private static function codeToString($code): string { switch ($code) { case E_ERROR: diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php index 9beda1e7..aa1884b9 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/ChromePHPFormatter.php @@ -1,4 +1,4 @@ - */ - private $logLevels = array( + private $logLevels = [ Logger::DEBUG => 'log', Logger::INFO => 'info', Logger::NOTICE => 'info', @@ -32,10 +34,10 @@ class ChromePHPFormatter implements FormatterInterface Logger::CRITICAL => 'error', Logger::ALERT => 'error', Logger::EMERGENCY => 'error', - ); + ]; /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record) { @@ -46,7 +48,7 @@ public function format(array $record) unset($record['extra']['file'], $record['extra']['line']); } - $message = array('message' => $record['message']); + $message = ['message' => $record['message']]; if ($record['context']) { $message['context'] = $record['context']; } @@ -57,17 +59,20 @@ public function format(array $record) $message = reset($message); } - return array( + return [ $record['channel'], $message, $backtrace, $this->logLevels[$record['level']], - ); + ]; } + /** + * {@inheritDoc} + */ public function formatBatch(array $records) { - $formatted = array(); + $formatted = []; foreach ($records as $record) { $formatted[] = $this->format($record); diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php index 4c556cf1..6c8a9ab5 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/ElasticaFormatter.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ class ElasticaFormatter extends NormalizerFormatter { @@ -26,15 +28,15 @@ class ElasticaFormatter extends NormalizerFormatter protected $index; /** - * @var string Elastic search document type + * @var ?string Elastic search document type */ protected $type; /** - * @param string $index Elastic Search index name - * @param string $type Elastic Search document type + * @param string $index Elastic Search index name + * @param ?string $type Elastic Search document type, deprecated as of Elastica 7 */ - public function __construct($index, $type) + public function __construct(string $index, ?string $type) { // elasticsearch requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\TH:i:s.uP'); @@ -44,7 +46,7 @@ public function __construct($index, $type) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function format(array $record) { @@ -53,35 +55,33 @@ public function format(array $record) return $this->getDocument($record); } - /** - * Getter index - * @return string - */ - public function getIndex() + public function getIndex(): string { return $this->index; } /** - * Getter type - * @return string + * @deprecated since Elastica 7 type has no effect */ - public function getType() + public function getType(): string { + /** @phpstan-ignore-next-line */ return $this->type; } /** * Convert a log message into an Elastica Document * - * @param array $record Log message - * @return Document + * @phpstan-param Record $record */ - protected function getDocument($record) + protected function getDocument(array $record): Document { $document = new Document(); $document->setData($record); - $document->setType($this->type); + if (method_exists($document, 'setType')) { + /** @phpstan-ignore-next-line */ + $document->setType($this->type); + } $document->setIndex($this->index); return $document; diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php new file mode 100644 index 00000000..b792b819 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/ElasticsearchFormatter.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; + +/** + * Format a log message into an Elasticsearch record + * + * @author Avtandil Kikabidze + */ +class ElasticsearchFormatter extends NormalizerFormatter +{ + /** + * @var string Elasticsearch index name + */ + protected $index; + + /** + * @var string Elasticsearch record type + */ + protected $type; + + /** + * @param string $index Elasticsearch index name + * @param string $type Elasticsearch record type + */ + public function __construct(string $index, string $type) + { + // Elasticsearch requires an ISO 8601 format date with optional millisecond precision. + parent::__construct(DateTimeInterface::ISO8601); + + $this->index = $index; + $this->type = $type; + } + + /** + * {@inheritDoc} + */ + public function format(array $record) + { + $record = parent::format($record); + + return $this->getDocument($record); + } + + /** + * Getter index + * + * @return string + */ + public function getIndex(): string + { + return $this->index; + } + + /** + * Getter type + * + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * Convert a log message into an Elasticsearch record + * + * @param mixed[] $record Log message + * @return mixed[] + */ + protected function getDocument(array $record): array + { + $record['_index'] = $this->index; + $record['_type'] = $this->type; + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php index 5094af3c..867ae586 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/FlowdockFormatter.php @@ -1,4 +1,4 @@ - + * @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4 */ class FlowdockFormatter implements FormatterInterface { @@ -28,26 +29,24 @@ class FlowdockFormatter implements FormatterInterface */ private $sourceEmail; - /** - * @param string $source - * @param string $sourceEmail - */ - public function __construct($source, $sourceEmail) + public function __construct(string $source, string $sourceEmail) { $this->source = $source; $this->sourceEmail = $sourceEmail; } /** - * {@inheritdoc} + * {@inheritDoc} + * + * @return mixed[] */ - public function format(array $record) + public function format(array $record): array { - $tags = array( + $tags = [ '#logs', '#' . strtolower($record['level_name']), '#' . $record['channel'], - ); + ]; foreach ($record['extra'] as $value) { $tags[] = '#' . $value; @@ -60,24 +59,26 @@ public function format(array $record) $this->getShortMessage($record['message']) ); - $record['flowdock'] = array( + $record['flowdock'] = [ 'source' => $this->source, 'from_address' => $this->sourceEmail, 'subject' => $subject, 'content' => $record['message'], 'tags' => $tags, 'project' => $this->source, - ); + ]; return $record; } /** - * {@inheritdoc} + * {@inheritDoc} + * + * @return mixed[][] */ - public function formatBatch(array $records) + public function formatBatch(array $records): array { - $formatted = array(); + $formatted = []; foreach ($records as $record) { $formatted[] = $this->format($record); @@ -86,12 +87,7 @@ public function formatBatch(array $records) return $formatted; } - /** - * @param string $message - * - * @return string - */ - public function getShortMessage($message) + public function getShortMessage(string $message): string { static $hasMbString; diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php index f8ead475..29b14d30 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/FluentdFormatter.php @@ -1,4 +1,4 @@ -levelTag = (bool) $levelTag; + $this->levelTag = $levelTag; } - public function isUsingLevelsInTag() + public function isUsingLevelsInTag(): bool { return $this->levelTag; } - public function format(array $record) + public function format(array $record): string { $tag = $record['channel']; if ($this->levelTag) { $tag .= '.' . strtolower($record['level_name']); } - $message = array( + $message = [ 'message' => $record['message'], 'context' => $record['context'], 'extra' => $record['extra'], - ); + ]; if (!$this->levelTag) { $message['level'] = $record['level']; $message['level_name'] = $record['level_name']; } - return Utils::jsonEncode(array($tag, $record['datetime']->getTimestamp(), $message)); + return Utils::jsonEncode([$tag, $record['datetime']->getTimestamp(), $message]); } - public function formatBatch(array $records) + public function formatBatch(array $records): string { $message = ''; foreach ($records as $record) { diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php b/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php index b5de7511..19617ec5 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/FormatterInterface.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ interface FormatterInterface { @@ -23,6 +25,8 @@ interface FormatterInterface * * @param array $record A record to format * @return mixed The formatted record + * + * @phpstan-param Record $record */ public function format(array $record); @@ -31,6 +35,8 @@ public function format(array $record); * * @param array $records A set of records to format * @return mixed The formatted set of records + * + * @phpstan-param Record[] $records */ public function formatBatch(array $records); } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php index 2c1b0e86..3b3e1e7f 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/GelfMessageFormatter.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger */ class GelfMessageFormatter extends NormalizerFormatter { - const DEFAULT_MAX_LENGTH = 32766; + protected const DEFAULT_MAX_LENGTH = 32766; /** * @var string the name of the system for the Gelf log message @@ -44,10 +47,19 @@ class GelfMessageFormatter extends NormalizerFormatter */ protected $maxLength; + /** + * @var int + */ + private $gelfVersion = 2; + /** * Translates Monolog log levels to Graylog2 log priorities. + * + * @var array + * + * @phpstan-var array */ - private $logLevels = array( + private $logLevels = [ Logger::DEBUG => 7, Logger::INFO => 6, Logger::NOTICE => 5, @@ -56,25 +68,41 @@ class GelfMessageFormatter extends NormalizerFormatter Logger::CRITICAL => 2, Logger::ALERT => 1, Logger::EMERGENCY => 0, - ); + ]; - public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $maxLength = null) + public function __construct(?string $systemName = null, ?string $extraPrefix = null, string $contextPrefix = 'ctxt_', ?int $maxLength = null) { + if (!class_exists(Message::class)) { + throw new \RuntimeException('Composer package graylog2/gelf-php is required to use Monolog\'s GelfMessageFormatter'); + } + parent::__construct('U.u'); - $this->systemName = $systemName ?: gethostname(); + $this->systemName = (is_null($systemName) || $systemName === '') ? (string) gethostname() : $systemName; - $this->extraPrefix = $extraPrefix; + $this->extraPrefix = is_null($extraPrefix) ? '' : $extraPrefix; $this->contextPrefix = $contextPrefix; $this->maxLength = is_null($maxLength) ? self::DEFAULT_MAX_LENGTH : $maxLength; + + if (method_exists(Message::class, 'setFacility')) { + $this->gelfVersion = 1; + } } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function format(array $record) + public function format(array $record): Message { - $record = parent::format($record); + $context = $extra = []; + if (isset($record['context'])) { + /** @var mixed[] $context */ + $context = parent::normalize($record['context']); + } + if (isset($record['extra'])) { + /** @var mixed[] $extra */ + $extra = parent::normalize($record['extra']); + } if (!isset($record['datetime'], $record['message'], $record['level'])) { throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given'); @@ -87,49 +115,58 @@ public function format(array $record) ->setHost($this->systemName) ->setLevel($this->logLevels[$record['level']]); - // message length + system name length + 200 for padding / metadata + // message length + system name length + 200 for padding / metadata $len = 200 + strlen((string) $record['message']) + strlen($this->systemName); if ($len > $this->maxLength) { - $message->setShortMessage(substr($record['message'], 0, $this->maxLength)); + $message->setShortMessage(Utils::substr($record['message'], 0, $this->maxLength)); } - if (isset($record['channel'])) { - $message->setFacility($record['channel']); - } - if (isset($record['extra']['line'])) { - $message->setLine($record['extra']['line']); - unset($record['extra']['line']); - } - if (isset($record['extra']['file'])) { - $message->setFile($record['extra']['file']); - unset($record['extra']['file']); + if ($this->gelfVersion === 1) { + if (isset($record['channel'])) { + $message->setFacility($record['channel']); + } + if (isset($extra['line'])) { + $message->setLine($extra['line']); + unset($extra['line']); + } + if (isset($extra['file'])) { + $message->setFile($extra['file']); + unset($extra['file']); + } + } else { + $message->setAdditional('facility', $record['channel']); } - foreach ($record['extra'] as $key => $val) { + foreach ($extra as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = strlen($this->extraPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->extraPrefix . $key, substr($val, 0, $this->maxLength)); - break; + $message->setAdditional($this->extraPrefix . $key, Utils::substr((string) $val, 0, $this->maxLength)); + + continue; } $message->setAdditional($this->extraPrefix . $key, $val); } - foreach ($record['context'] as $key => $val) { + foreach ($context as $key => $val) { $val = is_scalar($val) || null === $val ? $val : $this->toJson($val); $len = strlen($this->contextPrefix . $key . $val); if ($len > $this->maxLength) { - $message->setAdditional($this->contextPrefix . $key, substr($val, 0, $this->maxLength)); - break; + $message->setAdditional($this->contextPrefix . $key, Utils::substr((string) $val, 0, $this->maxLength)); + + continue; } $message->setAdditional($this->contextPrefix . $key, $val); } - if (null === $message->getFile() && isset($record['context']['exception']['file'])) { - if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) { - $message->setFile($matches[1]); - $message->setLine($matches[2]); + if ($this->gelfVersion === 1) { + /** @phpstan-ignore-next-line */ + if (null === $message->getFile() && isset($context['exception']['file'])) { + if (preg_match("/^(.+):([0-9]+)$/", $context['exception']['file'], $matches)) { + $message->setFile($matches[1]); + $message->setLine($matches[2]); + } } } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php new file mode 100644 index 00000000..ca52ebf4 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/GoogleCloudLoggingFormatter.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +use DateTimeInterface; +use Monolog\LogRecord; + +/** + * Encodes message information into JSON in a format compatible with Cloud logging. + * + * @see https://cloud.google.com/logging/docs/structured-logging + * @see https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry + * + * @author Luís Cobucci + */ +final class GoogleCloudLoggingFormatter extends JsonFormatter +{ + /** {@inheritdoc} **/ + public function format(array $record): string + { + // Re-key level for GCP logging + $record['severity'] = $record['level_name']; + $record['time'] = $record['datetime']->format(DateTimeInterface::RFC3339_EXTENDED); + + // Remove keys that are not used by GCP + unset($record['level'], $record['level_name'], $record['datetime']); + + return parent::format($record); + } +} + diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php index 9e8d2d01..10a4311c 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/HtmlFormatter.php @@ -1,4 +1,5 @@ - */ - protected $logLevels = array( - Logger::DEBUG => '#cccccc', - Logger::INFO => '#468847', - Logger::NOTICE => '#3a87ad', - Logger::WARNING => '#c09853', - Logger::ERROR => '#f0ad4e', - Logger::CRITICAL => '#FF7708', - Logger::ALERT => '#C12A19', + protected $logLevels = [ + Logger::DEBUG => '#CCCCCC', + Logger::INFO => '#28A745', + Logger::NOTICE => '#17A2B8', + Logger::WARNING => '#FFC107', + Logger::ERROR => '#FD7E14', + Logger::CRITICAL => '#DC3545', + Logger::ALERT => '#821722', Logger::EMERGENCY => '#000000', - ); + ]; /** - * @param string $dateFormat The format of the timestamp: one supported by DateTime::format + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format */ - public function __construct($dateFormat = null) + public function __construct(?string $dateFormat = null) { parent::__construct($dateFormat); } @@ -47,12 +50,11 @@ public function __construct($dateFormat = null) /** * Creates an HTML table row * - * @param string $th Row header content - * @param string $td Row standard cell content - * @param bool $escapeTd false if td content must not be html escaped - * @return string + * @param string $th Row header content + * @param string $td Row standard cell content + * @param bool $escapeTd false if td content must not be html escaped */ - protected function addRow($th, $td = ' ', $escapeTd = true) + protected function addRow(string $th, string $td = ' ', bool $escapeTd = true): string { $th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8'); if ($escapeTd) { @@ -69,7 +71,7 @@ protected function addRow($th, $td = ' ', $escapeTd = true) * @param int $level Error level * @return string */ - protected function addTitle($title, $level) + protected function addTitle(string $title, int $level): string { $title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8'); @@ -79,21 +81,20 @@ protected function addTitle($title, $level) /** * Formats a log record. * - * @param array $record A record to format - * @return mixed The formatted record + * @return string The formatted record */ - public function format(array $record) + public function format(array $record): string { $output = $this->addTitle($record['level_name'], $record['level']); $output .= ''; $output .= $this->addRow('Message', (string) $record['message']); - $output .= $this->addRow('Time', $record['datetime']->format($this->dateFormat)); + $output .= $this->addRow('Time', $this->formatDate($record['datetime'])); $output .= $this->addRow('Channel', $record['channel']); if ($record['context']) { $embeddedTable = '
'; foreach ($record['context'] as $key => $value) { - $embeddedTable .= $this->addRow($key, $this->convertToString($value)); + $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Context', $embeddedTable, false); @@ -101,7 +102,7 @@ public function format(array $record) if ($record['extra']) { $embeddedTable = ''; foreach ($record['extra'] as $key => $value) { - $embeddedTable .= $this->addRow($key, $this->convertToString($value)); + $embeddedTable .= $this->addRow((string) $key, $this->convertToString($value)); } $embeddedTable .= '
'; $output .= $this->addRow('Extra', $embeddedTable, false); @@ -113,10 +114,9 @@ public function format(array $record) /** * Formats a set of log records. * - * @param array $records A set of records to format - * @return mixed The formatted set of records + * @return string The formatted set of records */ - public function formatBatch(array $records) + public function formatBatch(array $records): string { $message = ''; foreach ($records as $record) { @@ -126,17 +126,17 @@ public function formatBatch(array $records) return $message; } - protected function convertToString($data) + /** + * @param mixed $data + */ + protected function convertToString($data): string { if (null === $data || is_scalar($data)) { return (string) $data; } $data = $this->normalize($data); - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return Utils::jsonEncode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, true); - } - return str_replace('\\/', '/', Utils::jsonEncode($data, null, true)); + return Utils::jsonEncode($data, JSON_PRETTY_PRINT | Utils::DEFAULT_JSON_FLAGS, true); } } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php index 4c5422d5..b737d82e 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/JsonFormatter.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ class JsonFormatter extends NormalizerFormatter { - const BATCH_MODE_JSON = 1; - const BATCH_MODE_NEWLINES = 2; + public const BATCH_MODE_JSON = 1; + public const BATCH_MODE_NEWLINES = 2; + /** @var self::BATCH_MODE_* */ protected $batchMode; + /** @var bool */ protected $appendNewline; - - /** - * @var bool - */ + /** @var bool */ + protected $ignoreEmptyContextAndExtra; + /** @var bool */ protected $includeStacktraces = false; /** - * @param int $batchMode - * @param bool $appendNewline - * @param int $maxDepth + * @param self::BATCH_MODE_* $batchMode */ - public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true, $maxDepth = 9) + public function __construct(int $batchMode = self::BATCH_MODE_JSON, bool $appendNewline = true, bool $ignoreEmptyContextAndExtra = false, bool $includeStacktraces = false) { - parent::__construct(null, $maxDepth); $this->batchMode = $batchMode; $this->appendNewline = $appendNewline; + $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; + $this->includeStacktraces = $includeStacktraces; + + parent::__construct(); } /** @@ -53,36 +55,49 @@ public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = * formatted as a JSON-encoded array. However, for * compatibility with some API endpoints, alternative styles * are available. - * - * @return int */ - public function getBatchMode() + public function getBatchMode(): int { return $this->batchMode; } /** * True if newlines are appended to every formatted record - * - * @return bool */ - public function isAppendingNewlines() + public function isAppendingNewlines(): bool { return $this->appendNewline; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function format(array $record) + public function format(array $record): string { - return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : ''); + $normalized = $this->normalize($record); + + if (isset($normalized['context']) && $normalized['context'] === []) { + if ($this->ignoreEmptyContextAndExtra) { + unset($normalized['context']); + } else { + $normalized['context'] = new \stdClass; + } + } + if (isset($normalized['extra']) && $normalized['extra'] === []) { + if ($this->ignoreEmptyContextAndExtra) { + unset($normalized['extra']); + } else { + $normalized['extra'] = new \stdClass; + } + } + + return $this->toJson($normalized, true) . ($this->appendNewline ? "\n" : ''); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function formatBatch(array $records) + public function formatBatch(array $records): string { switch ($this->batchMode) { case static::BATCH_MODE_NEWLINES: @@ -95,20 +110,21 @@ public function formatBatch(array $records) } /** - * @param bool $include + * @return self */ - public function includeStacktraces($include = true) + public function includeStacktraces(bool $include = true): self { $this->includeStacktraces = $include; + + return $this; } /** * Return a JSON-encoded array of records. * - * @param array $records - * @return string + * @phpstan-param Record[] $records */ - protected function formatBatchJson(array $records) + protected function formatBatchJson(array $records): string { return $this->toJson($this->normalize($records), true); } @@ -117,10 +133,9 @@ protected function formatBatchJson(array $records) * Use new lines to separate records instead of a * JSON-encoded array. * - * @param array $records - * @return string + * @phpstan-param Record[] $records */ - protected function formatBatchNewlines(array $records) + protected function formatBatchNewlines(array $records): string { $instance = $this; @@ -141,30 +156,47 @@ protected function formatBatchNewlines(array $records) * * @return mixed */ - protected function normalize($data, $depth = 0) + protected function normalize($data, int $depth = 0) { - if ($depth > $this->maxDepth) { - return 'Over '.$this->maxDepth.' levels deep, aborting normalization'; + if ($depth > $this->maxNormalizeDepth) { + return 'Over '.$this->maxNormalizeDepth.' levels deep, aborting normalization'; } if (is_array($data)) { - $normalized = array(); + $normalized = []; $count = 1; foreach ($data as $key => $value) { - if ($count++ > 1000) { - $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization'; + if ($count++ > $this->maxNormalizeItemCount) { + $normalized['...'] = 'Over '.$this->maxNormalizeItemCount.' items ('.count($data).' total), aborting normalization'; break; } - $normalized[$key] = $this->normalize($value, $depth+1); + $normalized[$key] = $this->normalize($value, $depth + 1); } return $normalized; } - if ($data instanceof Exception || $data instanceof Throwable) { - return $this->normalizeException($data); + if (is_object($data)) { + if ($data instanceof \DateTimeInterface) { + return $this->formatDate($data); + } + + if ($data instanceof Throwable) { + return $this->normalizeException($data, $depth); + } + + // if the object has specific json serializability we want to make sure we skip the __toString treatment below + if ($data instanceof \JsonSerializable) { + return $data; + } + + if (method_exists($data, '__toString')) { + return $data->__toString(); + } + + return $data; } if (is_resource($data)) { @@ -178,35 +210,13 @@ protected function normalize($data, $depth = 0) * Normalizes given exception with or without its own stack trace based on * `includeStacktraces` property. * - * @param Exception|Throwable $e - * - * @return array + * {@inheritDoc} */ - protected function normalizeException($e) + protected function normalizeException(Throwable $e, int $depth = 0): array { - // TODO 2.0 only check for Throwable - if (!$e instanceof Exception && !$e instanceof Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e)); - } - - $data = array( - 'class' => Utils::getClass($e), - 'message' => $e->getMessage(), - 'code' => (int) $e->getCode(), - 'file' => $e->getFile().':'.$e->getLine(), - ); - - if ($this->includeStacktraces) { - $trace = $e->getTrace(); - foreach ($trace as $frame) { - if (isset($frame['file'])) { - $data['trace'][] = $frame['file'].':'.$frame['line']; - } - } - } - - if ($previous = $e->getPrevious()) { - $data['previous'] = $this->normalizeException($previous); + $data = parent::normalizeException($e, $depth); + if (!$this->includeStacktraces) { + unset($data['trace']); } return $data; diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php index acc1fd38..b31b2971 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/LineFormatter.php @@ -1,4 +1,4 @@ -format = $format ?: static::SIMPLE_FORMAT; + $this->format = $format === null ? static::SIMPLE_FORMAT : $format; $this->allowInlineLineBreaks = $allowInlineLineBreaks; $this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra; + $this->includeStacktraces($includeStacktraces); parent::__construct($dateFormat); } - public function includeStacktraces($include = true) + public function includeStacktraces(bool $include = true, ?callable $parser = null): self { $this->includeStacktraces = $include; if ($this->includeStacktraces) { $this->allowInlineLineBreaks = true; + $this->stacktracesParser = $parser; } + + return $this; } - public function allowInlineLineBreaks($allow = true) + public function allowInlineLineBreaks(bool $allow = true): self { $this->allowInlineLineBreaks = $allow; + + return $this; } - public function ignoreEmptyContextAndExtra($ignore = true) + public function ignoreEmptyContextAndExtra(bool $ignore = true): self { $this->ignoreEmptyContextAndExtra = $ignore; + + return $this; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function format(array $record) + public function format(array $record): string { $vars = parent::format($record); @@ -78,7 +92,6 @@ public function format(array $record) } } - foreach ($vars['context'] as $var => $val) { if (false !== strpos($output, '%context.'.$var.'%')) { $output = str_replace('%context.'.$var.'%', $this->stringify($val), $output); @@ -107,12 +120,16 @@ public function format(array $record) // remove leftover %extra.xxx% and %context.xxx% if any if (false !== strpos($output, '%')) { $output = preg_replace('/%(?:extra|context)\..+?%/', '', $output); + if (null === $output) { + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to run preg_replace: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); + } } return $output; } - public function formatBatch(array $records) + public function formatBatch(array $records): string { $message = ''; foreach ($records as $record) { @@ -122,34 +139,37 @@ public function formatBatch(array $records) return $message; } - public function stringify($value) + /** + * @param mixed $value + */ + public function stringify($value): string { return $this->replaceNewlines($this->convertToString($value)); } - protected function normalizeException($e) + protected function normalizeException(\Throwable $e, int $depth = 0): string { - // TODO 2.0 only check for Throwable - if (!$e instanceof \Exception && !$e instanceof \Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e)); - } + $str = $this->formatException($e); - $previousText = ''; if ($previous = $e->getPrevious()) { do { - $previousText .= ', '.Utils::getClass($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine(); - } while ($previous = $previous->getPrevious()); - } + $depth++; + if ($depth > $this->maxNormalizeDepth) { + $str .= '\n[previous exception] Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; + break; + } - $str = '[object] ('.Utils::getClass($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')'; - if ($this->includeStacktraces) { - $str .= "\n[stacktrace]\n".$e->getTraceAsString()."\n"; + $str .= "\n[previous exception] " . $this->formatException($previous); + } while ($previous = $previous->getPrevious()); } return $str; } - protected function convertToString($data) + /** + * @param mixed $data + */ + protected function convertToString($data): string { if (null === $data || is_bool($data)) { return var_export($data, true); @@ -159,23 +179,68 @@ protected function convertToString($data) return (string) $data; } - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return $this->toJson($data, true); - } - - return str_replace('\\/', '/', $this->toJson($data, true)); + return $this->toJson($data, true); } - protected function replaceNewlines($str) + protected function replaceNewlines(string $str): string { if ($this->allowInlineLineBreaks) { if (0 === strpos($str, '{')) { - return str_replace(array('\r', '\n'), array("\r", "\n"), $str); + $str = preg_replace('/(?getCode(); + if ($e instanceof \SoapFault) { + if (isset($e->faultcode)) { + $str .= ' faultcode: ' . $e->faultcode; + } + + if (isset($e->faultactor)) { + $str .= ' faultactor: ' . $e->faultactor; + } + + if (isset($e->detail)) { + if (is_string($e->detail)) { + $str .= ' detail: ' . $e->detail; + } elseif (is_object($e->detail) || is_array($e->detail)) { + $str .= ' detail: ' . $this->toJson($e->detail, true); + } + } + } + $str .= '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')'; + + if ($this->includeStacktraces) { + $str .= $this->stacktracesParser($e); + } + + return $str; + } + + private function stacktracesParser(\Throwable $e): string + { + $trace = $e->getTraceAsString(); + + if ($this->stacktracesParser) { + $trace = $this->stacktracesParserCustom($trace); + } + + return "\n[stacktrace]\n" . $trace . "\n"; + } + + private function stacktracesParserCustom(string $trace): string + { + return implode("\n", array_filter(array_map($this->stacktracesParser, explode("\n", $trace)))); } } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php index 401859bb..29841aa3 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/LogglyFormatter.php @@ -1,4 +1,4 @@ -format("Y-m-d\TH:i:s.uO"); - // TODO 2.0 unset the 'datetime' parameter, retained for BC + unset($record["datetime"]); } return parent::format($record); diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LogmaticFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LogmaticFormatter.php new file mode 100644 index 00000000..b0451aba --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Formatter/LogmaticFormatter.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Formatter; + +/** + * Encodes message information into JSON in a format compatible with Logmatic. + * + * @author Julien Breux + */ +class LogmaticFormatter extends JsonFormatter +{ + protected const MARKERS = ["sourcecode", "php"]; + + /** + * @var string + */ + protected $hostname = ''; + + /** + * @var string + */ + protected $appname = ''; + + public function setHostname(string $hostname): self + { + $this->hostname = $hostname; + + return $this; + } + + public function setAppname(string $appname): self + { + $this->appname = $appname; + + return $this; + } + + /** + * Appends the 'hostname' and 'appname' parameter for indexing by Logmatic. + * + * @see http://doc.logmatic.io/docs/basics-to-send-data + * @see \Monolog\Formatter\JsonFormatter::format() + */ + public function format(array $record): string + { + if (!empty($this->hostname)) { + $record["hostname"] = $this->hostname; + } + if (!empty($this->appname)) { + $record["appname"] = $this->appname; + } + + $record["@marker"] = static::MARKERS; + + return parent::format($record); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php index 8f83bec0..f8de0d33 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/LogstashFormatter.php @@ -1,4 +1,4 @@ - */ class LogstashFormatter extends NormalizerFormatter { - const V0 = 0; - const V1 = 1; - /** * @var string the name of the system for the Logstash log message, used to fill the @source field */ @@ -35,108 +32,47 @@ class LogstashFormatter extends NormalizerFormatter protected $applicationName; /** - * @var string a prefix for 'extra' fields from the Monolog record (optional) + * @var string the key for 'extra' fields from the Monolog record */ - protected $extraPrefix; + protected $extraKey; /** - * @var string a prefix for 'context' fields from the Monolog record (optional) + * @var string the key for 'context' fields from the Monolog record */ - protected $contextPrefix; + protected $contextKey; /** - * @var int logstash format version to use + * @param string $applicationName The application that sends the data, used as the "type" field of logstash + * @param string|null $systemName The system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine + * @param string $extraKey The key for extra keys inside logstash "fields", defaults to extra + * @param string $contextKey The key for context keys inside logstash "fields", defaults to context */ - protected $version; - - /** - * @param string $applicationName the application that sends the data, used as the "type" field of logstash - * @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine - * @param string $extraPrefix prefix for extra keys inside logstash "fields" - * @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_ - * @param int $version the logstash format version to use, defaults to 0 - */ - public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0) + public function __construct(string $applicationName, ?string $systemName = null, string $extraKey = 'extra', string $contextKey = 'context') { // logstash requires a ISO 8601 format date with optional millisecond precision. parent::__construct('Y-m-d\TH:i:s.uP'); - $this->systemName = $systemName ?: gethostname(); + $this->systemName = $systemName === null ? (string) gethostname() : $systemName; $this->applicationName = $applicationName; - $this->extraPrefix = $extraPrefix; - $this->contextPrefix = $contextPrefix; - $this->version = $version; + $this->extraKey = $extraKey; + $this->contextKey = $contextKey; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function format(array $record) + public function format(array $record): string { $record = parent::format($record); - if ($this->version === self::V1) { - $message = $this->formatV1($record); - } else { - $message = $this->formatV0($record); - } - - return $this->toJson($message) . "\n"; - } - - protected function formatV0(array $record) - { if (empty($record['datetime'])) { $record['datetime'] = gmdate('c'); } - $message = array( - '@timestamp' => $record['datetime'], - '@source' => $this->systemName, - '@fields' => array(), - ); - if (isset($record['message'])) { - $message['@message'] = $record['message']; - } - if (isset($record['channel'])) { - $message['@tags'] = array($record['channel']); - $message['@fields']['channel'] = $record['channel']; - } - if (isset($record['level'])) { - $message['@fields']['level'] = $record['level']; - } - if ($this->applicationName) { - $message['@type'] = $this->applicationName; - } - if (isset($record['extra']['server'])) { - $message['@source_host'] = $record['extra']['server']; - } - if (isset($record['extra']['url'])) { - $message['@source_path'] = $record['extra']['url']; - } - if (!empty($record['extra'])) { - foreach ($record['extra'] as $key => $val) { - $message['@fields'][$this->extraPrefix . $key] = $val; - } - } - if (!empty($record['context'])) { - foreach ($record['context'] as $key => $val) { - $message['@fields'][$this->contextPrefix . $key] = $val; - } - } - - return $message; - } - - protected function formatV1(array $record) - { - if (empty($record['datetime'])) { - $record['datetime'] = gmdate('c'); - } - $message = array( + $message = [ '@timestamp' => $record['datetime'], '@version' => 1, 'host' => $this->systemName, - ); + ]; if (isset($record['message'])) { $message['message'] = $record['message']; } @@ -147,20 +83,19 @@ protected function formatV1(array $record) if (isset($record['level_name'])) { $message['level'] = $record['level_name']; } + if (isset($record['level'])) { + $message['monolog_level'] = $record['level']; + } if ($this->applicationName) { $message['type'] = $this->applicationName; } if (!empty($record['extra'])) { - foreach ($record['extra'] as $key => $val) { - $message[$this->extraPrefix . $key] = $val; - } + $message[$this->extraKey] = $record['extra']; } if (!empty($record['context'])) { - foreach ($record['context'] as $key => $val) { - $message[$this->contextPrefix . $key] = $val; - } + $message[$this->contextKey] = $record['context']; } - return $message; + return $this->toJson($message) . "\n"; } } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php index bd9e4c02..fca69a89 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/MongoDBFormatter.php @@ -1,4 +1,4 @@ -maxNestingLevel = max($maxNestingLevel, 0); - $this->exceptionTraceAsString = (bool) $exceptionTraceAsString; + $this->exceptionTraceAsString = $exceptionTraceAsString; + + $this->isLegacyMongoExt = extension_loaded('mongodb') && version_compare((string) phpversion('mongodb'), '1.1.9', '<='); } /** * {@inheritDoc} + * + * @return mixed[] */ - public function format(array $record) + public function format(array $record): array { - return $this->formatArray($record); + /** @var mixed[] $res */ + $res = $this->formatArray($record); + + return $res; } /** * {@inheritDoc} + * + * @return array */ - public function formatBatch(array $records) + public function formatBatch(array $records): array { + $formatted = []; foreach ($records as $key => $record) { - $records[$key] = $this->format($record); + $formatted[$key] = $this->format($record); } - return $records; + return $formatted; } - protected function formatArray(array $record, $nestingLevel = 0) + /** + * @param mixed[] $array + * @return mixed[]|string Array except when max nesting level is reached then a string "[...]" + */ + protected function formatArray(array $array, int $nestingLevel = 0) { - if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) { - foreach ($record as $name => $value) { - if ($value instanceof \DateTime) { - $record[$name] = $this->formatDate($value, $nestingLevel + 1); - } elseif ($value instanceof \Exception) { - $record[$name] = $this->formatException($value, $nestingLevel + 1); - } elseif (is_array($value)) { - $record[$name] = $this->formatArray($value, $nestingLevel + 1); - } elseif (is_object($value)) { - $record[$name] = $this->formatObject($value, $nestingLevel + 1); - } + if ($this->maxNestingLevel > 0 && $nestingLevel > $this->maxNestingLevel) { + return '[...]'; + } + + foreach ($array as $name => $value) { + if ($value instanceof \DateTimeInterface) { + $array[$name] = $this->formatDate($value, $nestingLevel + 1); + } elseif ($value instanceof \Throwable) { + $array[$name] = $this->formatException($value, $nestingLevel + 1); + } elseif (is_array($value)) { + $array[$name] = $this->formatArray($value, $nestingLevel + 1); + } elseif (is_object($value) && !$value instanceof Type) { + $array[$name] = $this->formatObject($value, $nestingLevel + 1); } - } else { - $record = '[...]'; } - return $record; + return $array; } - protected function formatObject($value, $nestingLevel) + /** + * @param mixed $value + * @return mixed[]|string + */ + protected function formatObject($value, int $nestingLevel) { $objectVars = get_object_vars($value); $objectVars['class'] = Utils::getClass($value); @@ -82,14 +106,17 @@ protected function formatObject($value, $nestingLevel) return $this->formatArray($objectVars, $nestingLevel); } - protected function formatException(\Exception $exception, $nestingLevel) + /** + * @return mixed[]|string + */ + protected function formatException(\Throwable $exception, int $nestingLevel) { - $formattedException = array( + $formattedException = [ 'class' => Utils::getClass($exception), 'message' => $exception->getMessage(), 'code' => (int) $exception->getCode(), 'file' => $exception->getFile() . ':' . $exception->getLine(), - ); + ]; if ($this->exceptionTraceAsString === true) { $formattedException['trace'] = $exception->getTraceAsString(); @@ -100,8 +127,36 @@ protected function formatException(\Exception $exception, $nestingLevel) return $this->formatArray($formattedException, $nestingLevel); } - protected function formatDate(\DateTime $value, $nestingLevel) + protected function formatDate(\DateTimeInterface $value, int $nestingLevel): UTCDateTime { - return new \MongoDate($value->getTimestamp()); + if ($this->isLegacyMongoExt) { + return $this->legacyGetMongoDbDateTime($value); + } + + return $this->getMongoDbDateTime($value); + } + + private function getMongoDbDateTime(\DateTimeInterface $value): UTCDateTime + { + return new UTCDateTime((int) floor(((float) $value->format('U.u')) * 1000)); + } + + /** + * This is needed to support MongoDB Driver v1.19 and below + * + * See https://github.com/mongodb/mongo-php-driver/issues/426 + * + * It can probably be removed in 2.1 or later once MongoDB's 1.2 is released and widely adopted + */ + private function legacyGetMongoDbDateTime(\DateTimeInterface $value): UTCDateTime + { + $milliseconds = floor(((float) $value->format('U.u')) * 1000); + + $milliseconds = (PHP_INT_SIZE == 8) //64-bit OS? + ? (int) $milliseconds + : (string) $milliseconds; + + // @phpstan-ignore-next-line + return new UTCDateTime($milliseconds); } } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php index 010466b4..5441bc0a 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/NormalizerFormatter.php @@ -1,4 +1,4 @@ -dateFormat = $dateFormat ?: static::SIMPLE_DATE; - $this->maxDepth = $maxDepth; + $this->dateFormat = null === $dateFormat ? static::SIMPLE_DATE : $dateFormat; if (!function_exists('json_encode')) { throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter'); } } /** - * {@inheritdoc} + * {@inheritDoc} + * + * @param mixed[] $record */ public function format(array $record) { @@ -48,7 +56,7 @@ public function format(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ public function formatBatch(array $records) { @@ -59,26 +67,70 @@ public function formatBatch(array $records) return $records; } + public function getDateFormat(): string + { + return $this->dateFormat; + } + + public function setDateFormat(string $dateFormat): self + { + $this->dateFormat = $dateFormat; + + return $this; + } + /** - * @return int + * The maximum number of normalization levels to go through */ - public function getMaxDepth() + public function getMaxNormalizeDepth(): int { - return $this->maxDepth; + return $this->maxNormalizeDepth; + } + + public function setMaxNormalizeDepth(int $maxNormalizeDepth): self + { + $this->maxNormalizeDepth = $maxNormalizeDepth; + + return $this; } /** - * @param int $maxDepth + * The maximum number of items to normalize per level */ - public function setMaxDepth($maxDepth) + public function getMaxNormalizeItemCount(): int { - $this->maxDepth = $maxDepth; + return $this->maxNormalizeItemCount; } - protected function normalize($data, $depth = 0) + public function setMaxNormalizeItemCount(int $maxNormalizeItemCount): self { - if ($depth > $this->maxDepth) { - return 'Over '.$this->maxDepth.' levels deep, aborting normalization'; + $this->maxNormalizeItemCount = $maxNormalizeItemCount; + + return $this; + } + + /** + * Enables `json_encode` pretty print. + */ + public function setJsonPrettyPrint(bool $enable): self + { + if ($enable) { + $this->jsonEncodeOptions |= JSON_PRETTY_PRINT; + } else { + $this->jsonEncodeOptions &= ~JSON_PRETTY_PRINT; + } + + return $this; + } + + /** + * @param mixed $data + * @return null|scalar|array + */ + protected function normalize($data, int $depth = 0) + { + if ($depth > $this->maxNormalizeDepth) { + return 'Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization'; } if (null === $data || is_scalar($data)) { @@ -95,62 +147,71 @@ protected function normalize($data, $depth = 0) } if (is_array($data)) { - $normalized = array(); + $normalized = []; $count = 1; foreach ($data as $key => $value) { - if ($count++ > 1000) { - $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization'; + if ($count++ > $this->maxNormalizeItemCount) { + $normalized['...'] = 'Over ' . $this->maxNormalizeItemCount . ' items ('.count($data).' total), aborting normalization'; break; } - $normalized[$key] = $this->normalize($value, $depth+1); + $normalized[$key] = $this->normalize($value, $depth + 1); } return $normalized; } - if ($data instanceof \DateTime) { - return $data->format($this->dateFormat); + if ($data instanceof \DateTimeInterface) { + return $this->formatDate($data); } if (is_object($data)) { - // TODO 2.0 only check for Throwable - if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) { - return $this->normalizeException($data); + if ($data instanceof Throwable) { + return $this->normalizeException($data, $depth); } - // non-serializable objects that implement __toString stringified - if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) { + if ($data instanceof \JsonSerializable) { + /** @var null|scalar|array $value */ + $value = $data->jsonSerialize(); + } elseif (method_exists($data, '__toString')) { + /** @var string $value */ $value = $data->__toString(); } else { - // the rest is json-serialized in some way - $value = $this->toJson($data, true); + // the rest is normalized by json encoding and decoding it + /** @var null|scalar|array $value */ + $value = json_decode($this->toJson($data, true), true); } - return sprintf("[object] (%s: %s)", Utils::getClass($data), $value); + return [Utils::getClass($data) => $value]; } if (is_resource($data)) { - return sprintf('[resource] (%s)', get_resource_type($data)); + return sprintf('[resource(%s)]', get_resource_type($data)); } return '[unknown('.gettype($data).')]'; } - protected function normalizeException($e) + /** + * @return mixed[] + */ + protected function normalizeException(Throwable $e, int $depth = 0) { - // TODO 2.0 only check for Throwable - if (!$e instanceof Exception && !$e instanceof \Throwable) { - throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.Utils::getClass($e)); + if ($depth > $this->maxNormalizeDepth) { + return ['Over ' . $this->maxNormalizeDepth . ' levels deep, aborting normalization']; } - $data = array( + if ($e instanceof \JsonSerializable) { + return (array) $e->jsonSerialize(); + } + + $data = [ 'class' => Utils::getClass($e), 'message' => $e->getMessage(), 'code' => (int) $e->getCode(), 'file' => $e->getFile().':'.$e->getLine(), - ); + ]; if ($e instanceof \SoapFault) { if (isset($e->faultcode)) { @@ -162,7 +223,7 @@ protected function normalizeException($e) } if (isset($e->detail)) { - if (is_string($e->detail)) { + if (is_string($e->detail)) { $data['detail'] = $e->detail; } elseif (is_object($e->detail) || is_array($e->detail)) { $data['detail'] = $this->toJson($e->detail, true); @@ -178,7 +239,7 @@ protected function normalizeException($e) } if ($previous = $e->getPrevious()) { - $data['previous'] = $this->normalizeException($previous); + $data['previous'] = $this->normalizeException($previous, $depth + 1); } return $data; @@ -188,12 +249,39 @@ protected function normalizeException($e) * Return the JSON representation of a value * * @param mixed $data - * @param bool $ignoreErrors * @throws \RuntimeException if encoding fails and errors are not ignored + * @return string if encoding fails and ignoreErrors is true 'null' is returned + */ + protected function toJson($data, bool $ignoreErrors = false): string + { + return Utils::jsonEncode($data, $this->jsonEncodeOptions, $ignoreErrors); + } + + /** * @return string */ - protected function toJson($data, $ignoreErrors = false) + protected function formatDate(\DateTimeInterface $date) + { + // in case the date format isn't custom then we defer to the custom DateTimeImmutable + // formatting logic, which will pick the right format based on whether useMicroseconds is on + if ($this->dateFormat === self::SIMPLE_DATE && $date instanceof DateTimeImmutable) { + return (string) $date; + } + + return $date->format($this->dateFormat); + } + + public function addJsonEncodeOption(int $option): self { - return Utils::jsonEncode($data, null, $ignoreErrors); + $this->jsonEncodeOptions |= $option; + + return $this; + } + + public function removeJsonEncodeOption(int $option): self + { + $this->jsonEncodeOptions &= ~$option; + + return $this; } -} \ No newline at end of file +} diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php index 5d345d53..187bc550 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/ScalarFormatter.php @@ -1,4 +1,4 @@ - $record */ - public function format(array $record) + public function format(array $record): array { + $result = []; foreach ($record as $key => $value) { - $record[$key] = $this->normalizeValue($value); + $result[$key] = $this->normalizeValue($value); } - return $record; + return $result; } /** - * @param mixed $value - * @return mixed + * @param mixed $value + * @return scalar|null */ protected function normalizeValue($value) { $normalized = $this->normalize($value); - if (is_array($normalized) || is_object($normalized)) { + if (is_array($normalized)) { return $this->toJson($normalized, true); } diff --git a/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php b/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php index 65dba99c..6539b347 100644 --- a/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php +++ b/vendor/monolog/monolog/src/Monolog/Formatter/WildfireFormatter.php @@ -1,4 +1,4 @@ - * @author Christophe Coevoet * @author Kirill chEbba Chebunin + * + * @phpstan-import-type Level from \Monolog\Logger */ class WildfireFormatter extends NormalizerFormatter { - const TABLE = 'table'; - /** * Translates Monolog log levels to Wildfire levels. + * + * @var array */ - private $logLevels = array( + private $logLevels = [ Logger::DEBUG => 'LOG', Logger::INFO => 'INFO', Logger::NOTICE => 'INFO', @@ -36,12 +38,25 @@ class WildfireFormatter extends NormalizerFormatter Logger::CRITICAL => 'ERROR', Logger::ALERT => 'ERROR', Logger::EMERGENCY => 'ERROR', - ); + ]; + + /** + * @param string|null $dateFormat The format of the timestamp: one supported by DateTime::format + */ + public function __construct(?string $dateFormat = null) + { + parent::__construct($dateFormat); + + // http headers do not like non-ISO-8559-1 characters + $this->removeJsonEncodeOption(JSON_UNESCAPED_UNICODE); + } /** - * {@inheritdoc} + * {@inheritDoc} + * + * @return string */ - public function format(array $record) + public function format(array $record): string { // Retrieve the line and file if set and remove them from the formatted extra $file = $line = ''; @@ -54,8 +69,9 @@ public function format(array $record) unset($record['extra']['line']); } + /** @var mixed[] $record */ $record = $this->normalize($record); - $message = array('message' => $record['message']); + $message = ['message' => $record['message']]; $handleError = false; if ($record['context']) { $message['context'] = $record['context']; @@ -69,42 +85,52 @@ public function format(array $record) $message = reset($message); } - if (isset($record['context'][self::TABLE])) { + if (isset($record['context']['table'])) { $type = 'TABLE'; $label = $record['channel'] .': '. $record['message']; - $message = $record['context'][self::TABLE]; + $message = $record['context']['table']; } else { $type = $this->logLevels[$record['level']]; $label = $record['channel']; } // Create JSON object describing the appearance of the message in the console - $json = $this->toJson(array( - array( + $json = $this->toJson([ + [ 'Type' => $type, 'File' => $file, 'Line' => $line, 'Label' => $label, - ), + ], $message, - ), $handleError); + ], $handleError); // The message itself is a serialization of the above JSON object + it's length return sprintf( - '%s|%s|', + '%d|%s|', strlen($json), $json ); } + /** + * {@inheritDoc} + * + * @phpstan-return never + */ public function formatBatch(array $records) { throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); } - protected function normalize($data, $depth = 0) + /** + * {@inheritDoc} + * + * @return null|scalar|array|object + */ + protected function normalize($data, int $depth = 0) { - if (is_object($data) && !$data instanceof \DateTime) { + if (is_object($data) && !$data instanceof \DateTimeInterface) { return $data; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php index cdd9f7d4..a5cdaa71 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ -abstract class AbstractHandler implements HandlerInterface, ResettableInterface +abstract class AbstractHandler extends Handler implements ResettableInterface { - protected $level = Logger::DEBUG; - protected $bubble = true; - /** - * @var FormatterInterface + * @var int + * @phpstan-var Level */ - protected $formatter; - protected $processors = array(); + protected $level = Logger::DEBUG; + /** @var bool */ + protected $bubble = true; /** * @param int|string $level The minimum logging level at which this handler will be triggered * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function __construct($level = Logger::DEBUG, $bubble = true) + public function __construct($level = Logger::DEBUG, bool $bubble = true) { $this->setLevel($level); $this->bubble = $bubble; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return $record['level'] >= $this->level; } - /** - * {@inheritdoc} - */ - public function handleBatch(array $records) - { - foreach ($records as $record) { - $this->handle($record); - } - } - - /** - * Closes the handler. - * - * This will be called automatically when the object is destroyed - */ - public function close() - { - } - - /** - * {@inheritdoc} - */ - public function pushProcessor($callback) - { - if (!is_callable($callback)) { - throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); - } - array_unshift($this->processors, $callback); - - return $this; - } - - /** - * {@inheritdoc} - */ - public function popProcessor() - { - if (!$this->processors) { - throw new \LogicException('You tried to pop from an empty processor stack.'); - } - - return array_shift($this->processors); - } - - /** - * {@inheritdoc} - */ - public function setFormatter(FormatterInterface $formatter) - { - $this->formatter = $formatter; - - return $this; - } - - /** - * {@inheritdoc} - */ - public function getFormatter() - { - if (!$this->formatter) { - $this->formatter = $this->getDefaultFormatter(); - } - - return $this->formatter; - } - /** * Sets minimum logging level at which this handler will be triggered. * - * @param int|string $level Level or level name + * @param Level|LevelName|LogLevel::* $level Level or level name * @return self */ - public function setLevel($level) + public function setLevel($level): self { $this->level = Logger::toMonologLevel($level); @@ -133,8 +70,10 @@ public function setLevel($level) * Gets minimum logging level at which this handler will be triggered. * * @return int + * + * @phpstan-return Level */ - public function getLevel() + public function getLevel(): int { return $this->level; } @@ -146,7 +85,7 @@ public function getLevel() * false means that bubbling is not permitted. * @return self */ - public function setBubble($bubble) + public function setBubble(bool $bubble): self { $this->bubble = $bubble; @@ -159,38 +98,15 @@ public function setBubble($bubble) * @return bool true means that this handler allows bubbling. * false means that bubbling is not permitted. */ - public function getBubble() + public function getBubble(): bool { return $this->bubble; } - public function __destruct() - { - try { - $this->close(); - } catch (\Exception $e) { - // do nothing - } catch (\Throwable $e) { - // do nothing - } - } - - public function reset() - { - foreach ($this->processors as $processor) { - if ($processor instanceof ResettableInterface) { - $processor->reset(); - } - } - } - /** - * Gets the default formatter. - * - * @return FormatterInterface + * {@inheritDoc} */ - protected function getDefaultFormatter() + public function reset() { - return new LineFormatter(); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php index e1e89530..77e533fc 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractProcessingHandler.php @@ -1,4 +1,4 @@ - * @author Christophe Coevoet + * + * @phpstan-import-type LevelName from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-type FormattedRecord array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[], formatted: mixed} */ -abstract class AbstractProcessingHandler extends AbstractHandler +abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { + use ProcessableHandlerTrait; + use FormattableHandlerTrait; + /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; } - $record = $this->processRecord($record); + if ($this->processors) { + /** @var Record $record */ + $record = $this->processRecord($record); + } $record['formatted'] = $this->getFormatter()->format($record); @@ -44,25 +53,17 @@ public function handle(array $record) /** * Writes the record down to the log of the implementing handler * - * @param array $record - * @return void + * @phpstan-param FormattedRecord $record */ - abstract protected function write(array $record); + abstract protected function write(array $record): void; /** - * Processes a record. - * - * @param array $record - * @return array + * @return void */ - protected function processRecord(array $record) + public function reset() { - if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - } + parent::reset(); - return $record; + $this->resetProcessors(); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php index 8c76aca0..5e5ad1c1 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/AbstractSyslogHandler.php @@ -1,4 +1,4 @@ - */ - protected $logLevels = array( + protected $logLevels = [ Logger::DEBUG => LOG_DEBUG, Logger::INFO => LOG_INFO, Logger::NOTICE => LOG_NOTICE, @@ -33,12 +39,13 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler Logger::CRITICAL => LOG_CRIT, Logger::ALERT => LOG_ALERT, Logger::EMERGENCY => LOG_EMERG, - ); + ]; /** * List of valid log facility names. + * @var array */ - protected $facilities = array( + protected $facilities = [ 'auth' => LOG_AUTH, 'authpriv' => LOG_AUTHPRIV, 'cron' => LOG_CRON, @@ -50,14 +57,12 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler 'syslog' => LOG_SYSLOG, 'user' => LOG_USER, 'uucp' => LOG_UUCP, - ); + ]; /** - * @param mixed $facility - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant */ - public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true) + public function __construct($facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); @@ -82,7 +87,7 @@ public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubbl } // convert textual description of facility to syslog constant - if (array_key_exists(strtolower($facility), $this->facilities)) { + if (is_string($facility) && array_key_exists(strtolower($facility), $this->facilities)) { $facility = $this->facilities[strtolower($facility)]; } elseif (!in_array($facility, array_values($this->facilities), true)) { throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given'); @@ -92,9 +97,9 @@ public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubbl } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%'); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php index e5a46bc0..994872ce 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/AmqpHandler.php @@ -1,4 +1,4 @@ - */ + private $extraAttributes = []; + + /** + * @return array + */ + public function getExtraAttributes(): array + { + return $this->extraAttributes; + } + + /** + * Configure extra attributes to pass to the AMQPExchange (if you are using the amqp extension) + * + * @param array $extraAttributes One of content_type, content_encoding, + * message_id, user_id, app_id, delivery_mode, + * priority, timestamp, expiration, type + * or reply_to, headers. + * @return AmqpHandler + */ + public function setExtraAttributes(array $extraAttributes): self + { + $this->extraAttributes = $extraAttributes; + return $this; + } /** * @var string @@ -31,18 +60,16 @@ class AmqpHandler extends AbstractProcessingHandler /** * @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use - * @param string $exchangeName - * @param int $level - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string|null $exchangeName Optional exchange name, for AMQPChannel (PhpAmqpLib) only */ - public function __construct($exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true) + public function __construct($exchange, ?string $exchangeName = null, $level = Logger::DEBUG, bool $bubble = true) { - if ($exchange instanceof AMQPExchange) { - $exchange->setName($exchangeName); - } elseif ($exchange instanceof AMQPChannel) { - $this->exchangeName = $exchangeName; - } else { + if ($exchange instanceof AMQPChannel) { + $this->exchangeName = (string) $exchangeName; + } elseif (!$exchange instanceof AMQPExchange) { throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required'); + } elseif ($exchangeName) { + @trigger_error('The $exchangeName parameter can only be passed when using PhpAmqpLib, if using an AMQPExchange instance configure it beforehand', E_USER_DEPRECATED); } $this->exchange = $exchange; @@ -52,20 +79,24 @@ public function __construct($exchange, $exchangeName = 'log', $level = Logger::D /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $data = $record["formatted"]; $routingKey = $this->getRoutingKey($record); if ($this->exchange instanceof AMQPExchange) { + $attributes = [ + 'delivery_mode' => 2, + 'content_type' => 'application/json', + ]; + if ($this->extraAttributes) { + $attributes = array_merge($attributes, $this->extraAttributes); + } $this->exchange->publish( $data, $routingKey, 0, - array( - 'delivery_mode' => 2, - 'content_type' => 'application/json', - ) + $attributes ); } else { $this->exchange->basic_publish( @@ -79,7 +110,7 @@ protected function write(array $record) /** * {@inheritDoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if ($this->exchange instanceof AMQPExchange) { parent::handleBatch($records); @@ -92,6 +123,7 @@ public function handleBatch(array $records) continue; } + /** @var Record $record */ $record = $this->processRecord($record); $data = $this->getFormatter()->format($record); @@ -108,40 +140,31 @@ public function handleBatch(array $records) /** * Gets the routing key for the AMQP exchange * - * @param array $record - * @return string + * @phpstan-param Record $record */ - protected function getRoutingKey(array $record) + protected function getRoutingKey(array $record): string { - $routingKey = sprintf( - '%s.%s', - // TODO 2.0 remove substr call - substr($record['level_name'], 0, 4), - $record['channel'] - ); + $routingKey = sprintf('%s.%s', $record['level_name'], $record['channel']); return strtolower($routingKey); } - /** - * @param string $data - * @return AMQPMessage - */ - private function createAmqpMessage($data) + private function createAmqpMessage(string $data): AMQPMessage { - return new AMQPMessage( - (string) $data, - array( - 'delivery_mode' => 2, - 'content_type' => 'application/json', - ) - ); + $attributes = [ + 'delivery_mode' => 2, + 'content_type' => 'application/json', + ]; + if ($this->extraAttributes) { + $attributes = array_merge($attributes, $this->extraAttributes); + } + return new AMQPMessage($data, $attributes); } /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php index 68feb480..95bbfed4 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/BrowserConsoleHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class BrowserConsoleHandler extends AbstractProcessingHandler { + /** @var bool */ protected static $initialized = false; - protected static $records = array(); + /** @var FormattedRecord[] */ + protected static $records = []; + + protected const FORMAT_HTML = 'html'; + protected const FORMAT_JS = 'js'; + protected const FORMAT_UNKNOWN = 'unknown'; /** * {@inheritDoc} @@ -32,7 +50,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler * * You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%'); } @@ -40,7 +58,7 @@ protected function getDefaultFormatter() /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { // Accumulate records static::$records[] = $record; @@ -56,57 +74,57 @@ protected function write(array $record) * Convert records to javascript console commands and send it to the browser. * This method is automatically called on PHP shutdown if output is HTML or Javascript. */ - public static function send() + public static function send(): void { $format = static::getResponseFormat(); - if ($format === 'unknown') { + if ($format === self::FORMAT_UNKNOWN) { return; } if (count(static::$records)) { - if ($format === 'html') { + if ($format === self::FORMAT_HTML) { static::writeOutput(''); - } elseif ($format === 'js') { + } elseif ($format === self::FORMAT_JS) { static::writeOutput(static::generateScript()); } static::resetStatic(); } } - public function close() + public function close(): void { self::resetStatic(); } public function reset() { + parent::reset(); + self::resetStatic(); } /** * Forget all logged records */ - public static function resetStatic() + public static function resetStatic(): void { - static::$records = array(); + static::$records = []; } /** * Wrapper for register_shutdown_function to allow overriding */ - protected function registerShutdownFunction() + protected function registerShutdownFunction(): void { if (PHP_SAPI !== 'cli') { - register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send')); + register_shutdown_function(['Monolog\Handler\BrowserConsoleHandler', 'send']); } } /** * Wrapper for echo to allow overriding - * - * @param string $str */ - protected static function writeOutput($str) + protected static function writeOutput(string $str): void { echo $str; } @@ -119,42 +137,55 @@ protected static function writeOutput($str) * If Content-Type is anything else -> unknown * * @return string One of 'js', 'html' or 'unknown' + * @phpstan-return self::FORMAT_* */ - protected static function getResponseFormat() + protected static function getResponseFormat(): string { // Check content type foreach (headers_list() as $header) { if (stripos($header, 'content-type:') === 0) { - // This handler only works with HTML and javascript outputs - // text/javascript is obsolete in favour of application/javascript, but still used - if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) { - return 'js'; - } - if (stripos($header, 'text/html') === false) { - return 'unknown'; - } - break; + return static::getResponseFormatFromContentType($header); } } - return 'html'; + return self::FORMAT_HTML; } - private static function generateScript() + /** + * @return string One of 'js', 'html' or 'unknown' + * @phpstan-return self::FORMAT_* + */ + protected static function getResponseFormatFromContentType(string $contentType): string { - $script = array(); + // This handler only works with HTML and javascript outputs + // text/javascript is obsolete in favour of application/javascript, but still used + if (stripos($contentType, 'application/javascript') !== false || stripos($contentType, 'text/javascript') !== false) { + return self::FORMAT_JS; + } + + if (stripos($contentType, 'text/html') !== false) { + return self::FORMAT_HTML; + } + + return self::FORMAT_UNKNOWN; + } + + private static function generateScript(): string + { + $script = []; foreach (static::$records as $record) { $context = static::dump('Context', $record['context']); $extra = static::dump('Extra', $record['extra']); if (empty($context) && empty($extra)) { - $script[] = static::call_array('log', static::handleStyles($record['formatted'])); + $script[] = static::call_array(static::getConsoleMethodForLevel($record['level']), static::handleStyles($record['formatted'])); } else { - $script = array_merge($script, - array(static::call_array('groupCollapsed', static::handleStyles($record['formatted']))), + $script = array_merge( + $script, + [static::call_array('groupCollapsed', static::handleStyles($record['formatted']))], $context, $extra, - array(static::call('groupEnd')) + [static::call('groupEnd')] ); } } @@ -162,9 +193,26 @@ private static function generateScript() return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);"; } - private static function handleStyles($formatted) + private static function getConsoleMethodForLevel(int $level): string + { + return [ + Logger::DEBUG => 'debug', + Logger::INFO => 'info', + Logger::NOTICE => 'info', + Logger::WARNING => 'warn', + Logger::ERROR => 'error', + Logger::CRITICAL => 'error', + Logger::ALERT => 'error', + Logger::EMERGENCY => 'error', + ][$level] ?? 'log'; + } + + /** + * @return string[] + */ + private static function handleStyles(string $formatted): array { - $args = array(); + $args = []; $format = '%c' . $formatted; preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); @@ -173,7 +221,7 @@ private static function handleStyles($formatted) $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0])); $pos = $match[0][1]; - $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); + $format = Utils::substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . Utils::substr($format, $pos + strlen($match[0][0])); } $args[] = static::quote('font-weight: normal'); @@ -182,12 +230,12 @@ private static function handleStyles($formatted) return array_reverse($args); } - private static function handleCustomStyles($style, $string) + private static function handleCustomStyles(string $style, string $string): string { - static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey'); - static $labels = array(); + static $colors = ['blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey']; + static $labels = []; - return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) { + $style = preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function (array $m) use ($string, &$colors, &$labels) { if (trim($m[1]) === 'autolabel') { // Format the string as a label with consistent auto assigned background color if (!isset($labels[$string])) { @@ -200,11 +248,22 @@ private static function handleCustomStyles($style, $string) return $m[1]; }, $style); + + if (null === $style) { + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to run preg_replace_callback: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); + } + + return $style; } - private static function dump($title, array $dict) + /** + * @param mixed[] $dict + * @return mixed[] + */ + private static function dump(string $title, array $dict): array { - $script = array(); + $script = []; $dict = array_filter($dict); if (empty($dict)) { return $script; @@ -215,26 +274,34 @@ private static function dump($title, array $dict) if (empty($value)) { $value = static::quote(''); } - $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value); + $script[] = static::call('log', static::quote('%s: %o'), static::quote((string) $key), $value); } return $script; } - private static function quote($arg) + private static function quote(string $arg): string { return '"' . addcslashes($arg, "\"\n\\") . '"'; } - private static function call() + /** + * @param mixed $args + */ + private static function call(...$args): string { - $args = func_get_args(); $method = array_shift($args); + if (!is_string($method)) { + throw new \UnexpectedValueException('Expected the first arg to be a string, got: '.var_export($method, true)); + } return static::call_array($method, $args); } - private static function call_array($method, array $args) + /** + * @param mixed[] $args + */ + private static function call_array(string $method, array $args): string { return 'c.' . $method . '(' . implode(', ', $args) . ');'; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php index 0957e558..fcce5d63 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/BufferHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ -class BufferHandler extends AbstractHandler +class BufferHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { + use ProcessableHandlerTrait; + + /** @var HandlerInterface */ protected $handler; + /** @var int */ protected $bufferSize = 0; + /** @var int */ protected $bufferLimit; + /** @var bool */ protected $flushOnOverflow; - protected $buffer = array(); + /** @var Record[] */ + protected $buffer = []; + /** @var bool */ protected $initialized = false; /** * @param HandlerInterface $handler Handler. * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded */ - public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) + public function __construct(HandlerInterface $handler, int $bufferLimit = 0, $level = Logger::DEBUG, bool $bubble = true, bool $flushOnOverflow = false) { parent::__construct($level, $bubble); $this->handler = $handler; - $this->bufferLimit = (int) $bufferLimit; + $this->bufferLimit = $bufferLimit; $this->flushOnOverflow = $flushOnOverflow; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($record['level'] < $this->level) { return false; @@ -58,7 +66,7 @@ public function handle(array $record) if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors - register_shutdown_function(array($this, 'close')); + register_shutdown_function([$this, 'close']); $this->initialized = true; } @@ -72,9 +80,8 @@ public function handle(array $record) } if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + /** @var Record $record */ + $record = $this->processRecord($record); } $this->buffer[] = $record; @@ -83,7 +90,7 @@ public function handle(array $record) return false === $this->bubble; } - public function flush() + public function flush(): void { if ($this->bufferSize === 0) { return; @@ -101,20 +108,22 @@ public function __destruct() } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function close() + public function close(): void { $this->flush(); + + $this->handler->close(); } /** * Clears the buffer without flushing any messages down to the wrapped handler. */ - public function clear() + public function clear(): void { $this->bufferSize = 0; - $this->buffer = array(); + $this->buffer = []; } public function reset() @@ -123,26 +132,36 @@ public function reset() parent::reset(); + $this->resetProcessors(); + if ($this->handler instanceof ResettableInterface) { $this->handler->reset(); } } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->handler->setFormatter($formatter); + if ($this->handler instanceof FormattableHandlerInterface) { + $this->handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->handler->getFormatter(); + if ($this->handler instanceof FormattableHandlerInterface) { + return $this->handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php index 47120e54..234ecf61 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ChromePHPHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ class ChromePHPHandler extends AbstractProcessingHandler { + use WebRequestRecognizerTrait; + /** * Version of the extension */ - const VERSION = '4.0'; + protected const VERSION = '4.0'; /** * Header name */ - const HEADER_NAME = 'X-ChromeLogger-Data'; + protected const HEADER_NAME = 'X-ChromeLogger-Data'; /** * Regular expression to detect supported browsers (matches any Chrome, or Firefox 43+) */ - const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; + protected const USER_AGENT_REGEX = '{\b(?:Chrome/\d+(?:\.\d+)*|HeadlessChrome|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}'; + /** @var bool */ protected static $initialized = false; /** @@ -50,19 +56,17 @@ class ChromePHPHandler extends AbstractProcessingHandler */ protected static $overflowed = false; - protected static $json = array( + /** @var mixed[] */ + protected static $json = [ 'version' => self::VERSION, - 'columns' => array('label', 'log', 'backtrace', 'type'), - 'rows' => array(), - ); + 'columns' => ['label', 'log', 'backtrace', 'type'], + 'rows' => [], + ]; + /** @var bool */ protected static $sendHeaders = true; - /** - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - */ - public function __construct($level = Logger::DEBUG, $bubble = true) + public function __construct($level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); if (!function_exists('json_encode')) { @@ -71,17 +75,23 @@ public function __construct($level = Logger::DEBUG, $bubble = true) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { - $messages = array(); + if (!$this->isWebRequest()) { + return; + } + + $messages = []; foreach ($records as $record) { if ($record['level'] < $this->level) { continue; } - $messages[] = $this->processRecord($record); + /** @var Record $message */ + $message = $this->processRecord($record); + $messages[] = $message; } if (!empty($messages)) { @@ -94,7 +104,7 @@ public function handleBatch(array $records) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new ChromePHPFormatter(); } @@ -104,10 +114,13 @@ protected function getDefaultFormatter() * * @see sendHeader() * @see send() - * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { + if (!$this->isWebRequest()) { + return; + } + self::$json['rows'][] = $record['formatted']; $this->send(); @@ -118,7 +131,7 @@ protected function write(array $record) * * @see sendHeader() */ - protected function send() + protected function send(): void { if (self::$overflowed || !self::$sendHeaders) { return; @@ -132,40 +145,37 @@ protected function send() return; } - self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''; + self::$json['request_uri'] = $_SERVER['REQUEST_URI'] ?? ''; } - $json = Utils::jsonEncode(self::$json, null, true); - $data = base64_encode(utf8_encode($json)); + $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); + $data = base64_encode($json); if (strlen($data) > 3 * 1024) { self::$overflowed = true; - $record = array( + $record = [ 'message' => 'Incomplete logs, chrome header size limit reached', - 'context' => array(), + 'context' => [], 'level' => Logger::WARNING, 'level_name' => Logger::getLevelName(Logger::WARNING), 'channel' => 'monolog', - 'datetime' => new \DateTime(), - 'extra' => array(), - ); + 'datetime' => new \DateTimeImmutable(), + 'extra' => [], + ]; self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record); - $json = Utils::jsonEncode(self::$json, null, true); - $data = base64_encode(utf8_encode($json)); + $json = Utils::jsonEncode(self::$json, Utils::DEFAULT_JSON_FLAGS & ~JSON_UNESCAPED_UNICODE, true); + $data = base64_encode($json); } if (trim($data) !== '') { - $this->sendHeader(self::HEADER_NAME, $data); + $this->sendHeader(static::HEADER_NAME, $data); } } /** * Send header string to the client - * - * @param string $header - * @param string $content */ - protected function sendHeader($header, $content) + protected function sendHeader(string $header, string $content): void { if (!headers_sent() && self::$sendHeaders) { header(sprintf('%s: %s', $header, $content)); @@ -174,39 +184,13 @@ protected function sendHeader($header, $content) /** * Verifies if the headers are accepted by the current user agent - * - * @return bool */ - protected function headersAccepted() + protected function headersAccepted(): bool { if (empty($_SERVER['HTTP_USER_AGENT'])) { return false; } - return preg_match(self::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']); - } - - /** - * BC getter for the sendHeaders property that has been made static - */ - public function __get($property) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - return static::$sendHeaders; - } - - /** - * BC setter for the sendHeaders property that has been made static - */ - public function __set($property, $value) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - static::$sendHeaders = $value; + return preg_match(static::USER_AGENT_REGEX, $_SERVER['HTTP_USER_AGENT']) === 1; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php index cc986971..52657613 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/CouchDBHandler.php @@ -1,4 +1,4 @@ -options = array_merge(array( + $this->options = array_merge([ 'host' => 'localhost', 'port' => 5984, 'dbname' => 'logger', 'username' => null, 'password' => null, - ), $options); + ], $options); parent::__construct($level, $bubble); } @@ -39,7 +44,7 @@ public function __construct(array $options = array(), $level = Logger::DEBUG, $b /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $basicAuth = null; if ($this->options['username']) { @@ -47,17 +52,17 @@ protected function write(array $record) } $url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname']; - $context = stream_context_create(array( - 'http' => array( + $context = stream_context_create([ + 'http' => [ 'method' => 'POST', 'content' => $record['formatted'], 'ignore_errors' => true, 'max_redirects' => 0, 'header' => 'Content-type: application/json', - ), - )); + ], + ]); - if (false === @file_get_contents($url, null, $context)) { + if (false === @file_get_contents($url, false, $context)) { throw new \RuntimeException(sprintf('Could not connect to %s', $url)); } } @@ -65,7 +70,7 @@ protected function write(array $record) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php index 44928efb..3535a4fc 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/CubeHandler.php @@ -1,4 +1,4 @@ - + * @deprecated Since 2.8.0 and 3.2.0, Cube appears abandoned and thus we will drop this handler in Monolog 4 */ class CubeHandler extends AbstractProcessingHandler { - private $udpConnection; - private $httpConnection; + /** @var resource|\Socket|null */ + private $udpConnection = null; + /** @var resource|\CurlHandle|null */ + private $httpConnection = null; + /** @var string */ private $scheme; + /** @var string */ private $host; + /** @var int */ private $port; - private $acceptedSchemes = array('http', 'udp'); + /** @var string[] */ + private $acceptedSchemes = ['http', 'udp']; /** * Create a Cube handler @@ -36,23 +43,24 @@ class CubeHandler extends AbstractProcessingHandler * A valid url must consist of three parts : protocol://host:port * Only valid protocols used by Cube are http and udp */ - public function __construct($url, $level = Logger::DEBUG, $bubble = true) + public function __construct(string $url, $level = Logger::DEBUG, bool $bubble = true) { $urlInfo = parse_url($url); - if (!isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) { + if ($urlInfo === false || !isset($urlInfo['scheme'], $urlInfo['host'], $urlInfo['port'])) { throw new \UnexpectedValueException('URL "'.$url.'" is not valid'); } if (!in_array($urlInfo['scheme'], $this->acceptedSchemes)) { throw new \UnexpectedValueException( 'Invalid protocol (' . $urlInfo['scheme'] . ').' - . ' Valid options are ' . implode(', ', $this->acceptedSchemes)); + . ' Valid options are ' . implode(', ', $this->acceptedSchemes) + ); } $this->scheme = $urlInfo['scheme']; $this->host = $urlInfo['host']; - $this->port = $urlInfo['port']; + $this->port = (int) $urlInfo['port']; parent::__construct($level, $bubble); } @@ -63,50 +71,53 @@ public function __construct($url, $level = Logger::DEBUG, $bubble = true) * @throws \LogicException when unable to connect to the socket * @throws MissingExtensionException when there is no socket extension */ - protected function connectUdp() + protected function connectUdp(): void { if (!extension_loaded('sockets')) { throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler'); } - $this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); - if (!$this->udpConnection) { + $udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0); + if (false === $udpConnection) { throw new \LogicException('Unable to create a socket'); } + $this->udpConnection = $udpConnection; if (!socket_connect($this->udpConnection, $this->host, $this->port)) { throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port); } } /** - * Establish a connection to a http server - * @throws \LogicException when no curl extension + * Establish a connection to an http server + * + * @throws \LogicException when unable to connect to the socket + * @throws MissingExtensionException when no curl extension */ - protected function connectHttp() + protected function connectHttp(): void { if (!extension_loaded('curl')) { - throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler'); + throw new MissingExtensionException('The curl extension is required to use http URLs with the CubeHandler'); } - $this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); - - if (!$this->httpConnection) { + $httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put'); + if (false === $httpConnection) { throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port); } + $this->httpConnection = $httpConnection; curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST"); curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true); } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $date = $record['datetime']; - $data = array('time' => $date->format('Y-m-d\TH:i:s.uO')); + $data = ['time' => $date->format('Y-m-d\TH:i:s.uO')]; unset($record['datetime']); if (isset($record['context']['type'])) { @@ -126,7 +137,7 @@ protected function write(array $record) } } - private function writeUdp($data) + private function writeUdp(string $data): void { if (!$this->udpConnection) { $this->connectUdp(); @@ -135,17 +146,21 @@ private function writeUdp($data) socket_send($this->udpConnection, $data, strlen($data), 0); } - private function writeHttp($data) + private function writeHttp(string $data): void { if (!$this->httpConnection) { $this->connectHttp(); } + if (null === $this->httpConnection) { + throw new \LogicException('No connection could be established'); + } + curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']'); - curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array( + curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen('['.$data.']'), - )); + ]); Curl\Util::execute($this->httpConnection, 5, false); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php b/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php index 48d30b35..7213e8ee 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/Curl/Util.php @@ -1,4 +1,4 @@ - */ + private static $retriableErrorCodes = [ CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_CONNECT, CURLE_HTTP_NOT_FOUND, @@ -21,18 +29,21 @@ class Util CURLE_OPERATION_TIMEOUTED, CURLE_HTTP_POST_ERROR, CURLE_SSL_CONNECT_ERROR, - ); + ]; /** * Executes a CURL request with optional retries and exception on failure * - * @param resource $ch curl handler - * @throws \RuntimeException + * @param resource|CurlHandle $ch curl handler + * @param int $retries + * @param bool $closeAfterDone + * @return bool|string @see curl_exec */ - public static function execute($ch, $retries = 5, $closeAfterDone = true) + public static function execute($ch, int $retries = 5, bool $closeAfterDone = true) { while ($retries--) { - if (curl_exec($ch) === false) { + $curlResponse = curl_exec($ch); + if ($curlResponse === false) { $curlErrno = curl_errno($ch); if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) { @@ -42,7 +53,7 @@ public static function execute($ch, $retries = 5, $closeAfterDone = true) curl_close($ch); } - throw new \RuntimeException(sprintf('Curl error (code %s): %s', $curlErrno, $curlError)); + throw new \RuntimeException(sprintf('Curl error (code %d): %s', $curlErrno, $curlError)); } continue; @@ -51,7 +62,10 @@ public static function execute($ch, $retries = 5, $closeAfterDone = true) if ($closeAfterDone) { curl_close($ch); } - break; + + return $curlResponse; } + + return false; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php index 35b55cb4..9b85ae7e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/DeduplicationHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class DeduplicationHandler extends BufferHandler { @@ -41,7 +46,7 @@ class DeduplicationHandler extends BufferHandler protected $deduplicationStore; /** - * @var int + * @var Level */ protected $deduplicationLevel; @@ -58,11 +63,13 @@ class DeduplicationHandler extends BufferHandler /** * @param HandlerInterface $handler Handler. * @param string $deduplicationStore The file/path where the deduplication log should be kept - * @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes + * @param string|int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes * @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * + * @phpstan-param Level|LevelName|LogLevel::* $deduplicationLevel */ - public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true) + public function __construct(HandlerInterface $handler, ?string $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, int $time = 60, bool $bubble = true) { parent::__construct($handler, 0, Logger::DEBUG, $bubble, false); @@ -71,7 +78,7 @@ public function __construct(HandlerInterface $handler, $deduplicationStore = nul $this->time = $time; } - public function flush() + public function flush(): void { if ($this->bufferSize === 0) { return; @@ -81,7 +88,6 @@ public function flush() foreach ($this->buffer as $record) { if ($record['level'] >= $this->deduplicationLevel) { - $passthru = $passthru || !$this->isDuplicate($record); if ($passthru) { $this->appendRecord($record); @@ -101,7 +107,10 @@ public function flush() } } - private function isDuplicate(array $record) + /** + * @phpstan-param Record $record + */ + private function isDuplicate(array $record): bool { if (!file_exists($this->deduplicationStore)) { return false; @@ -131,21 +140,26 @@ private function isDuplicate(array $record) return false; } - private function collectLogs() + private function collectLogs(): void { if (!file_exists($this->deduplicationStore)) { - return false; + return; } $handle = fopen($this->deduplicationStore, 'rw+'); + + if (!$handle) { + throw new \RuntimeException('Failed to open file for reading and writing: ' . $this->deduplicationStore); + } + flock($handle, LOCK_EX); - $validLogs = array(); + $validLogs = []; $timestampValidity = time() - $this->time; while (!feof($handle)) { $log = fgets($handle); - if (substr($log, 0, 10) >= $timestampValidity) { + if ($log && substr($log, 0, 10) >= $timestampValidity) { $validLogs[] = $log; } } @@ -162,7 +176,10 @@ private function collectLogs() $this->gc = false; } - private function appendRecord(array $record) + /** + * @phpstan-param Record $record + */ + private function appendRecord(array $record): void { file_put_contents($this->deduplicationStore, $record['datetime']->getTimestamp() . ':' . $record['level_name'] . ':' . preg_replace('{[\r\n].*}', '', $record['message']) . "\n", FILE_APPEND); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php index b91ffec9..ebd52c3a 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/DoctrineCouchDBHandler.php @@ -1,4 +1,4 @@ -client = $client; parent::__construct($level, $bubble); @@ -33,12 +35,12 @@ public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubb /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->client->postDocument($record['formatted']); } - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php index 8846e0a0..21840bf6 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/DynamoDbHandler.php @@ -1,4 +1,4 @@ -=')) { $this->version = 3; $this->marshaler = new Marshaler; @@ -69,9 +65,9 @@ public function __construct(DynamoDbClient $client, $table, $level = Logger::DEB } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $filtered = $this->filterEmptyFields($record['formatted']); if ($this->version === 3) { @@ -81,17 +77,17 @@ protected function write(array $record) $formatted = $this->client->formatAttributes($filtered); } - $this->client->putItem(array( + $this->client->putItem([ 'TableName' => $this->table, 'Item' => $formatted, - )); + ]); } /** - * @param array $record - * @return array + * @param mixed[] $record + * @return mixed[] */ - protected function filterEmptyFields(array $record) + protected function filterEmptyFields(array $record): array { return array_filter($record, function ($value) { return !empty($value) || false === $value || 0 === $value; @@ -99,9 +95,9 @@ protected function filterEmptyFields(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new ScalarFormatter(self::DATE_FORMAT); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php deleted file mode 100644 index bb0f83eb..00000000 --- a/vendor/monolog/monolog/src/Monolog/Handler/ElasticSearchHandler.php +++ /dev/null @@ -1,128 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\FormatterInterface; -use Monolog\Formatter\ElasticaFormatter; -use Monolog\Logger; -use Elastica\Client; -use Elastica\Exception\ExceptionInterface; - -/** - * Elastic Search handler - * - * Usage example: - * - * $client = new \Elastica\Client(); - * $options = array( - * 'index' => 'elastic_index_name', - * 'type' => 'elastic_doc_type', - * ); - * $handler = new ElasticSearchHandler($client, $options); - * $log = new Logger('application'); - * $log->pushHandler($handler); - * - * @author Jelle Vink - */ -class ElasticSearchHandler extends AbstractProcessingHandler -{ - /** - * @var Client - */ - protected $client; - - /** - * @var array Handler config options - */ - protected $options = array(); - - /** - * @param Client $client Elastica Client object - * @param array $options Handler configuration - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - */ - public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true) - { - parent::__construct($level, $bubble); - $this->client = $client; - $this->options = array_merge( - array( - 'index' => 'monolog', // Elastic index name - 'type' => 'record', // Elastic document type - 'ignore_error' => false, // Suppress Elastica exceptions - ), - $options - ); - } - - /** - * {@inheritDoc} - */ - protected function write(array $record) - { - $this->bulkSend(array($record['formatted'])); - } - - /** - * {@inheritdoc} - */ - public function setFormatter(FormatterInterface $formatter) - { - if ($formatter instanceof ElasticaFormatter) { - return parent::setFormatter($formatter); - } - throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter'); - } - - /** - * Getter options - * @return array - */ - public function getOptions() - { - return $this->options; - } - - /** - * {@inheritDoc} - */ - protected function getDefaultFormatter() - { - return new ElasticaFormatter($this->options['index'], $this->options['type']); - } - - /** - * {@inheritdoc} - */ - public function handleBatch(array $records) - { - $documents = $this->getFormatter()->formatBatch($records); - $this->bulkSend($documents); - } - - /** - * Use Elasticsearch bulk API to send list of documents - * @param array $documents - * @throws \RuntimeException - */ - protected function bulkSend(array $documents) - { - try { - $this->client->addDocuments($documents); - } catch (ExceptionInterface $e) { - if (!$this->options['ignore_error']) { - throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e); - } - } - } -} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ElasticaHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ElasticaHandler.php new file mode 100644 index 00000000..fc92ca42 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ElasticaHandler.php @@ -0,0 +1,129 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Elastica\Document; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\ElasticaFormatter; +use Monolog\Logger; +use Elastica\Client; +use Elastica\Exception\ExceptionInterface; + +/** + * Elastic Search handler + * + * Usage example: + * + * $client = new \Elastica\Client(); + * $options = array( + * 'index' => 'elastic_index_name', + * 'type' => 'elastic_doc_type', Types have been removed in Elastica 7 + * ); + * $handler = new ElasticaHandler($client, $options); + * $log = new Logger('application'); + * $log->pushHandler($handler); + * + * @author Jelle Vink + */ +class ElasticaHandler extends AbstractProcessingHandler +{ + /** + * @var Client + */ + protected $client; + + /** + * @var mixed[] Handler config options + */ + protected $options = []; + + /** + * @param Client $client Elastica Client object + * @param mixed[] $options Handler configuration + */ + public function __construct(Client $client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) + { + parent::__construct($level, $bubble); + $this->client = $client; + $this->options = array_merge( + [ + 'index' => 'monolog', // Elastic index name + 'type' => 'record', // Elastic document type + 'ignore_error' => false, // Suppress Elastica exceptions + ], + $options + ); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record): void + { + $this->bulkSend([$record['formatted']]); + } + + /** + * {@inheritDoc} + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + if ($formatter instanceof ElasticaFormatter) { + return parent::setFormatter($formatter); + } + + throw new \InvalidArgumentException('ElasticaHandler is only compatible with ElasticaFormatter'); + } + + /** + * @return mixed[] + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new ElasticaFormatter($this->options['index'], $this->options['type']); + } + + /** + * {@inheritDoc} + */ + public function handleBatch(array $records): void + { + $documents = $this->getFormatter()->formatBatch($records); + $this->bulkSend($documents); + } + + /** + * Use Elasticsearch bulk API to send list of documents + * + * @param Document[] $documents + * + * @throws \RuntimeException + */ + protected function bulkSend(array $documents): void + { + try { + $this->client->addDocuments($documents); + } catch (ExceptionInterface $e) { + if (!$this->options['ignore_error']) { + throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e); + } + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ElasticsearchHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ElasticsearchHandler.php new file mode 100644 index 00000000..e88375c0 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ElasticsearchHandler.php @@ -0,0 +1,218 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Elastic\Elasticsearch\Response\Elasticsearch; +use Throwable; +use RuntimeException; +use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\ElasticsearchFormatter; +use InvalidArgumentException; +use Elasticsearch\Common\Exceptions\RuntimeException as ElasticsearchRuntimeException; +use Elasticsearch\Client; +use Elastic\Elasticsearch\Exception\InvalidArgumentException as ElasticInvalidArgumentException; +use Elastic\Elasticsearch\Client as Client8; + +/** + * Elasticsearch handler + * + * @link https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/index.html + * + * Simple usage example: + * + * $client = \Elasticsearch\ClientBuilder::create() + * ->setHosts($hosts) + * ->build(); + * + * $options = array( + * 'index' => 'elastic_index_name', + * 'type' => 'elastic_doc_type', + * ); + * $handler = new ElasticsearchHandler($client, $options); + * $log = new Logger('application'); + * $log->pushHandler($handler); + * + * @author Avtandil Kikabidze + */ +class ElasticsearchHandler extends AbstractProcessingHandler +{ + /** + * @var Client|Client8 + */ + protected $client; + + /** + * @var mixed[] Handler config options + */ + protected $options = []; + + /** + * @var bool + */ + private $needsType; + + /** + * @param Client|Client8 $client Elasticsearch Client object + * @param mixed[] $options Handler configuration + */ + public function __construct($client, array $options = [], $level = Logger::DEBUG, bool $bubble = true) + { + if (!$client instanceof Client && !$client instanceof Client8) { + throw new \TypeError('Elasticsearch\Client or Elastic\Elasticsearch\Client instance required'); + } + + parent::__construct($level, $bubble); + $this->client = $client; + $this->options = array_merge( + [ + 'index' => 'monolog', // Elastic index name + 'type' => '_doc', // Elastic document type + 'ignore_error' => false, // Suppress Elasticsearch exceptions + ], + $options + ); + + if ($client instanceof Client8 || $client::VERSION[0] === '7') { + $this->needsType = false; + // force the type to _doc for ES8/ES7 + $this->options['type'] = '_doc'; + } else { + $this->needsType = true; + } + } + + /** + * {@inheritDoc} + */ + protected function write(array $record): void + { + $this->bulkSend([$record['formatted']]); + } + + /** + * {@inheritDoc} + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + if ($formatter instanceof ElasticsearchFormatter) { + return parent::setFormatter($formatter); + } + + throw new InvalidArgumentException('ElasticsearchHandler is only compatible with ElasticsearchFormatter'); + } + + /** + * Getter options + * + * @return mixed[] + */ + public function getOptions(): array + { + return $this->options; + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new ElasticsearchFormatter($this->options['index'], $this->options['type']); + } + + /** + * {@inheritDoc} + */ + public function handleBatch(array $records): void + { + $documents = $this->getFormatter()->formatBatch($records); + $this->bulkSend($documents); + } + + /** + * Use Elasticsearch bulk API to send list of documents + * + * @param array[] $records Records + _index/_type keys + * @throws \RuntimeException + */ + protected function bulkSend(array $records): void + { + try { + $params = [ + 'body' => [], + ]; + + foreach ($records as $record) { + $params['body'][] = [ + 'index' => $this->needsType ? [ + '_index' => $record['_index'], + '_type' => $record['_type'], + ] : [ + '_index' => $record['_index'], + ], + ]; + unset($record['_index'], $record['_type']); + + $params['body'][] = $record; + } + + /** @var Elasticsearch */ + $responses = $this->client->bulk($params); + + if ($responses['errors'] === true) { + throw $this->createExceptionFromResponses($responses); + } + } catch (Throwable $e) { + if (! $this->options['ignore_error']) { + throw new RuntimeException('Error sending messages to Elasticsearch', 0, $e); + } + } + } + + /** + * Creates elasticsearch exception from responses array + * + * Only the first error is converted into an exception. + * + * @param mixed[]|Elasticsearch $responses returned by $this->client->bulk() + */ + protected function createExceptionFromResponses($responses): Throwable + { + foreach ($responses['items'] ?? [] as $item) { + if (isset($item['index']['error'])) { + return $this->createExceptionFromError($item['index']['error']); + } + } + + if (class_exists(ElasticInvalidArgumentException::class)) { + return new ElasticInvalidArgumentException('Elasticsearch failed to index one or more records.'); + } + + return new ElasticsearchRuntimeException('Elasticsearch failed to index one or more records.'); + } + + /** + * Creates elasticsearch exception from error array + * + * @param mixed[] $error + */ + protected function createExceptionFromError(array $error): Throwable + { + $previous = isset($error['caused_by']) ? $this->createExceptionFromError($error['caused_by']) : null; + + if (class_exists(ElasticInvalidArgumentException::class)) { + return new ElasticInvalidArgumentException($error['type'] . ': ' . $error['reason'], 0, $previous); + } + + return new ElasticsearchRuntimeException($error['type'] . ': ' . $error['reason'], 0, $previous); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php index b2986b0f..f2e22036 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ErrorLogHandler.php @@ -1,4 +1,4 @@ -expandNewlines) { - $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); - foreach ($lines as $line) { - error_log($line, $this->messageType); - } - } else { + if (!$this->expandNewlines) { error_log((string) $record['formatted'], $this->messageType); + + return; + } + + $lines = preg_split('{[\r\n]+}', (string) $record['formatted']); + if ($lines === false) { + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to preg_split formatted string: ' . $pcreErrorCode . ' / '. Utils::pcreLastErrorMessage($pcreErrorCode)); + } + foreach ($lines as $line) { + error_log($line, $this->messageType); } } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FallbackGroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FallbackGroupHandler.php new file mode 100644 index 00000000..d4e234ce --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/FallbackGroupHandler.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Throwable; + +/** + * Forwards records to at most one handler + * + * If a handler fails, the exception is suppressed and the record is forwarded to the next handler. + * + * As soon as one handler handles a record successfully, the handling stops there. + * + * @phpstan-import-type Record from \Monolog\Logger + */ +class FallbackGroupHandler extends GroupHandler +{ + /** + * {@inheritDoc} + */ + public function handle(array $record): bool + { + if ($this->processors) { + /** @var Record $record */ + $record = $this->processRecord($record); + } + foreach ($this->handlers as $handler) { + try { + $handler->handle($record); + break; + } catch (Throwable $e) { + // What throwable? + } + } + + return false === $this->bubble; + } + + /** + * {@inheritDoc} + */ + public function handleBatch(array $records): void + { + if ($this->processors) { + $processed = []; + foreach ($records as $record) { + $processed[] = $this->processRecord($record); + } + /** @var Record[] $records */ + $records = $processed; + } + + foreach ($this->handlers as $handler) { + try { + $handler->handleBatch($records); + break; + } catch (Throwable $e) { + // What throwable? + } + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php index 949f2271..718f17ef 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FilterHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ -class FilterHandler extends AbstractHandler +class FilterHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface { + use ProcessableHandlerTrait; + /** * Handler or factory callable($record, $this) * - * @var callable|\Monolog\Handler\HandlerInterface + * @var callable|HandlerInterface + * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface */ protected $handler; @@ -35,6 +44,7 @@ class FilterHandler extends AbstractHandler * Minimum level for logs that are passed to handler * * @var int[] + * @phpstan-var array */ protected $acceptedLevels; @@ -46,12 +56,17 @@ class FilterHandler extends AbstractHandler protected $bubble; /** + * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler + * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $filterHandler). * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided - * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array + * @param int|string $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * + * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList + * @phpstan-param Level|LevelName|LogLevel::* $maxLevel */ - public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true) + public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, bool $bubble = true) { $this->handler = $handler; $this->bubble = $bubble; @@ -63,9 +78,9 @@ public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel } /** - * @return array + * @phpstan-return array */ - public function getAcceptedLevels() + public function getAcceptedLevels(): array { return array_flip($this->acceptedLevels); } @@ -73,8 +88,11 @@ public function getAcceptedLevels() /** * @param int|string|array $minLevelOrList A list of levels to accept or a minimum level or level name if maxLevel is provided * @param int|string $maxLevel Maximum level or level name to accept, only used if $minLevelOrList is not an array + * + * @phpstan-param Level|LevelName|LogLevel::*|array $minLevelOrList + * @phpstan-param Level|LevelName|LogLevel::* $maxLevel */ - public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY) + public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY): self { if (is_array($minLevelOrList)) { $acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList); @@ -86,29 +104,30 @@ public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = L })); } $this->acceptedLevels = array_flip($acceptedLevels); + + return $this; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return isset($this->acceptedLevels[$record['level']]); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; } if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + /** @var Record $record */ + $record = $this->processRecord($record); } $this->getHandler($record)->handle($record); @@ -117,11 +136,11 @@ public function handle(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { - $filtered = array(); + $filtered = []; foreach ($records as $record) { if ($this->isHandling($record)) { $filtered[] = $record; @@ -139,11 +158,13 @@ public function handleBatch(array $records) * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @return HandlerInterface + * + * @phpstan-param Record $record */ public function getHandler(array $record = null) { if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); + $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } @@ -153,20 +174,39 @@ public function getHandler(array $record = null) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->getHandler()->setFormatter($formatter); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->getHandler()->getFormatter(); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + return $handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); + } + + public function reset() + { + $this->resetProcessors(); + + if ($this->getHandler() instanceof ResettableInterface) { + $this->getHandler()->reset(); + } } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php index aaca12cc..0aa5607b 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ActivationStrategyInterface.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ActivationStrategyInterface { /** * Returns whether the given record activates the handler. * - * @param array $record - * @return bool + * @phpstan-param Record $record */ - public function isHandlerActivated(array $record); + public function isHandlerActivated(array $record): bool; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php index 2a2a64d9..7b9abb58 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ChannelLevelActivationStrategy.php @@ -1,4 +1,4 @@ - * * @author Mike Meessen + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class ChannelLevelActivationStrategy implements ActivationStrategyInterface { + /** + * @var Level + */ private $defaultActionLevel; + + /** + * @var array + */ private $channelToActionLevel; /** - * @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any - * @param array $channelToActionLevel An array that maps channel names to action levels. + * @param int|string $defaultActionLevel The default action level to be used if the record's category doesn't match any + * @param array $channelToActionLevel An array that maps channel names to action levels. + * + * @phpstan-param array $channelToActionLevel + * @phpstan-param Level|LevelName|LogLevel::* $defaultActionLevel */ - public function __construct($defaultActionLevel, $channelToActionLevel = array()) + public function __construct($defaultActionLevel, array $channelToActionLevel = []) { $this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel); $this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel); } - public function isHandlerActivated(array $record) + /** + * @phpstan-param Record $record + */ + public function isHandlerActivated(array $record): bool { if (isset($this->channelToActionLevel[$record['channel']])) { return $record['level'] >= $this->channelToActionLevel[$record['channel']]; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php index 6e630852..5ec88eab 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossed/ErrorLevelActivationStrategy.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class ErrorLevelActivationStrategy implements ActivationStrategyInterface { + /** + * @var Level + */ private $actionLevel; + /** + * @param int|string $actionLevel Level or name or value + * + * @phpstan-param Level|LevelName|LogLevel::* $actionLevel + */ public function __construct($actionLevel) { $this->actionLevel = Logger::toMonologLevel($actionLevel); } - public function isHandlerActivated(array $record) + public function isHandlerActivated(array $record): bool { return $record['level'] >= $this->actionLevel; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php index cdabc445..0627b445 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FingersCrossedHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ -class FingersCrossedHandler extends AbstractHandler +class FingersCrossedHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface, FormattableHandlerInterface { + use ProcessableHandlerTrait; + + /** + * @var callable|HandlerInterface + * @phpstan-var callable(?Record, HandlerInterface): HandlerInterface|HandlerInterface + */ protected $handler; + /** @var ActivationStrategyInterface */ protected $activationStrategy; + /** @var bool */ protected $buffering = true; + /** @var int */ protected $bufferSize; - protected $buffer = array(); + /** @var Record[] */ + protected $buffer = []; + /** @var bool */ protected $stopBuffering; + /** + * @var ?int + * @phpstan-var ?Level + */ protected $passthruLevel; + /** @var bool */ + protected $bubble; /** - * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). - * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action - * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true) - * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + * @psalm-param HandlerInterface|callable(?Record, HandlerInterface): HandlerInterface $handler + * + * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $fingersCrossedHandler). + * @param int|string|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action, or a level name/value at which the handler is activated + * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true) + * @param int|string $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered + * + * @phpstan-param Level|LevelName|LogLevel::* $passthruLevel + * @phpstan-param Level|LevelName|LogLevel::*|ActivationStrategyInterface $activationStrategy */ - public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null) + public function __construct($handler, $activationStrategy = null, int $bufferSize = 0, bool $bubble = true, bool $stopBuffering = true, $passthruLevel = null) { if (null === $activationStrategy) { $activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING); @@ -74,9 +105,9 @@ public function __construct($handler, $activationStrategy = null, $bufferSize = } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return true; } @@ -84,24 +115,24 @@ public function isHandling(array $record) /** * Manually activate this logger regardless of the activation strategy */ - public function activate() + public function activate(): void { if ($this->stopBuffering) { $this->buffering = false; } + $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); - $this->buffer = array(); + $this->buffer = []; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + /** @var Record $record */ + $record = $this->processRecord($record); } if ($this->buffering) { @@ -120,18 +151,20 @@ public function handle(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function close() + public function close(): void { $this->flushBuffer(); + + $this->getHandler()->close(); } public function reset() { $this->flushBuffer(); - parent::reset(); + $this->resetProcessors(); if ($this->getHandler() instanceof ResettableInterface) { $this->getHandler()->reset(); @@ -143,16 +176,16 @@ public function reset() * * It also resets the handler to its initial buffering state. */ - public function clear() + public function clear(): void { - $this->buffer = array(); + $this->buffer = []; $this->reset(); } /** * Resets the state of the handler. Stops forwarding records to the wrapped handler. */ - private function flushBuffer() + private function flushBuffer(): void { if (null !== $this->passthruLevel) { $level = $this->passthruLevel; @@ -160,11 +193,11 @@ private function flushBuffer() return $record['level'] >= $level; }); if (count($this->buffer) > 0) { - $this->getHandler(end($this->buffer) ?: null)->handleBatch($this->buffer); + $this->getHandler(end($this->buffer))->handleBatch($this->buffer); } } - $this->buffer = array(); + $this->buffer = []; $this->buffering = true; } @@ -174,11 +207,13 @@ private function flushBuffer() * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * * @return HandlerInterface + * + * @phpstan-param Record $record */ public function getHandler(array $record = null) { if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); + $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } @@ -188,20 +223,30 @@ public function getHandler(array $record = null) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->getHandler()->setFormatter($formatter); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->getHandler()->getFormatter(); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + return $handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php index 2a171bd8..72718de6 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FirePHPHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FirePHPHandler extends AbstractProcessingHandler { + use WebRequestRecognizerTrait; + /** * WildFire JSON header message format */ - const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; + protected const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2'; /** * FirePHP structure for parsing messages & their presentation */ - const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; + protected const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'; /** * Must reference a "known" plugin, otherwise headers won't display in FirePHP */ - const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; + protected const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3'; /** * Header prefix for Wildfire to recognize & parse headers */ - const HEADER_PREFIX = 'X-Wf'; + protected const HEADER_PREFIX = 'X-Wf'; /** * Whether or not Wildfire vendor-specific headers have been generated & sent yet + * @var bool */ protected static $initialized = false; @@ -51,35 +57,43 @@ class FirePHPHandler extends AbstractProcessingHandler */ protected static $messageIndex = 1; + /** @var bool */ protected static $sendHeaders = true; /** * Base header creation function used by init headers & record headers * - * @param array $meta Wildfire Plugin, Protocol & Structure Indexes - * @param string $message Log message - * @return array Complete header string ready for the client as key and message as value + * @param array $meta Wildfire Plugin, Protocol & Structure Indexes + * @param string $message Log message + * + * @return array Complete header string ready for the client as key and message as value + * + * @phpstan-return non-empty-array */ - protected function createHeader(array $meta, $message) + protected function createHeader(array $meta, string $message): array { - $header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta)); + $header = sprintf('%s-%s', static::HEADER_PREFIX, join('-', $meta)); - return array($header => $message); + return [$header => $message]; } /** * Creates message header from record * + * @return array + * + * @phpstan-return non-empty-array + * * @see createHeader() - * @param array $record - * @return array + * + * @phpstan-param FormattedRecord $record */ - protected function createRecordHeader(array $record) + protected function createRecordHeader(array $record): array { // Wildfire is extensible to support multiple protocols & plugins in a single request, // but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake. return $this->createHeader( - array(1, 1, 1, self::$messageIndex++), + [1, 1, 1, self::$messageIndex++], $record['formatted'] ); } @@ -87,7 +101,7 @@ protected function createRecordHeader(array $record) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new WildfireFormatter(); } @@ -97,25 +111,23 @@ protected function getDefaultFormatter() * * @see createHeader() * @see sendHeader() - * @return array + * + * @return array */ - protected function getInitHeaders() + protected function getInitHeaders(): array { // Initial payload consists of required headers for Wildfire return array_merge( - $this->createHeader(array('Protocol', 1), self::PROTOCOL_URI), - $this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI), - $this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI) + $this->createHeader(['Protocol', 1], static::PROTOCOL_URI), + $this->createHeader([1, 'Structure', 1], static::STRUCTURE_URI), + $this->createHeader([1, 'Plugin', 1], static::PLUGIN_URI) ); } /** * Send header string to the client - * - * @param string $header - * @param string $content */ - protected function sendHeader($header, $content) + protected function sendHeader(string $header, string $content): void { if (!headers_sent() && self::$sendHeaders) { header(sprintf('%s: %s', $header, $content)); @@ -127,11 +139,10 @@ protected function sendHeader($header, $content) * * @see sendHeader() * @see sendInitHeaders() - * @param array $record */ - protected function write(array $record) + protected function write(array $record): void { - if (!self::$sendHeaders) { + if (!self::$sendHeaders || !$this->isWebRequest()) { return; } @@ -157,10 +168,8 @@ protected function write(array $record) /** * Verifies if the headers are accepted by the current user agent - * - * @return bool */ - protected function headersAccepted() + protected function headersAccepted(): bool { if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) { return true; @@ -168,28 +177,4 @@ protected function headersAccepted() return isset($_SERVER['HTTP_X_FIREPHP_VERSION']); } - - /** - * BC getter for the sendHeaders property that has been made static - */ - public function __get($property) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - return static::$sendHeaders; - } - - /** - * BC setter for the sendHeaders property that has been made static - */ - public function __set($property, $value) - { - if ('sendHeaders' !== $property) { - throw new \InvalidArgumentException('Undefined property '.$property); - } - - static::$sendHeaders = $value; - } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php index c43c0134..85c95b9d 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FleepHookHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class FleepHookHandler extends SocketHandler { - const FLEEP_HOST = 'fleep.io'; + protected const FLEEP_HOST = 'fleep.io'; - const FLEEP_HOOK_URI = '/hook/'; + protected const FLEEP_HOOK_URI = '/hook/'; /** * @var string Webhook token (specifies the conversation where logs are sent) @@ -40,20 +43,35 @@ class FleepHookHandler extends SocketHandler * see https://fleep.io/integrations/webhooks/ * * @param string $token Webhook token - * @param bool|int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not * @throws MissingExtensionException */ - public function __construct($token, $level = Logger::DEBUG, $bubble = true) - { + public function __construct( + string $token, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler'); } $this->token = $token; - $connectionString = 'ssl://' . self::FLEEP_HOST . ':443'; - parent::__construct($connectionString, $level, $bubble); + $connectionString = 'ssl://' . static::FLEEP_HOST . ':443'; + parent::__construct( + $connectionString, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); } /** @@ -63,29 +81,24 @@ public function __construct($token, $level = Logger::DEBUG, $bubble = true) * * @return LineFormatter */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter(null, null, true, true); } /** * Handles a log record - * - * @param array $record */ - public function write(array $record) + public function write(array $record): void { parent::write($record); $this->closeSocket(); } /** - * {@inheritdoc} - * - * @param array $record - * @return string + * {@inheritDoc} */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -94,14 +107,11 @@ protected function generateDataStream($record) /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { - $header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; - $header .= "Host: " . self::FLEEP_HOST . "\r\n"; + $header = "POST " . static::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n"; + $header .= "Host: " . static::FLEEP_HOST . "\r\n"; $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; $header .= "Content-Length: " . strlen($content) . "\r\n"; $header .= "\r\n"; @@ -112,14 +122,13 @@ private function buildHeader($content) /** * Builds the body of API call * - * @param array $record - * @return string + * @phpstan-param FormattedRecord $record */ - private function buildContent($record) + private function buildContent(array $record): string { - $dataArray = array( + $dataArray = [ 'message' => $record['formatted'], - ); + ]; return http_build_query($dataArray); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php index f0f010cb..5715d580 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FlowdockHandler.php @@ -1,4 +1,4 @@ - * @see https://www.flowdock.com/api/push + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler + * @deprecated Since 2.9.0 and 3.3.0, Flowdock was shutdown we will thus drop this handler in Monolog 4 */ class FlowdockHandler extends SocketHandler { @@ -35,26 +38,39 @@ class FlowdockHandler extends SocketHandler protected $apiToken; /** - * @param string $apiToken - * @param bool|int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * * @throws MissingExtensionException if OpenSSL is missing */ - public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true) - { + public function __construct( + string $apiToken, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); } - parent::__construct('ssl://api.flowdock.com:443', $level, $bubble); + parent::__construct( + 'ssl://api.flowdock.com:443', + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->apiToken = $apiToken; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { if (!$formatter instanceof FlowdockFormatter) { throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\Formatter\FlowdockFormatter to function correctly'); @@ -65,20 +81,16 @@ public function setFormatter(FormatterInterface $formatter) /** * Gets the default formatter. - * - * @return FormatterInterface */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\Formatter\FlowdockFormatter to function correctly'); } /** - * {@inheritdoc} - * - * @param array $record + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { parent::write($record); @@ -86,12 +98,9 @@ protected function write(array $record) } /** - * {@inheritdoc} - * - * @param array $record - * @return string + * {@inheritDoc} */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -101,21 +110,17 @@ protected function generateDataStream($record) /** * Builds the body of API call * - * @param array $record - * @return string + * @phpstan-param FormattedRecord $record */ - private function buildContent($record) + private function buildContent(array $record): string { return Utils::jsonEncode($record['formatted']['flowdock']); } /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; $header .= "Host: api.flowdock.com\r\n"; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php index 3e2f1b28..fc1693cd 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerInterface.php @@ -16,8 +16,6 @@ /** * Interface to describe loggers that have a formatter * - * This interface is present in monolog 1.x to ease forward compatibility. - * * @author Jordi Boggiano */ interface FormattableHandlerInterface diff --git a/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php index e9ec5e77..b60bdce0 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/FormattableHandlerTrait.php @@ -17,20 +17,17 @@ /** * Helper trait for implementing FormattableInterface * - * This trait is present in monolog 1.x to ease forward compatibility. - * * @author Jordi Boggiano */ trait FormattableHandlerTrait { /** - * @var FormatterInterface + * @var ?FormatterInterface */ protected $formatter; /** - * {@inheritdoc} - * @suppress PhanTypeMismatchReturn + * {@inheritDoc} */ public function setFormatter(FormatterInterface $formatter): HandlerInterface { @@ -40,7 +37,7 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function getFormatter(): FormatterInterface { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php index b6cde7c6..4ff26c4c 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/GelfHandler.php @@ -1,4 +1,4 @@ -publisher = $publisher; } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->publisher->publish($record['formatted']); } @@ -58,7 +50,7 @@ protected function write(array $record) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new GelfMessageFormatter(); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php index 0d461f9c..3c9dc4b3 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/GroupHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ -class GroupHandler extends AbstractHandler +class GroupHandler extends Handler implements ProcessableHandlerInterface, ResettableInterface { + use ProcessableHandlerTrait; + + /** @var HandlerInterface[] */ protected $handlers; + /** @var bool */ + protected $bubble; /** - * @param array $handlers Array of Handlers. - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param HandlerInterface[] $handlers Array of Handlers. + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct(array $handlers, $bubble = true) + public function __construct(array $handlers, bool $bubble = true) { foreach ($handlers as $handler) { if (!$handler instanceof HandlerInterface) { @@ -40,9 +47,9 @@ public function __construct(array $handlers, $bubble = true) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { @@ -54,14 +61,13 @@ public function isHandling(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + /** @var Record $record */ + $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { @@ -72,18 +78,16 @@ public function handle(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if ($this->processors) { - $processed = array(); + $processed = []; foreach ($records as $record) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - $processed[] = $record; + $processed[] = $this->processRecord($record); } + /** @var Record[] $records */ $records = $processed; } @@ -94,7 +98,7 @@ public function handleBatch(array $records) public function reset() { - parent::reset(); + $this->resetProcessors(); foreach ($this->handlers as $handler) { if ($handler instanceof ResettableInterface) { @@ -103,13 +107,24 @@ public function reset() } } + public function close(): void + { + parent::close(); + + foreach ($this->handlers as $handler) { + $handler->close(); + } + } + /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { foreach ($this->handlers as $handler) { - $handler->setFormatter($formatter); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); + } } return $this; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/Handler.php b/vendor/monolog/monolog/src/Monolog/Handler/Handler.php new file mode 100644 index 00000000..34b4935d --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/Handler.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * Base Handler class providing basic close() support as well as handleBatch + * + * @author Jordi Boggiano + */ +abstract class Handler implements HandlerInterface +{ + /** + * {@inheritDoc} + */ + public function handleBatch(array $records): void + { + foreach ($records as $record) { + $this->handle($record); + } + } + + /** + * {@inheritDoc} + */ + public function close(): void + { + } + + public function __destruct() + { + try { + $this->close(); + } catch (\Throwable $e) { + // do nothing + } + } + + public function __sleep() + { + $this->close(); + + $reflClass = new \ReflectionClass($this); + + $keys = []; + foreach ($reflClass->getProperties() as $reflProp) { + if (!$reflProp->isStatic()) { + $keys[] = $reflProp->getName(); + } + } + + return $keys; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php index 8d5a4a09..affcc51f 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/HandlerInterface.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ interface HandlerInterface { @@ -32,8 +33,10 @@ interface HandlerInterface * @param array $record Partial log record containing only a level key * * @return bool + * + * @phpstan-param array{level: Level} $record */ - public function isHandling(array $record); + public function isHandling(array $record): bool; /** * Handles a record. @@ -45,46 +48,38 @@ public function isHandling(array $record); * Unless the bubbling is interrupted (by returning true), the Logger class will keep on * calling further handlers in the stack with a given log record. * - * @param array $record The record to handle - * @return bool true means that this handler handled the record, and that bubbling is not permitted. - * false means the record was either not processed or that this handler allows bubbling. + * @param array $record The record to handle + * @return bool true means that this handler handled the record, and that bubbling is not permitted. + * false means the record was either not processed or that this handler allows bubbling. + * + * @phpstan-param Record $record */ - public function handle(array $record); + public function handle(array $record): bool; /** * Handles a set of records at once. * * @param array $records The records to handle (an array of record arrays) - */ - public function handleBatch(array $records); - - /** - * Adds a processor in the stack. * - * @param callable $callback - * @return self + * @phpstan-param Record[] $records */ - public function pushProcessor($callback); + public function handleBatch(array $records): void; /** - * Removes the processor on top of the stack and returns it. + * Closes the handler. * - * @return callable - */ - public function popProcessor(); - - /** - * Sets the formatter. + * Ends a log cycle and frees all resources used by the handler. * - * @param FormatterInterface $formatter - * @return self - */ - public function setFormatter(FormatterInterface $formatter); - - /** - * Gets the formatter. + * Closing a Handler means flushing all buffers and freeing any open resources/handles. + * + * Implementations have to be idempotent (i.e. it should be possible to call close several times without breakage) + * and ideally handlers should be able to reopen themselves on handle() after they have been closed. + * + * This is useful at the end of a request and will be called automatically when the object + * is destroyed if you extend Monolog\Handler\Handler. * - * @return FormatterInterface + * If you are thinking of calling this method yourself, most likely you should be + * calling ResettableInterface::reset instead. Have a look. */ - public function getFormatter(); + public function close(): void; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php b/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php index 55e64986..d4351b9f 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/HandlerWrapper.php @@ -1,4 +1,4 @@ - */ -class HandlerWrapper implements HandlerInterface, ResettableInterface +class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, FormattableHandlerInterface, ResettableInterface { /** * @var HandlerInterface */ protected $handler; - /** - * HandlerWrapper constructor. - * @param HandlerInterface $handler - */ public function __construct(HandlerInterface $handler) { $this->handler = $handler; } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return $this->handler->isHandling($record); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { return $this->handler->handle($record); } /** - * {@inheritdoc} + * {@inheritDoc} + */ + public function handleBatch(array $records): void + { + $this->handler->handleBatch($records); + } + + /** + * {@inheritDoc} */ - public function handleBatch(array $records) + public function close(): void { - return $this->handler->handleBatch($records); + $this->handler->close(); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function pushProcessor($callback) + public function pushProcessor(callable $callback): HandlerInterface { - $this->handler->pushProcessor($callback); + if ($this->handler instanceof ProcessableHandlerInterface) { + $this->handler->pushProcessor($callback); - return $this; + return $this; + } + + throw new \LogicException('The wrapped handler does not implement ' . ProcessableHandlerInterface::class); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function popProcessor() + public function popProcessor(): callable { - return $this->handler->popProcessor(); + if ($this->handler instanceof ProcessableHandlerInterface) { + return $this->handler->popProcessor(); + } + + throw new \LogicException('The wrapped handler does not implement ' . ProcessableHandlerInterface::class); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->handler->setFormatter($formatter); + if ($this->handler instanceof FormattableHandlerInterface) { + $this->handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->handler->getFormatter(); + if ($this->handler instanceof FormattableHandlerInterface) { + return $this->handler->getFormatter(); + } + + throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class); } public function reset() { if ($this->handler instanceof ResettableInterface) { - return $this->handler->reset(); + $this->handler->reset(); } } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php deleted file mode 100644 index 30258e36..00000000 --- a/vendor/monolog/monolog/src/Monolog/Handler/HipChatHandler.php +++ /dev/null @@ -1,367 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; - -/** - * Sends notifications through the hipchat api to a hipchat room - * - * Notes: - * API token - HipChat API token - * Room - HipChat Room Id or name, where messages are sent - * Name - Name used to send the message (from) - * notify - Should the message trigger a notification in the clients - * version - The API version to use (HipChatHandler::API_V1 | HipChatHandler::API_V2) - * - * @author Rafael Dohms - * @see https://www.hipchat.com/docs/api - */ -class HipChatHandler extends SocketHandler -{ - /** - * Use API version 1 - */ - const API_V1 = 'v1'; - - /** - * Use API version v2 - */ - const API_V2 = 'v2'; - - /** - * The maximum allowed length for the name used in the "from" field. - */ - const MAXIMUM_NAME_LENGTH = 15; - - /** - * The maximum allowed length for the message. - */ - const MAXIMUM_MESSAGE_LENGTH = 9500; - - /** - * @var string - */ - private $token; - - /** - * @var string - */ - private $room; - - /** - * @var string - */ - private $name; - - /** - * @var bool - */ - private $notify; - - /** - * @var string - */ - private $format; - - /** - * @var string - */ - private $host; - - /** - * @var string - */ - private $version; - - /** - * @param string $token HipChat API Token - * @param string $room The room that should be alerted of the message (Id or Name) - * @param string $name Name used in the "from" field. - * @param bool $notify Trigger a notification in clients or not - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param bool $useSSL Whether to connect via SSL. - * @param string $format The format of the messages (default to text, can be set to html if you have html in the messages) - * @param string $host The HipChat server hostname. - * @param string $version The HipChat API version (default HipChatHandler::API_V1) - */ - public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1) - { - @trigger_error('The Monolog\Handler\HipChatHandler class is deprecated. You should migrate to Slack and the SlackWebhookHandler / SlackbotHandler, see https://www.atlassian.com/partnerships/slack', E_USER_DEPRECATED); - - if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) { - throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.'); - } - - $connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80'; - parent::__construct($connectionString, $level, $bubble); - - $this->token = $token; - $this->name = $name; - $this->notify = $notify; - $this->room = $room; - $this->format = $format; - $this->host = $host; - $this->version = $version; - } - - /** - * {@inheritdoc} - * - * @param array $record - * @return string - */ - protected function generateDataStream($record) - { - $content = $this->buildContent($record); - - return $this->buildHeader($content) . $content; - } - - /** - * Builds the body of API call - * - * @param array $record - * @return string - */ - private function buildContent($record) - { - $dataArray = array( - 'notify' => $this->version == self::API_V1 ? - ($this->notify ? 1 : 0) : - ($this->notify ? 'true' : 'false'), - 'message' => $record['formatted'], - 'message_format' => $this->format, - 'color' => $this->getAlertColor($record['level']), - ); - - if (!$this->validateStringLength($dataArray['message'], static::MAXIMUM_MESSAGE_LENGTH)) { - if (function_exists('mb_substr')) { - $dataArray['message'] = mb_substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]'; - } else { - $dataArray['message'] = substr($dataArray['message'], 0, static::MAXIMUM_MESSAGE_LENGTH).' [truncated]'; - } - } - - // if we are using the legacy API then we need to send some additional information - if ($this->version == self::API_V1) { - $dataArray['room_id'] = $this->room; - } - - // append the sender name if it is set - // always append it if we use the v1 api (it is required in v1) - if ($this->version == self::API_V1 || $this->name !== null) { - $dataArray['from'] = (string) $this->name; - } - - return http_build_query($dataArray); - } - - /** - * Builds the header of the API Call - * - * @param string $content - * @return string - */ - private function buildHeader($content) - { - if ($this->version == self::API_V1) { - $header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n"; - } else { - // needed for rooms with special (spaces, etc) characters in the name - $room = rawurlencode($this->room); - $header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n"; - } - - $header .= "Host: {$this->host}\r\n"; - $header .= "Content-Type: application/x-www-form-urlencoded\r\n"; - $header .= "Content-Length: " . strlen($content) . "\r\n"; - $header .= "\r\n"; - - return $header; - } - - /** - * Assigns a color to each level of log records. - * - * @param int $level - * @return string - */ - protected function getAlertColor($level) - { - switch (true) { - case $level >= Logger::ERROR: - return 'red'; - case $level >= Logger::WARNING: - return 'yellow'; - case $level >= Logger::INFO: - return 'green'; - case $level == Logger::DEBUG: - return 'gray'; - default: - return 'yellow'; - } - } - - /** - * {@inheritdoc} - * - * @param array $record - */ - protected function write(array $record) - { - parent::write($record); - $this->finalizeWrite(); - } - - /** - * Finalizes the request by reading some bytes and then closing the socket - * - * If we do not read some but close the socket too early, hipchat sometimes - * drops the request entirely. - */ - protected function finalizeWrite() - { - $res = $this->getResource(); - if (is_resource($res)) { - @fread($res, 2048); - } - $this->closeSocket(); - } - - /** - * {@inheritdoc} - */ - public function handleBatch(array $records) - { - if (count($records) == 0) { - return true; - } - - $batchRecords = $this->combineRecords($records); - - $handled = false; - foreach ($batchRecords as $batchRecord) { - if ($this->isHandling($batchRecord)) { - $this->write($batchRecord); - $handled = true; - } - } - - if (!$handled) { - return false; - } - - return false === $this->bubble; - } - - /** - * Combines multiple records into one. Error level of the combined record - * will be the highest level from the given records. Datetime will be taken - * from the first record. - * - * @param array $records - * @return array - */ - private function combineRecords(array $records) - { - $batchRecord = null; - $batchRecords = array(); - $messages = array(); - $formattedMessages = array(); - $level = 0; - $levelName = null; - $datetime = null; - - foreach ($records as $record) { - $record = $this->processRecord($record); - - if ($record['level'] > $level) { - $level = $record['level']; - $levelName = $record['level_name']; - } - - if (null === $datetime) { - $datetime = $record['datetime']; - } - - $messages[] = $record['message']; - $messageStr = implode(PHP_EOL, $messages); - $formattedMessages[] = $this->getFormatter()->format($record); - $formattedMessageStr = implode('', $formattedMessages); - - $batchRecord = array( - 'message' => $messageStr, - 'formatted' => $formattedMessageStr, - 'context' => array(), - 'extra' => array(), - ); - - if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) { - // Pop the last message and implode the remaining messages - $lastMessage = array_pop($messages); - $lastFormattedMessage = array_pop($formattedMessages); - $batchRecord['message'] = implode(PHP_EOL, $messages); - $batchRecord['formatted'] = implode('', $formattedMessages); - - $batchRecords[] = $batchRecord; - $messages = array($lastMessage); - $formattedMessages = array($lastFormattedMessage); - - $batchRecord = null; - } - } - - if (null !== $batchRecord) { - $batchRecords[] = $batchRecord; - } - - // Set the max level and datetime for all records - foreach ($batchRecords as &$batchRecord) { - $batchRecord = array_merge( - $batchRecord, - array( - 'level' => $level, - 'level_name' => $levelName, - 'datetime' => $datetime, - ) - ); - } - - return $batchRecords; - } - - /** - * Validates the length of a string. - * - * If the `mb_strlen()` function is available, it will use that, as HipChat - * allows UTF-8 characters. Otherwise, it will fall back to `strlen()`. - * - * Note that this might cause false failures in the specific case of using - * a valid name with less than 16 characters, but 16 or more bytes, on a - * system where `mb_strlen()` is unavailable. - * - * @param string $str - * @param int $length - * - * @return bool - */ - private function validateStringLength($str, $length) - { - if (function_exists('mb_strlen')) { - return (mb_strlen($str) <= $length); - } - - return (strlen($str) <= $length); - } -} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php index f4d3b97e..000ccea4 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/IFTTTHandler.php @@ -1,4 +1,4 @@ -eventName = $eventName; $this->secretKey = $secretKey; @@ -45,15 +49,15 @@ public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bub } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function write(array $record) + public function write(array $record): void { - $postData = array( + $postData = [ "value1" => $record["channel"], "value2" => $record["level_name"], "value3" => $record["message"], - ); + ]; $postString = Utils::jsonEncode($postData); $ch = curl_init(); @@ -61,9 +65,9 @@ public function write(array $record) curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postString); - curl_setopt($ch, CURLOPT_HTTPHEADER, array( + curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Content-Type: application/json", - )); + ]); Curl\Util::execute($ch); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php index 8f683dce..71f64a26 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/InsightOpsHandler.php @@ -1,4 +1,4 @@ -logToken = $token; } /** - * {@inheritdoc} - * - * @param array $record - * @return string + * {@inheritDoc} */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php index ea89fb3e..25fcd159 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/LogEntriesHandler.php @@ -1,4 +1,4 @@ -logToken = $token; } /** - * {@inheritdoc} - * - * @param array $record - * @return string + * {@inheritDoc} */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { return $this->logToken . ' ' . $record['formatted']; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php index bcd62e1c..6d13db37 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php @@ -1,4 +1,4 @@ -token = $token; @@ -42,26 +59,72 @@ public function __construct($token, $level = Logger::DEBUG, $bubble = true) parent::__construct($level, $bubble); } - public function setTag($tag) + /** + * Loads and returns the shared curl handler for the given endpoint. + * + * @param string $endpoint + * + * @return resource|CurlHandle + */ + protected function getCurlHandler(string $endpoint) { - $tag = !empty($tag) ? $tag : array(); - $this->tag = is_array($tag) ? $tag : array($tag); + if (!array_key_exists($endpoint, $this->curlHandlers)) { + $this->curlHandlers[$endpoint] = $this->loadCurlHandle($endpoint); + } + + return $this->curlHandlers[$endpoint]; } - public function addTag($tag) + /** + * Starts a fresh curl session for the given endpoint and returns its handler. + * + * @param string $endpoint + * + * @return resource|CurlHandle + */ + private function loadCurlHandle(string $endpoint) + { + $url = sprintf("https://%s/%s/%s/", static::HOST, $endpoint, $this->token); + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + + return $ch; + } + + /** + * @param string[]|string $tag + */ + public function setTag($tag): self + { + $tag = !empty($tag) ? $tag : []; + $this->tag = is_array($tag) ? $tag : [$tag]; + + return $this; + } + + /** + * @param string[]|string $tag + */ + public function addTag($tag): self { if (!empty($tag)) { - $tag = is_array($tag) ? $tag : array($tag); + $tag = is_array($tag) ? $tag : [$tag]; $this->tag = array_unique(array_merge($this->tag, $tag)); } + + return $this; } - protected function write(array $record) + protected function write(array $record): void { - $this->send($record["formatted"], self::ENDPOINT_SINGLE); + $this->send($record["formatted"], static::ENDPOINT_SINGLE); } - public function handleBatch(array $records) + public function handleBatch(array $records): void { $level = $this->level; @@ -70,32 +133,27 @@ public function handleBatch(array $records) }); if ($records) { - $this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH); + $this->send($this->getFormatter()->formatBatch($records), static::ENDPOINT_BATCH); } } - protected function send($data, $endpoint) + protected function send(string $data, string $endpoint): void { - $url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token); + $ch = $this->getCurlHandler($endpoint); - $headers = array('Content-Type: application/json'); + $headers = ['Content-Type: application/json']; if (!empty($this->tag)) { $headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag); } - $ch = curl_init(); - - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - Curl\Util::execute($ch); + Curl\Util::execute($ch, 5, false); } - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LogglyFormatter(); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/LogmaticHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/LogmaticHandler.php new file mode 100644 index 00000000..859a4690 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/LogmaticHandler.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LogmaticFormatter; + +/** + * @author Julien Breux + */ +class LogmaticHandler extends SocketHandler +{ + /** + * @var string + */ + private $logToken; + + /** + * @var string + */ + private $hostname; + + /** + * @var string + */ + private $appname; + + /** + * @param string $token Log token supplied by Logmatic. + * @param string $hostname Host name supplied by Logmatic. + * @param string $appname Application name supplied by Logmatic. + * @param bool $useSSL Whether or not SSL encryption should be used. + * + * @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing + */ + public function __construct( + string $token, + string $hostname = '', + string $appname = '', + bool $useSSL = true, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { + if ($useSSL && !extension_loaded('openssl')) { + throw new MissingExtensionException('The OpenSSL PHP extension is required to use SSL encrypted connection for LogmaticHandler'); + } + + $endpoint = $useSSL ? 'ssl://api.logmatic.io:10515' : 'api.logmatic.io:10514'; + $endpoint .= '/v1/'; + + parent::__construct( + $endpoint, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); + + $this->logToken = $token; + $this->hostname = $hostname; + $this->appname = $appname; + } + + /** + * {@inheritDoc} + */ + protected function generateDataStream(array $record): string + { + return $this->logToken . ' ' . $record['formatted']; + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + $formatter = new LogmaticFormatter(); + + if (!empty($this->hostname)) { + $formatter->setHostname($this->hostname); + } + if (!empty($this->appname)) { + $formatter->setAppname($this->appname); + } + + return $formatter; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php index 9e232838..97f34320 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/MailHandler.php @@ -1,4 +1,4 @@ -level) { continue; } - $messages[] = $this->processRecord($record); + /** @var Record $message */ + $message = $this->processRecord($record); + $messages[] = $message; } if (!empty($messages)) { @@ -42,18 +49,24 @@ public function handleBatch(array $records) * * @param string $content formatted email body to be sent * @param array $records the array of log records that formed this content + * + * @phpstan-param Record[] $records */ - abstract protected function send($content, array $records); + abstract protected function send(string $content, array $records): void; /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { - $this->send((string) $record['formatted'], array($record)); + $this->send((string) $record['formatted'], [$record]); } - protected function getHighestRecord(array $records) + /** + * @phpstan-param non-empty-array $records + * @phpstan-return Record + */ + protected function getHighestRecord(array $records): array { $highestRecord = null; foreach ($records as $record) { @@ -64,4 +77,19 @@ protected function getHighestRecord(array $records) return $highestRecord; } + + protected function isHtmlBody(string $body): bool + { + return ($body[0] ?? null) === '<'; + } + + /** + * Gets the default formatter. + * + * @return FormatterInterface + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new HtmlFormatter(); + } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php index de039a86..3003500e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/MandrillHandler.php @@ -1,4 +1,4 @@ -message = $message; @@ -44,15 +48,22 @@ public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records): void { + $mime = 'text/plain'; + if ($this->isHtmlBody($content)) { + $mime = 'text/html'; + } + $message = clone $this->message; - $message->setBody($content); - if (version_compare(\Swift::VERSION, '6.0.0', '>=')) { + $message->setBody($content, $mime); + /** @phpstan-ignore-next-line */ + if (version_compare(Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { + /** @phpstan-ignore-next-line */ $message->setDate(time()); } @@ -61,11 +72,11 @@ protected function send($content, array $records) curl_setopt($ch, CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array( + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'key' => $this->apiKey, 'raw_message' => (string) $message, 'async' => false, - ))); + ])); Curl\Util::execute($ch); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php b/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php index 4724a7e2..3965aeea 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/MissingExtensionException.php @@ -1,4 +1,4 @@ - + * @author Christian Bergau */ class MissingExtensionException extends \Exception { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php index 56fe755b..30630911 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/MongoDBHandler.php @@ -1,4 +1,4 @@ -pushHandler($mongodb); * - * @author Thomas Tourlourat + * The above examples uses the MongoDB PHP library's client class; however, the + * MongoDB\Driver\Manager class from ext-mongodb is also supported. */ class MongoDBHandler extends AbstractProcessingHandler { - protected $mongoCollection; + /** @var \MongoDB\Collection */ + private $collection; + /** @var Client|Manager */ + private $manager; + /** @var string */ + private $namespace; - public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true) + /** + * Constructor. + * + * @param Client|Manager $mongodb MongoDB library or driver client + * @param string $database Database name + * @param string $collection Collection name + */ + public function __construct($mongodb, string $database, string $collection, $level = Logger::DEBUG, bool $bubble = true) { - if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo || $mongo instanceof \MongoDB\Client)) { - throw new \InvalidArgumentException('MongoClient, Mongo or MongoDB\Client instance required'); + if (!($mongodb instanceof Client || $mongodb instanceof Manager)) { + throw new \InvalidArgumentException('MongoDB\Client or MongoDB\Driver\Manager instance required'); } - $this->mongoCollection = $mongo->selectCollection($database, $collection); + if ($mongodb instanceof Client) { + $this->collection = $mongodb->selectCollection($database, $collection); + } else { + $this->manager = $mongodb; + $this->namespace = $database . '.' . $collection; + } parent::__construct($level, $bubble); } - protected function write(array $record) + protected function write(array $record): void { - if ($this->mongoCollection instanceof \MongoDB\Collection) { - $this->mongoCollection->insertOne($record["formatted"]); - } else { - $this->mongoCollection->save($record["formatted"]); + if (isset($this->collection)) { + $this->collection->insertOne($record['formatted']); + } + + if (isset($this->manager, $this->namespace)) { + $bulk = new BulkWrite; + $bulk->insert($record["formatted"]); + $this->manager->executeBulkWrite($this->namespace, $bulk); } } /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { - return new NormalizerFormatter(); + return new MongoDBFormatter; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php index d7807fd1..0c0a3bdb 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/NativeMailerHandler.php @@ -1,4 +1,4 @@ -to = is_array($to) ? $to : array($to); + $this->to = (array) $to; $this->subject = $subject; $this->addHeader(sprintf('From: %s', $from)); $this->maxColumnWidth = $maxColumnWidth; @@ -84,10 +82,9 @@ public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubbl /** * Add headers to the message * - * @param string|array $headers Custom added headers - * @return self + * @param string|string[] $headers Custom added headers */ - public function addHeader($headers) + public function addHeader($headers): self { foreach ((array) $headers as $header) { if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) { @@ -102,10 +99,9 @@ public function addHeader($headers) /** * Add parameters to the message * - * @param string|array $parameters Custom added parameters - * @return self + * @param string|string[] $parameters Custom added parameters */ - public function addParameter($parameters) + public function addParameter($parameters): self { $this->parameters = array_merge($this->parameters, (array) $parameters); @@ -113,14 +109,19 @@ public function addParameter($parameters) } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records): void { - $content = wordwrap($content, $this->maxColumnWidth); + $contentType = $this->getContentType() ?: ($this->isHtmlBody($content) ? 'text/html' : 'text/plain'); + + if ($contentType !== 'text/html') { + $content = wordwrap($content, $this->maxColumnWidth); + } + $headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n"); - $headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n"; - if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) { + $headers .= 'Content-type: ' . $contentType . '; charset=' . $this->getEncoding() . "\r\n"; + if ($contentType === 'text/html' && false === strpos($headers, 'MIME-Version:')) { $headers .= 'MIME-Version: 1.0' . "\r\n"; } @@ -136,28 +137,20 @@ protected function send($content, array $records) } } - /** - * @return string $contentType - */ - public function getContentType() + public function getContentType(): ?string { return $this->contentType; } - /** - * @return string $encoding - */ - public function getEncoding() + public function getEncoding(): string { return $this->encoding; } /** - * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML - * messages. - * @return self + * @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML messages. */ - public function setContentType($contentType) + public function setContentType(string $contentType): self { if (strpos($contentType, "\n") !== false || strpos($contentType, "\r") !== false) { throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection'); @@ -168,11 +161,7 @@ public function setContentType($contentType) return $this; } - /** - * @param string $encoding - * @return self - */ - public function setEncoding($encoding) + public function setEncoding(string $encoding): self { if (strpos($encoding, "\n") !== false || strpos($encoding, "\r") !== false) { throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection'); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php index 64dc1381..114d749e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/NewRelicHandler.php @@ -1,4 +1,4 @@ -isNewRelicEnabled()) { throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler'); @@ -87,7 +88,7 @@ protected function write(array $record) unset($record['formatted']['context']['transaction_name']); } - if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { + if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { newrelic_notice_error($record['message'], $record['context']['exception']); unset($record['formatted']['context']['exception']); } else { @@ -124,7 +125,7 @@ protected function write(array $record) * * @return bool */ - protected function isNewRelicEnabled() + protected function isNewRelicEnabled(): bool { return extension_loaded('newrelic'); } @@ -133,10 +134,9 @@ protected function isNewRelicEnabled() * Returns the appname where this log should be sent. Each log can override the default appname, set in this * handler's constructor, by providing the appname in it's context. * - * @param array $context - * @return null|string + * @param mixed[] $context */ - protected function getAppName(array $context) + protected function getAppName(array $context): ?string { if (isset($context['appname'])) { return $context['appname']; @@ -149,11 +149,9 @@ protected function getAppName(array $context) * Returns the name of the current transaction. Each log can override the default transaction name, set in this * handler's constructor, by providing the transaction_name in it's context * - * @param array $context - * - * @return null|string + * @param mixed[] $context */ - protected function getTransactionName(array $context) + protected function getTransactionName(array $context): ?string { if (isset($context['transaction_name'])) { return $context['transaction_name']; @@ -164,20 +162,16 @@ protected function getTransactionName(array $context) /** * Sets the NewRelic application that should receive this log. - * - * @param string $appName */ - protected function setNewRelicAppName($appName) + protected function setNewRelicAppName(string $appName): void { newrelic_set_appname($appName); } /** * Overwrites the name of the current transaction - * - * @param string $transactionName */ - protected function setNewRelicTransactionName($transactionName) + protected function setNewRelicTransactionName(string $transactionName): void { newrelic_name_transaction($transactionName); } @@ -186,7 +180,7 @@ protected function setNewRelicTransactionName($transactionName) * @param string $key * @param mixed $value */ - protected function setNewRelicParameter($key, $value) + protected function setNewRelicParameter(string $key, $value): void { if (null === $value || is_scalar($value)) { newrelic_add_custom_parameter($key, $value); @@ -198,7 +192,7 @@ protected function setNewRelicParameter($key, $value) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter(); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NoopHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NoopHandler.php new file mode 100644 index 00000000..1ddf0beb --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/NoopHandler.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +/** + * No-op + * + * This handler handles anything, but does nothing, and does not stop bubbling to the rest of the stack. + * This can be used for testing, or to disable a handler when overriding a configuration without + * influencing the rest of the stack. + * + * @author Roel Harbers + */ +class NoopHandler extends Handler +{ + /** + * {@inheritDoc} + */ + public function isHandling(array $record): bool + { + return true; + } + + /** + * {@inheritDoc} + */ + public function handle(array $record): bool + { + return false; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php index 4b845883..e75ee0c6 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/NullHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ -class NullHandler extends AbstractHandler +class NullHandler extends Handler { /** - * @param int $level The minimum logging level at which this handler will be triggered + * @var int + */ + private $level; + + /** + * @param string|int $level The minimum logging level at which this handler will be triggered + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ public function __construct($level = Logger::DEBUG) { - parent::__construct($level, false); + $this->level = Logger::toMonologLevel($level); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function isHandling(array $record): bool { - if ($record['level'] < $this->level) { - return false; - } + return $record['level'] >= $this->level; + } - return true; + /** + * {@inheritDoc} + */ + public function handle(array $record): bool + { + return $record['level'] >= $this->level; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/OverflowHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/OverflowHandler.php new file mode 100644 index 00000000..22068c9a --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/OverflowHandler.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Formatter\FormatterInterface; + +/** + * Handler to only pass log messages when a certain threshold of number of messages is reached. + * + * This can be useful in cases of processing a batch of data, but you're for example only interested + * in case it fails catastrophically instead of a warning for 1 or 2 events. Worse things can happen, right? + * + * Usage example: + * + * ``` + * $log = new Logger('application'); + * $handler = new SomeHandler(...) + * + * // Pass all warnings to the handler when more than 10 & all error messages when more then 5 + * $overflow = new OverflowHandler($handler, [Logger::WARNING => 10, Logger::ERROR => 5]); + * + * $log->pushHandler($overflow); + *``` + * + * @author Kris Buist + */ +class OverflowHandler extends AbstractHandler implements FormattableHandlerInterface +{ + /** @var HandlerInterface */ + private $handler; + + /** @var int[] */ + private $thresholdMap = [ + Logger::DEBUG => 0, + Logger::INFO => 0, + Logger::NOTICE => 0, + Logger::WARNING => 0, + Logger::ERROR => 0, + Logger::CRITICAL => 0, + Logger::ALERT => 0, + Logger::EMERGENCY => 0, + ]; + + /** + * Buffer of all messages passed to the handler before the threshold was reached + * + * @var mixed[][] + */ + private $buffer = []; + + /** + * @param HandlerInterface $handler + * @param int[] $thresholdMap Dictionary of logger level => threshold + */ + public function __construct( + HandlerInterface $handler, + array $thresholdMap = [], + $level = Logger::DEBUG, + bool $bubble = true + ) { + $this->handler = $handler; + foreach ($thresholdMap as $thresholdLevel => $threshold) { + $this->thresholdMap[$thresholdLevel] = $threshold; + } + parent::__construct($level, $bubble); + } + + /** + * Handles a record. + * + * All records may be passed to this method, and the handler should discard + * those that it does not want to handle. + * + * The return value of this function controls the bubbling process of the handler stack. + * Unless the bubbling is interrupted (by returning true), the Logger class will keep on + * calling further handlers in the stack with a given log record. + * + * {@inheritDoc} + */ + public function handle(array $record): bool + { + if ($record['level'] < $this->level) { + return false; + } + + $level = $record['level']; + + if (!isset($this->thresholdMap[$level])) { + $this->thresholdMap[$level] = 0; + } + + if ($this->thresholdMap[$level] > 0) { + // The overflow threshold is not yet reached, so we're buffering the record and lowering the threshold by 1 + $this->thresholdMap[$level]--; + $this->buffer[$level][] = $record; + + return false === $this->bubble; + } + + if ($this->thresholdMap[$level] == 0) { + // This current message is breaking the threshold. Flush the buffer and continue handling the current record + foreach ($this->buffer[$level] ?? [] as $buffered) { + $this->handler->handle($buffered); + } + $this->thresholdMap[$level]--; + unset($this->buffer[$level]); + } + + $this->handler->handle($record); + + return false === $this->bubble; + } + + /** + * {@inheritDoc} + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + if ($this->handler instanceof FormattableHandlerInterface) { + $this->handler->setFormatter($formatter); + + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); + } + + /** + * {@inheritDoc} + */ + public function getFormatter(): FormatterInterface + { + if ($this->handler instanceof FormattableHandlerInterface) { + return $this->handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($this->handler).' does not support formatters.'); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php index d0a8b43e..23a1d117 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/PHPConsoleHandler.php @@ -1,4 +1,4 @@ -addDebug('SELECT * FROM users', array('db', 'time' => 0.012)); + * $logger->debug('SELECT * FROM users', array('db', 'time' => 0.012)); * PC::debug($_SERVER); // PHP Console debugger for any type of vars * * @author Sergey Barbushin https://www.linkedin.com/in/barbushin + * + * @phpstan-import-type Record from \Monolog\Logger + * @deprecated Since 2.8.0 and 3.2.0, PHPConsole is abandoned and thus we will drop this handler in Monolog 4 */ class PHPConsoleHandler extends AbstractProcessingHandler { - private $options = array( + /** @var array */ + private $options = [ 'enabled' => true, // bool Is PHP Console server enabled - 'classesPartialsTraceIgnore' => array('Monolog\\'), // array Hide calls of classes started with... - 'debugTagsKeysInContext' => array(0, 'tag'), // bool Is PHP Console server enabled + 'classesPartialsTraceIgnore' => ['Monolog\\'], // array Hide calls of classes started with... + 'debugTagsKeysInContext' => [0, 'tag'], // bool Is PHP Console server enabled 'useOwnErrorsHandler' => false, // bool Enable errors handling 'useOwnExceptionsHandler' => false, // bool Enable exceptions handling 'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths @@ -52,7 +56,7 @@ class PHPConsoleHandler extends AbstractProcessingHandler 'headersLimit' => null, // int|null Set headers size limit for your web-server 'password' => null, // string|null Protect PHP Console connection by password 'enableSslOnlyMode' => false, // bool Force connection by SSL for clients with PHP Console installed - 'ipMasks' => array(), // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1') + 'ipMasks' => [], // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1') 'enableEvalListener' => false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required) 'dumperDetectCallbacks' => false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings 'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level @@ -60,40 +64,43 @@ class PHPConsoleHandler extends AbstractProcessingHandler 'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item 'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON 'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug - 'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ) - ); + 'dataStorage' => null, // \PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ) + ]; /** @var Connector */ private $connector; /** - * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details - * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) - * @param int $level - * @param bool $bubble - * @throws Exception + * @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details + * @param Connector|null $connector Instance of \PhpConsole\Connector class (optional) + * @throws \RuntimeException */ - public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true) + public function __construct(array $options = [], ?Connector $connector = null, $level = Logger::DEBUG, bool $bubble = true) { if (!class_exists('PhpConsole\Connector')) { - throw new Exception('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); + throw new \RuntimeException('PHP Console library not found. See https://github.com/barbushin/php-console#installation'); } parent::__construct($level, $bubble); $this->options = $this->initOptions($options); $this->connector = $this->initConnector($connector); } - private function initOptions(array $options) + /** + * @param array $options + * + * @return array + */ + private function initOptions(array $options): array { $wrongOptions = array_diff(array_keys($options), array_keys($this->options)); if ($wrongOptions) { - throw new Exception('Unknown options: ' . implode(', ', $wrongOptions)); + throw new \RuntimeException('Unknown options: ' . implode(', ', $wrongOptions)); } return array_replace($this->options, $options); } - private function initConnector(Connector $connector = null) + private function initConnector(?Connector $connector = null): Connector { if (!$connector) { if ($this->options['dataStorage']) { @@ -108,7 +115,7 @@ private function initConnector(Connector $connector = null) if ($this->options['enabled'] && $connector->isActiveClient()) { if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) { - $handler = Handler::getInstance(); + $handler = VendorPhpConsoleHandler::getInstance(); $handler->setHandleErrors($this->options['useOwnErrorsHandler']); $handler->setHandleExceptions($this->options['useOwnExceptionsHandler']); $handler->start(); @@ -148,17 +155,20 @@ private function initConnector(Connector $connector = null) return $connector; } - public function getConnector() + public function getConnector(): Connector { return $this->connector; } - public function getOptions() + /** + * @return array + */ + public function getOptions(): array { return $this->options; } - public function handle(array $record) + public function handle(array $record): bool { if ($this->options['enabled'] && $this->connector->isActiveClient()) { return parent::handle($record); @@ -169,22 +179,22 @@ public function handle(array $record) /** * Writes the record down to the log of the implementing handler - * - * @param array $record - * @return void */ - protected function write(array $record) + protected function write(array $record): void { if ($record['level'] < Logger::NOTICE) { $this->handleDebugRecord($record); - } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) { + } elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Throwable) { $this->handleExceptionRecord($record); } else { $this->handleErrorRecord($record); } } - private function handleDebugRecord(array $record) + /** + * @phpstan-param Record $record + */ + private function handleDebugRecord(array $record): void { $tags = $this->getRecordTags($record); $message = $record['message']; @@ -194,24 +204,34 @@ private function handleDebugRecord(array $record) $this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']); } - private function handleExceptionRecord(array $record) + /** + * @phpstan-param Record $record + */ + private function handleExceptionRecord(array $record): void { $this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']); } - private function handleErrorRecord(array $record) + /** + * @phpstan-param Record $record + */ + private function handleErrorRecord(array $record): void { $context = $record['context']; $this->connector->getErrorsDispatcher()->dispatchError( - isset($context['code']) ? $context['code'] : null, - isset($context['message']) ? $context['message'] : $record['message'], - isset($context['file']) ? $context['file'] : null, - isset($context['line']) ? $context['line'] : null, + $context['code'] ?? null, + $context['message'] ?? $record['message'], + $context['file'] ?? null, + $context['line'] ?? null, $this->options['classesPartialsTraceIgnore'] ); } + /** + * @phpstan-param Record $record + * @return string + */ private function getRecordTags(array &$record) { $tags = null; @@ -236,7 +256,7 @@ private function getRecordTags(array &$record) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter('%message%'); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ProcessHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ProcessHandler.php new file mode 100644 index 00000000..8a8cf1be --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/ProcessHandler.php @@ -0,0 +1,191 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * Stores to STDIN of any process, specified by a command. + * + * Usage example: + *
+ * $log = new Logger('myLogger');
+ * $log->pushHandler(new ProcessHandler('/usr/bin/php /var/www/monolog/someScript.php'));
+ * 
+ * + * @author Kolja Zuelsdorf + */ +class ProcessHandler extends AbstractProcessingHandler +{ + /** + * Holds the process to receive data on its STDIN. + * + * @var resource|bool|null + */ + private $process; + + /** + * @var string + */ + private $command; + + /** + * @var string|null + */ + private $cwd; + + /** + * @var resource[] + */ + private $pipes = []; + + /** + * @var array + */ + protected const DESCRIPTOR_SPEC = [ + 0 => ['pipe', 'r'], // STDIN is a pipe that the child will read from + 1 => ['pipe', 'w'], // STDOUT is a pipe that the child will write to + 2 => ['pipe', 'w'], // STDERR is a pipe to catch the any errors + ]; + + /** + * @param string $command Command for the process to start. Absolute paths are recommended, + * especially if you do not use the $cwd parameter. + * @param string|null $cwd "Current working directory" (CWD) for the process to be executed in. + * @throws \InvalidArgumentException + */ + public function __construct(string $command, $level = Logger::DEBUG, bool $bubble = true, ?string $cwd = null) + { + if ($command === '') { + throw new \InvalidArgumentException('The command argument must be a non-empty string.'); + } + if ($cwd === '') { + throw new \InvalidArgumentException('The optional CWD argument must be a non-empty string or null.'); + } + + parent::__construct($level, $bubble); + + $this->command = $command; + $this->cwd = $cwd; + } + + /** + * Writes the record down to the log of the implementing handler + * + * @throws \UnexpectedValueException + */ + protected function write(array $record): void + { + $this->ensureProcessIsStarted(); + + $this->writeProcessInput($record['formatted']); + + $errors = $this->readProcessErrors(); + if (empty($errors) === false) { + throw new \UnexpectedValueException(sprintf('Errors while writing to process: %s', $errors)); + } + } + + /** + * Makes sure that the process is actually started, and if not, starts it, + * assigns the stream pipes, and handles startup errors, if any. + */ + private function ensureProcessIsStarted(): void + { + if (is_resource($this->process) === false) { + $this->startProcess(); + + $this->handleStartupErrors(); + } + } + + /** + * Starts the actual process and sets all streams to non-blocking. + */ + private function startProcess(): void + { + $this->process = proc_open($this->command, static::DESCRIPTOR_SPEC, $this->pipes, $this->cwd); + + foreach ($this->pipes as $pipe) { + stream_set_blocking($pipe, false); + } + } + + /** + * Selects the STDERR stream, handles upcoming startup errors, and throws an exception, if any. + * + * @throws \UnexpectedValueException + */ + private function handleStartupErrors(): void + { + $selected = $this->selectErrorStream(); + if (false === $selected) { + throw new \UnexpectedValueException('Something went wrong while selecting a stream.'); + } + + $errors = $this->readProcessErrors(); + + if (is_resource($this->process) === false || empty($errors) === false) { + throw new \UnexpectedValueException( + sprintf('The process "%s" could not be opened: ' . $errors, $this->command) + ); + } + } + + /** + * Selects the STDERR stream. + * + * @return int|bool + */ + protected function selectErrorStream() + { + $empty = []; + $errorPipes = [$this->pipes[2]]; + + return stream_select($errorPipes, $empty, $empty, 1); + } + + /** + * Reads the errors of the process, if there are any. + * + * @codeCoverageIgnore + * @return string Empty string if there are no errors. + */ + protected function readProcessErrors(): string + { + return (string) stream_get_contents($this->pipes[2]); + } + + /** + * Writes to the input stream of the opened process. + * + * @codeCoverageIgnore + */ + protected function writeProcessInput(string $string): void + { + fwrite($this->pipes[0], $string); + } + + /** + * {@inheritDoc} + */ + public function close(): void + { + if (is_resource($this->process)) { + foreach ($this->pipes as $pipe) { + fclose($pipe); + } + proc_close($this->process); + $this->process = null; + } + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php index 66a3d83a..3adec7a4 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerInterface.php @@ -16,25 +16,29 @@ /** * Interface to describe loggers that have processors * - * This interface is present in monolog 1.x to ease forward compatibility. - * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessableHandlerInterface { /** * Adds a processor in the stack. * + * @psalm-param ProcessorInterface|callable(Record): Record $callback + * * @param ProcessorInterface|callable $callback * @return HandlerInterface self */ - public function pushProcessor($callback): HandlerInterface; + public function pushProcessor(callable $callback): HandlerInterface; /** * Removes the processor on top of the stack and returns it. * - * @throws \LogicException In case the processor stack is empty - * @return callable + * @psalm-return ProcessorInterface|callable(Record): Record $callback + * + * @throws \LogicException In case the processor stack is empty + * @return callable|ProcessorInterface */ public function popProcessor(): callable; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php index 09f32a12..9ef6e301 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ProcessableHandlerTrait.php @@ -12,26 +12,27 @@ namespace Monolog\Handler; use Monolog\ResettableInterface; +use Monolog\Processor\ProcessorInterface; /** * Helper trait for implementing ProcessableInterface * - * This trait is present in monolog 1.x to ease forward compatibility. - * * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger */ trait ProcessableHandlerTrait { /** * @var callable[] + * @phpstan-var array */ protected $processors = []; /** - * {@inheritdoc} - * @suppress PhanTypeMismatchReturn + * {@inheritDoc} */ - public function pushProcessor($callback): HandlerInterface + public function pushProcessor(callable $callback): HandlerInterface { array_unshift($this->processors, $callback); @@ -39,7 +40,7 @@ public function pushProcessor($callback): HandlerInterface } /** - * {@inheritdoc} + * {@inheritDoc} */ public function popProcessor(): callable { @@ -52,6 +53,9 @@ public function popProcessor(): callable /** * Processes a record. + * + * @phpstan-param Record $record + * @phpstan-return Record */ protected function processRecord(array $record): array { diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php index a99e6ab7..36e19ccc 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/PsrHandler.php @@ -1,4 +1,4 @@ - */ -class PsrHandler extends AbstractHandler +class PsrHandler extends AbstractHandler implements FormattableHandlerInterface { /** * PSR-3 compliant logger @@ -28,12 +33,15 @@ class PsrHandler extends AbstractHandler */ protected $logger; + /** + * @var FormatterInterface|null + */ + protected $formatter; + /** * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not */ - public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true) + public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, bool $bubble = true) { parent::__construct($level, $bubble); @@ -43,14 +51,45 @@ public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bu /** * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; } - $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']); + if ($this->formatter) { + $formatted = $this->formatter->format($record); + $this->logger->log(strtolower($record['level_name']), (string) $formatted, $record['context']); + } else { + $this->logger->log(strtolower($record['level_name']), $record['message'], $record['context']); + } return false === $this->bubble; } + + /** + * Sets the formatter. + * + * @param FormatterInterface $formatter + */ + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + $this->formatter = $formatter; + + return $this; + } + + /** + * Gets the formatter. + * + * @return FormatterInterface + */ + public function getFormatter(): FormatterInterface + { + if (!$this->formatter) { + throw new \LogicException('No formatter has been set and this handler does not have a default formatter'); + } + + return $this->formatter; + } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php index f27bb3da..fed2303d 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/PushoverHandler.php @@ -1,4 +1,4 @@ - * @see https://www.pushover.net/api + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class PushoverHandler extends SocketHandler { + /** @var string */ private $token; + /** @var array */ private $users; + /** @var string */ private $title; - private $user; + /** @var string|int|null */ + private $user = null; + /** @var int */ private $retry; + /** @var int */ private $expire; + /** @var int */ private $highPriorityLevel; + /** @var int */ private $emergencyLevel; + /** @var bool */ private $useFormattedMessage = false; /** * All parameters that can be sent to Pushover * @see https://pushover.net/api - * @var array + * @var array */ - private $parameterNames = array( + private $parameterNames = [ 'token' => true, 'user' => true, 'message' => true, @@ -51,72 +66,103 @@ class PushoverHandler extends SocketHandler 'retry' => true, 'expire' => true, 'callback' => true, - ); + ]; /** * Sounds the api supports by default * @see https://pushover.net/api#sounds - * @var array + * @var string[] */ - private $sounds = array( + private $sounds = [ 'pushover', 'bike', 'bugle', 'cashregister', 'classical', 'cosmic', 'falling', 'gamelan', 'incoming', 'intermission', 'magic', 'mechanical', 'pianobar', 'siren', 'spacealarm', 'tugboat', 'alien', 'climb', 'persistent', 'echo', 'updown', 'none', - ); + ]; /** * @param string $token Pushover api token * @param string|array $users Pushover user id or array of ids the message will be sent to - * @param string $title Title sent to the Pushover API - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string|null $title Title sent to the Pushover API * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not * the pushover.net app owner. OpenSSL is required for this option. - * @param int $highPriorityLevel The minimum logging level at which this handler will start + * @param string|int $highPriorityLevel The minimum logging level at which this handler will start * sending "high priority" requests to the Pushover API - * @param int $emergencyLevel The minimum logging level at which this handler will start + * @param string|int $emergencyLevel The minimum logging level at which this handler will start * sending "emergency" requests to the Pushover API - * @param int $retry The retry parameter specifies how often (in seconds) the Pushover servers will send the same notification to the user. - * @param int $expire The expire parameter specifies how many seconds your notification will continue to be retried for (every retry seconds). + * @param int $retry The retry parameter specifies how often (in seconds) the Pushover servers will + * send the same notification to the user. + * @param int $expire The expire parameter specifies how many seconds your notification will continue + * to be retried for (every retry seconds). + * + * @phpstan-param string|array $users + * @phpstan-param Level|LevelName|LogLevel::* $highPriorityLevel + * @phpstan-param Level|LevelName|LogLevel::* $emergencyLevel */ - public function __construct($token, $users, $title = null, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $highPriorityLevel = Logger::CRITICAL, $emergencyLevel = Logger::EMERGENCY, $retry = 30, $expire = 25200) - { + public function __construct( + string $token, + $users, + ?string $title = null, + $level = Logger::CRITICAL, + bool $bubble = true, + bool $useSSL = true, + $highPriorityLevel = Logger::CRITICAL, + $emergencyLevel = Logger::EMERGENCY, + int $retry = 30, + int $expire = 25200, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { $connectionString = $useSSL ? 'ssl://api.pushover.net:443' : 'api.pushover.net:80'; - parent::__construct($connectionString, $level, $bubble); + parent::__construct( + $connectionString, + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->token = $token; $this->users = (array) $users; - $this->title = $title ?: gethostname(); + $this->title = $title ?: (string) gethostname(); $this->highPriorityLevel = Logger::toMonologLevel($highPriorityLevel); $this->emergencyLevel = Logger::toMonologLevel($emergencyLevel); $this->retry = $retry; $this->expire = $expire; } - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); return $this->buildHeader($content) . $content; } - private function buildContent($record) + /** + * @phpstan-param FormattedRecord $record + */ + private function buildContent(array $record): string { // Pushover has a limit of 512 characters on title and message combined. $maxMessageLength = 512 - strlen($this->title); $message = ($this->useFormattedMessage) ? $record['formatted'] : $record['message']; - $message = substr($message, 0, $maxMessageLength); + $message = Utils::substr($message, 0, $maxMessageLength); $timestamp = $record['datetime']->getTimestamp(); - $dataArray = array( + $dataArray = [ 'token' => $this->token, 'user' => $this->user, 'message' => $message, 'title' => $this->title, 'timestamp' => $timestamp, - ); + ]; if (isset($record['level']) && $record['level'] >= $this->emergencyLevel) { $dataArray['priority'] = 2; @@ -141,7 +187,7 @@ private function buildContent($record) return http_build_query($dataArray); } - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST /1/messages.json HTTP/1.1\r\n"; $header .= "Host: api.pushover.net\r\n"; @@ -152,7 +198,7 @@ private function buildHeader($content) return $header; } - protected function write(array $record) + protected function write(array $record): void { foreach ($this->users as $user) { $this->user = $user; @@ -164,22 +210,37 @@ protected function write(array $record) $this->user = null; } - public function setHighPriorityLevel($value) + /** + * @param int|string $value + * + * @phpstan-param Level|LevelName|LogLevel::* $value + */ + public function setHighPriorityLevel($value): self { - $this->highPriorityLevel = $value; + $this->highPriorityLevel = Logger::toMonologLevel($value); + + return $this; } - public function setEmergencyLevel($value) + /** + * @param int|string $value + * + * @phpstan-param Level|LevelName|LogLevel::* $value + */ + public function setEmergencyLevel($value): self { - $this->emergencyLevel = $value; + $this->emergencyLevel = Logger::toMonologLevel($value); + + return $this; } /** * Use the formatted message? - * @param bool $value */ - public function useFormattedMessage($value) + public function useFormattedMessage(bool $value): self { - $this->useFormattedMessage = (bool) $value; + $this->useFormattedMessage = $value; + + return $this; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php deleted file mode 100644 index b0298fa6..00000000 --- a/vendor/monolog/monolog/src/Monolog/Handler/RavenHandler.php +++ /dev/null @@ -1,234 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Formatter\LineFormatter; -use Monolog\Formatter\FormatterInterface; -use Monolog\Logger; -use Raven_Client; - -/** - * Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server - * using sentry-php (https://github.com/getsentry/sentry-php) - * - * @author Marc Abramowitz - */ -class RavenHandler extends AbstractProcessingHandler -{ - /** - * Translates Monolog log levels to Raven log levels. - */ - protected $logLevels = array( - Logger::DEBUG => Raven_Client::DEBUG, - Logger::INFO => Raven_Client::INFO, - Logger::NOTICE => Raven_Client::INFO, - Logger::WARNING => Raven_Client::WARNING, - Logger::ERROR => Raven_Client::ERROR, - Logger::CRITICAL => Raven_Client::FATAL, - Logger::ALERT => Raven_Client::FATAL, - Logger::EMERGENCY => Raven_Client::FATAL, - ); - - /** - * @var string should represent the current version of the calling - * software. Can be any string (git commit, version number) - */ - protected $release; - - /** - * @var Raven_Client the client object that sends the message to the server - */ - protected $ravenClient; - - /** - * @var FormatterInterface The formatter to use for the logs generated via handleBatch() - */ - protected $batchFormatter; - - /** - * @param Raven_Client $ravenClient - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - */ - public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) - { - @trigger_error('The Monolog\Handler\RavenHandler class is deprecated. You should rather upgrade to the sentry/sentry 2.x and use Sentry\Monolog\Handler, see https://github.com/getsentry/sentry-php/blob/master/src/Monolog/Handler.php', E_USER_DEPRECATED); - - parent::__construct($level, $bubble); - - $this->ravenClient = $ravenClient; - } - - /** - * {@inheritdoc} - */ - public function handleBatch(array $records) - { - $level = $this->level; - - // filter records based on their level - $records = array_filter($records, function ($record) use ($level) { - return $record['level'] >= $level; - }); - - if (!$records) { - return; - } - - // the record with the highest severity is the "main" one - $record = array_reduce($records, function ($highest, $record) { - if (null === $highest || $record['level'] > $highest['level']) { - return $record; - } - - return $highest; - }); - - // the other ones are added as a context item - $logs = array(); - foreach ($records as $r) { - $logs[] = $this->processRecord($r); - } - - if ($logs) { - $record['context']['logs'] = (string) $this->getBatchFormatter()->formatBatch($logs); - } - - $this->handle($record); - } - - /** - * Sets the formatter for the logs generated by handleBatch(). - * - * @param FormatterInterface $formatter - */ - public function setBatchFormatter(FormatterInterface $formatter) - { - $this->batchFormatter = $formatter; - } - - /** - * Gets the formatter for the logs generated by handleBatch(). - * - * @return FormatterInterface - */ - public function getBatchFormatter() - { - if (!$this->batchFormatter) { - $this->batchFormatter = $this->getDefaultBatchFormatter(); - } - - return $this->batchFormatter; - } - - /** - * {@inheritdoc} - */ - protected function write(array $record) - { - $previousUserContext = false; - $options = array(); - $options['level'] = $this->logLevels[$record['level']]; - $options['tags'] = array(); - if (!empty($record['extra']['tags'])) { - $options['tags'] = array_merge($options['tags'], $record['extra']['tags']); - unset($record['extra']['tags']); - } - if (!empty($record['context']['tags'])) { - $options['tags'] = array_merge($options['tags'], $record['context']['tags']); - unset($record['context']['tags']); - } - if (!empty($record['context']['fingerprint'])) { - $options['fingerprint'] = $record['context']['fingerprint']; - unset($record['context']['fingerprint']); - } - if (!empty($record['context']['logger'])) { - $options['logger'] = $record['context']['logger']; - unset($record['context']['logger']); - } else { - $options['logger'] = $record['channel']; - } - foreach ($this->getExtraParameters() as $key) { - foreach (array('extra', 'context') as $source) { - if (!empty($record[$source][$key])) { - $options[$key] = $record[$source][$key]; - unset($record[$source][$key]); - } - } - } - if (!empty($record['context'])) { - $options['extra']['context'] = $record['context']; - if (!empty($record['context']['user'])) { - $previousUserContext = $this->ravenClient->context->user; - $this->ravenClient->user_context($record['context']['user']); - unset($options['extra']['context']['user']); - } - } - if (!empty($record['extra'])) { - $options['extra']['extra'] = $record['extra']; - } - - if (!empty($this->release) && !isset($options['release'])) { - $options['release'] = $this->release; - } - - if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { - $options['message'] = $record['formatted']; - $this->ravenClient->captureException($record['context']['exception'], $options); - } else { - $this->ravenClient->captureMessage($record['formatted'], array(), $options); - } - - if ($previousUserContext !== false) { - $this->ravenClient->user_context($previousUserContext); - } - } - - /** - * {@inheritDoc} - */ - protected function getDefaultFormatter() - { - return new LineFormatter('[%channel%] %message%'); - } - - /** - * Gets the default formatter for the logs generated by handleBatch(). - * - * @return FormatterInterface - */ - protected function getDefaultBatchFormatter() - { - return new LineFormatter(); - } - - /** - * Gets extra parameters supported by Raven that can be found in "extra" and "context" - * - * @return array - */ - protected function getExtraParameters() - { - return array('contexts', 'checksum', 'release', 'event_id'); - } - - /** - * @param string $value - * @return self - */ - public function setRelease($value) - { - $this->release = $value; - - return $this; - } -} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php index 3725db24..91d16eaf 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RedisHandler.php @@ -1,4 +1,4 @@ -pushHandler($redis); * * @author Thomas Tourlourat + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class RedisHandler extends AbstractProcessingHandler { + /** @var \Predis\Client<\Predis\Client>|\Redis */ private $redisClient; + /** @var string */ private $redisKey; + /** @var int */ protected $capSize; /** - * @param \Predis\Client|\Redis $redis The redis instance + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance * @param string $key The key name to push records to - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param int|false $capSize Number of entries to limit list size to + * @param int $capSize Number of entries to limit list size to, 0 = unlimited */ - public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true, $capSize = false) + public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true, int $capSize = 0) { if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { throw new \InvalidArgumentException('Predis\Client or Redis instance required'); @@ -54,7 +58,7 @@ public function __construct($redis, $key, $level = Logger::DEBUG, $bubble = true /** * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { if ($this->capSize) { $this->writeCapped($record); @@ -67,10 +71,9 @@ protected function write(array $record) * Write and cap the collection * Writes the record to the redis list and caps its * - * @param array $record associative record array - * @return void + * @phpstan-param FormattedRecord $record */ - protected function writeCapped(array $record) + protected function writeCapped(array $record): void { if ($this->redisClient instanceof \Redis) { $mode = defined('\Redis::MULTI') ? \Redis::MULTI : 1; @@ -91,7 +94,7 @@ protected function writeCapped(array $record) /** * {@inheritDoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new LineFormatter(); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RedisPubSubHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RedisPubSubHandler.php new file mode 100644 index 00000000..7789309c --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/RedisPubSubHandler.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Formatter\LineFormatter; +use Monolog\Formatter\FormatterInterface; +use Monolog\Logger; + +/** + * Sends the message to a Redis Pub/Sub channel using PUBLISH + * + * usage example: + * + * $log = new Logger('application'); + * $redis = new RedisPubSubHandler(new Predis\Client("tcp://localhost:6379"), "logs", Logger::WARNING); + * $log->pushHandler($redis); + * + * @author Gaëtan Faugère + */ +class RedisPubSubHandler extends AbstractProcessingHandler +{ + /** @var \Predis\Client<\Predis\Client>|\Redis */ + private $redisClient; + /** @var string */ + private $channelKey; + + /** + * @param \Predis\Client<\Predis\Client>|\Redis $redis The redis instance + * @param string $key The channel key to publish records to + */ + public function __construct($redis, string $key, $level = Logger::DEBUG, bool $bubble = true) + { + if (!(($redis instanceof \Predis\Client) || ($redis instanceof \Redis))) { + throw new \InvalidArgumentException('Predis\Client or Redis instance required'); + } + + $this->redisClient = $redis; + $this->channelKey = $key; + + parent::__construct($level, $bubble); + } + + /** + * {@inheritDoc} + */ + protected function write(array $record): void + { + $this->redisClient->publish($this->channelKey, $record["formatted"]); + } + + /** + * {@inheritDoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new LineFormatter(); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php index 65073ffe..adcc9395 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RollbarHandler.php @@ -1,4 +1,4 @@ - 'debug', Logger::INFO => 'info', Logger::NOTICE => 'info', @@ -49,7 +48,7 @@ class RollbarHandler extends AbstractProcessingHandler Logger::CRITICAL => 'critical', Logger::ALERT => 'critical', Logger::EMERGENCY => 'critical', - ); + ]; /** * Records whether any log records have been added since the last flush of the rollbar notifier @@ -58,24 +57,23 @@ class RollbarHandler extends AbstractProcessingHandler */ private $hasRecords = false; + /** @var bool */ protected $initialized = false; /** - * @param RollbarNotifier $rollbarNotifier RollbarNotifier object constructed with valid token - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param RollbarLogger $rollbarLogger RollbarLogger object constructed with valid token */ - public function __construct(RollbarNotifier $rollbarNotifier, $level = Logger::ERROR, $bubble = true) + public function __construct(RollbarLogger $rollbarLogger, $level = Logger::ERROR, bool $bubble = true) { - $this->rollbarNotifier = $rollbarNotifier; + $this->rollbarLogger = $rollbarLogger; parent::__construct($level, $bubble); } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!$this->initialized) { // __destructor() doesn't get called on Fatal errors @@ -84,54 +82,45 @@ protected function write(array $record) } $context = $record['context']; - $payload = array(); - if (isset($context['payload'])) { - $payload = $context['payload']; - unset($context['payload']); - } - $context = array_merge($context, $record['extra'], array( + $context = array_merge($context, $record['extra'], [ 'level' => $this->levelMap[$record['level']], 'monolog_level' => $record['level_name'], 'channel' => $record['channel'], 'datetime' => $record['datetime']->format('U'), - )); + ]); - if (isset($context['exception']) && $context['exception'] instanceof Exception) { - $payload['level'] = $context['level']; + if (isset($context['exception']) && $context['exception'] instanceof Throwable) { $exception = $context['exception']; unset($context['exception']); - - $this->rollbarNotifier->report_exception($exception, $context, $payload); + $toLog = $exception; } else { - $this->rollbarNotifier->report_message( - $record['message'], - $context['level'], - $context, - $payload - ); + $toLog = $record['message']; } + // @phpstan-ignore-next-line + $this->rollbarLogger->log($context['level'], $toLog, $context); + $this->hasRecords = true; } - public function flush() + public function flush(): void { if ($this->hasRecords) { - $this->rollbarNotifier->flush(); + $this->rollbarLogger->flush(); $this->hasRecords = false; } } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function close() + public function close(): void { $this->flush(); } /** - * {@inheritdoc} + * {@inheritDoc} */ public function reset() { @@ -139,6 +128,4 @@ public function reset() parent::reset(); } - - } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php index b8253ba0..17745d22 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/RotatingFileHandler.php @@ -1,4 +1,4 @@ -filename = Utils::canonicalizePath($filename); - $this->maxFiles = (int) $maxFiles; - $this->nextRotation = new \DateTime('tomorrow'); + $this->maxFiles = $maxFiles; + $this->nextRotation = new \DateTimeImmutable('tomorrow'); $this->filenameFormat = '{filename}-{date}'; - $this->dateFormat = 'Y-m-d'; + $this->dateFormat = static::FILE_PER_DAY; parent::__construct($this->getTimedFilename(), $level, $bubble, $filePermission, $useLocking); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function close() + public function close(): void { parent::close(); @@ -68,7 +73,7 @@ public function close() } /** - * {@inheritdoc} + * {@inheritDoc} */ public function reset() { @@ -79,40 +84,40 @@ public function reset() } } - public function setFilenameFormat($filenameFormat, $dateFormat) + public function setFilenameFormat(string $filenameFormat, string $dateFormat): self { - if (!preg_match('{^Y(([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { - trigger_error( + if (!preg_match('{^[Yy](([/_.-]?m)([/_.-]?d)?)?$}', $dateFormat)) { + throw new InvalidArgumentException( 'Invalid date format - format must be one of '. 'RotatingFileHandler::FILE_PER_DAY ("Y-m-d"), RotatingFileHandler::FILE_PER_MONTH ("Y-m") '. 'or RotatingFileHandler::FILE_PER_YEAR ("Y"), or you can set one of the '. - 'date formats using slashes, underscores and/or dots instead of dashes.', - E_USER_DEPRECATED + 'date formats using slashes, underscores and/or dots instead of dashes.' ); } if (substr_count($filenameFormat, '{date}') === 0) { - trigger_error( - 'Invalid filename format - format should contain at least `{date}`, because otherwise rotating is impossible.', - E_USER_DEPRECATED + throw new InvalidArgumentException( + 'Invalid filename format - format must contain at least `{date}`, because otherwise rotating is impossible.' ); } $this->filenameFormat = $filenameFormat; $this->dateFormat = $dateFormat; $this->url = $this->getTimedFilename(); $this->close(); + + return $this; } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { // on the first record written, if the log is new, we should rotate (once per day) if (null === $this->mustRotate) { - $this->mustRotate = !file_exists($this->url); + $this->mustRotate = null === $this->url || !file_exists($this->url); } - if ($this->nextRotation < $record['datetime']) { + if ($this->nextRotation <= $record['datetime']) { $this->mustRotate = true; $this->close(); } @@ -123,11 +128,11 @@ protected function write(array $record) /** * Rotates the files. */ - protected function rotate() + protected function rotate(): void { // update filename $this->url = $this->getTimedFilename(); - $this->nextRotation = new \DateTime('tomorrow'); + $this->nextRotation = new \DateTimeImmutable('tomorrow'); // skip GC of old logs if files are unlimited if (0 === $this->maxFiles) { @@ -135,6 +140,11 @@ protected function rotate() } $logFiles = glob($this->getGlobPattern()); + if (false === $logFiles) { + // failed to glob + return; + } + if ($this->maxFiles >= count($logFiles)) { // no files to remove return; @@ -149,7 +159,9 @@ protected function rotate() if (is_writable($file)) { // suppress errors here as unlink() might fail if two processes // are cleaning up/rotating at the same time - set_error_handler(function ($errno, $errstr, $errfile, $errline) {}); + set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline): bool { + return false; + }); unlink($file); restore_error_handler(); } @@ -158,31 +170,35 @@ protected function rotate() $this->mustRotate = false; } - protected function getTimedFilename() + protected function getTimedFilename(): string { $fileInfo = pathinfo($this->filename); $timedFilename = str_replace( - array('{filename}', '{date}'), - array($fileInfo['filename'], date($this->dateFormat)), + ['{filename}', '{date}'], + [$fileInfo['filename'], date($this->dateFormat)], $fileInfo['dirname'] . '/' . $this->filenameFormat ); - if (!empty($fileInfo['extension'])) { + if (isset($fileInfo['extension'])) { $timedFilename .= '.'.$fileInfo['extension']; } return $timedFilename; } - protected function getGlobPattern() + protected function getGlobPattern(): string { $fileInfo = pathinfo($this->filename); $glob = str_replace( - array('{filename}', '{date}'), - array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'), + ['{filename}', '{date}'], + [$fileInfo['filename'], str_replace( + ['Y', 'y', 'm', 'd'], + ['[0-9][0-9][0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]', '[0-9][0-9]'], + $this->dateFormat) + ], $fileInfo['dirname'] . '/' . $this->filenameFormat ); - if (!empty($fileInfo['extension'])) { + if (isset($fileInfo['extension'])) { $glob .= '.'.$fileInfo['extension']; } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php index b547ed7d..c128a32d 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SamplingHandler.php @@ -1,4 +1,4 @@ - * @author Kunal Mehta + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ -class SamplingHandler extends AbstractHandler +class SamplingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface { + use ProcessableHandlerTrait; + /** - * @var callable|HandlerInterface $handler + * @var HandlerInterface|callable + * @phpstan-var HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface */ protected $handler; @@ -40,10 +46,12 @@ class SamplingHandler extends AbstractHandler protected $factor; /** + * @psalm-param HandlerInterface|callable(Record|array{level: Level}|null, HandlerInterface): HandlerInterface $handler + * * @param callable|HandlerInterface $handler Handler or factory callable($record|null, $samplingHandler). - * @param int $factor Sample factor + * @param int $factor Sample factor (e.g. 10 means every ~10th record is sampled) */ - public function __construct($handler, $factor) + public function __construct($handler, int $factor) { parent::__construct(); $this->handler = $handler; @@ -54,18 +62,17 @@ public function __construct($handler, $factor) } } - public function isHandling(array $record) + public function isHandling(array $record): bool { return $this->getHandler($record)->isHandling($record); } - public function handle(array $record) + public function handle(array $record): bool { if ($this->isHandling($record) && mt_rand(1, $this->factor) === 1) { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + /** @var Record $record */ + $record = $this->processRecord($record); } $this->getHandler($record)->handle($record); @@ -79,12 +86,14 @@ public function handle(array $record) * * If the handler was provided as a factory callable, this will trigger the handler's instantiation. * + * @phpstan-param Record|array{level: Level}|null $record + * * @return HandlerInterface */ public function getHandler(array $record = null) { if (!$this->handler instanceof HandlerInterface) { - $this->handler = call_user_func($this->handler, $record, $this); + $this->handler = ($this->handler)($record, $this); if (!$this->handler instanceof HandlerInterface) { throw new \RuntimeException("The factory callable should return a HandlerInterface"); } @@ -94,20 +103,30 @@ public function getHandler(array $record = null) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { - $this->getHandler()->setFormatter($formatter); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + $handler->setFormatter($formatter); - return $this; + return $this; + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getFormatter() + public function getFormatter(): FormatterInterface { - return $this->getHandler()->getFormatter(); + $handler = $this->getHandler(); + if ($handler instanceof FormattableHandlerInterface) { + return $handler->getFormatter(); + } + + throw new \UnexpectedValueException('The nested handler of type '.get_class($handler).' does not support formatters.'); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SendGridHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SendGridHandler.php new file mode 100644 index 00000000..1280ee70 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/SendGridHandler.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; + +/** + * SendGridrHandler uses the SendGrid API v2 function to send Log emails, more information in https://sendgrid.com/docs/API_Reference/Web_API/mail.html + * + * @author Ricardo Fontanelli + */ +class SendGridHandler extends MailHandler +{ + /** + * The SendGrid API User + * @var string + */ + protected $apiUser; + + /** + * The SendGrid API Key + * @var string + */ + protected $apiKey; + + /** + * The email addresses to which the message will be sent + * @var string + */ + protected $from; + + /** + * The email addresses to which the message will be sent + * @var string[] + */ + protected $to; + + /** + * The subject of the email + * @var string + */ + protected $subject; + + /** + * @param string $apiUser The SendGrid API User + * @param string $apiKey The SendGrid API Key + * @param string $from The sender of the email + * @param string|string[] $to The recipients of the email + * @param string $subject The subject of the mail + */ + public function __construct(string $apiUser, string $apiKey, string $from, $to, string $subject, $level = Logger::ERROR, bool $bubble = true) + { + if (!extension_loaded('curl')) { + throw new MissingExtensionException('The curl extension is needed to use the SendGridHandler'); + } + + parent::__construct($level, $bubble); + $this->apiUser = $apiUser; + $this->apiKey = $apiKey; + $this->from = $from; + $this->to = (array) $to; + $this->subject = $subject; + } + + /** + * {@inheritDoc} + */ + protected function send(string $content, array $records): void + { + $message = []; + $message['api_user'] = $this->apiUser; + $message['api_key'] = $this->apiKey; + $message['from'] = $this->from; + foreach ($this->to as $recipient) { + $message['to[]'] = $recipient; + } + $message['subject'] = $this->subject; + $message['date'] = date('r'); + + if ($this->isHtmlBody($content)) { + $message['html'] = $content; + } else { + $message['text'] = $content; + } + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, 'https://api.sendgrid.com/api/mail.send.json'); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($message)); + Curl\Util::execute($ch, 2); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php b/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php index 39455501..71a41094 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/Slack/SlackRecord.php @@ -1,4 +1,4 @@ - * @see https://api.slack.com/incoming-webhooks * @see https://api.slack.com/docs/message-attachments + * + * @phpstan-import-type FormattedRecord from \Monolog\Handler\AbstractProcessingHandler + * @phpstan-import-type Record from \Monolog\Logger */ class SlackRecord { - const COLOR_DANGER = 'danger'; + public const COLOR_DANGER = 'danger'; - const COLOR_WARNING = 'warning'; + public const COLOR_WARNING = 'warning'; - const COLOR_GOOD = 'good'; + public const COLOR_GOOD = 'good'; - const COLOR_DEFAULT = '#e3e4e6'; + public const COLOR_DEFAULT = '#e3e4e6'; /** * Slack channel (encoded ID or name) @@ -48,7 +51,7 @@ class SlackRecord /** * User icon e.g. 'ghost', 'http://example.com/user.png' - * @var string + * @var string|null */ private $userIcon; @@ -72,12 +75,12 @@ class SlackRecord /** * Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] - * @var array + * @var string[] */ private $excludeFields; /** - * @var FormatterInterface + * @var ?FormatterInterface */ private $formatter; @@ -86,26 +89,45 @@ class SlackRecord */ private $normalizerFormatter; - public function __construct($channel = null, $username = null, $useAttachment = true, $userIcon = null, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array(), FormatterInterface $formatter = null) - { - $this->channel = $channel; - $this->username = $username; - $this->userIcon = trim($userIcon, ':'); - $this->useAttachment = $useAttachment; - $this->useShortAttachment = $useShortAttachment; - $this->includeContextAndExtra = $includeContextAndExtra; - $this->excludeFields = $excludeFields; - $this->formatter = $formatter; + /** + * @param string[] $excludeFields + */ + public function __construct( + ?string $channel = null, + ?string $username = null, + bool $useAttachment = true, + ?string $userIcon = null, + bool $useShortAttachment = false, + bool $includeContextAndExtra = false, + array $excludeFields = array(), + FormatterInterface $formatter = null + ) { + $this + ->setChannel($channel) + ->setUsername($username) + ->useAttachment($useAttachment) + ->setUserIcon($userIcon) + ->useShortAttachment($useShortAttachment) + ->includeContextAndExtra($includeContextAndExtra) + ->excludeFields($excludeFields) + ->setFormatter($formatter); if ($this->includeContextAndExtra) { $this->normalizerFormatter = new NormalizerFormatter(); } } - public function getSlackData(array $record) + /** + * Returns required data in format that Slack + * is expecting. + * + * @phpstan-param FormattedRecord $record + * @phpstan-return mixed[] + */ + public function getSlackData(array $record): array { $dataArray = array(); - $record = $this->excludeFields($record); + $record = $this->removeExcludedFields($record); if ($this->username) { $dataArray['username'] = $this->username; @@ -116,6 +138,7 @@ public function getSlackData(array $record) } if ($this->formatter && !$this->useAttachment) { + /** @phpstan-ignore-next-line */ $message = $this->formatter->format($record); } else { $message = $record['message']; @@ -123,12 +146,14 @@ public function getSlackData(array $record) if ($this->useAttachment) { $attachment = array( - 'fallback' => $message, - 'text' => $message, - 'color' => $this->getAttachmentColor($record['level']), - 'fields' => array(), - 'mrkdwn_in' => array('fields'), - 'ts' => $record['datetime']->getTimestamp() + 'fallback' => $message, + 'text' => $message, + 'color' => $this->getAttachmentColor($record['level']), + 'fields' => array(), + 'mrkdwn_in' => array('fields'), + 'ts' => $record['datetime']->getTimestamp(), + 'footer' => $this->username, + 'footer_icon' => $this->userIcon, ); if ($this->useShortAttachment) { @@ -138,7 +163,6 @@ public function getSlackData(array $record) $attachment['fields'][] = $this->generateAttachmentField('Level', $record['level_name']); } - if ($this->includeContextAndExtra) { foreach (array('extra', 'context') as $key) { if (empty($record[$key])) { @@ -147,7 +171,7 @@ public function getSlackData(array $record) if ($this->useShortAttachment) { $attachment['fields'][] = $this->generateAttachmentField( - $key, + (string) $key, $record[$key] ); } else { @@ -177,93 +201,157 @@ public function getSlackData(array $record) } /** - * Returned a Slack message attachment color associated with + * Returns a Slack message attachment color associated with * provided level. - * - * @param int $level - * @return string */ - public function getAttachmentColor($level) + public function getAttachmentColor(int $level): string { switch (true) { case $level >= Logger::ERROR: - return self::COLOR_DANGER; + return static::COLOR_DANGER; case $level >= Logger::WARNING: - return self::COLOR_WARNING; + return static::COLOR_WARNING; case $level >= Logger::INFO: - return self::COLOR_GOOD; + return static::COLOR_GOOD; default: - return self::COLOR_DEFAULT; + return static::COLOR_DEFAULT; } } /** * Stringifies an array of key/value pairs to be used in attachment fields * - * @param array $fields - * - * @return string + * @param mixed[] $fields */ - public function stringify($fields) + public function stringify(array $fields): string { + /** @var Record $fields */ $normalized = $this->normalizerFormatter->format($fields); - $prettyPrintFlag = defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 128; - $flags = 0; - if (PHP_VERSION_ID >= 50400) { - $flags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; - } $hasSecondDimension = count(array_filter($normalized, 'is_array')); $hasNonNumericKeys = !count(array_filter(array_keys($normalized), 'is_numeric')); return $hasSecondDimension || $hasNonNumericKeys - ? Utils::jsonEncode($normalized, $prettyPrintFlag | $flags) - : Utils::jsonEncode($normalized, $flags); + ? Utils::jsonEncode($normalized, JSON_PRETTY_PRINT|Utils::DEFAULT_JSON_FLAGS) + : Utils::jsonEncode($normalized, Utils::DEFAULT_JSON_FLAGS); } /** - * Sets the formatter + * Channel used by the bot when posting + * + * @param ?string $channel * - * @param FormatterInterface $formatter + * @return static + */ + public function setChannel(?string $channel = null): self + { + $this->channel = $channel; + + return $this; + } + + /** + * Username used by the bot when posting + * + * @param ?string $username + * + * @return static + */ + public function setUsername(?string $username = null): self + { + $this->username = $username; + + return $this; + } + + public function useAttachment(bool $useAttachment = true): self + { + $this->useAttachment = $useAttachment; + + return $this; + } + + public function setUserIcon(?string $userIcon = null): self + { + $this->userIcon = $userIcon; + + if (\is_string($userIcon)) { + $this->userIcon = trim($userIcon, ':'); + } + + return $this; + } + + public function useShortAttachment(bool $useShortAttachment = false): self + { + $this->useShortAttachment = $useShortAttachment; + + return $this; + } + + public function includeContextAndExtra(bool $includeContextAndExtra = false): self + { + $this->includeContextAndExtra = $includeContextAndExtra; + + if ($this->includeContextAndExtra) { + $this->normalizerFormatter = new NormalizerFormatter(); + } + + return $this; + } + + /** + * @param string[] $excludeFields */ - public function setFormatter(FormatterInterface $formatter) + public function excludeFields(array $excludeFields = []): self + { + $this->excludeFields = $excludeFields; + + return $this; + } + + public function setFormatter(?FormatterInterface $formatter = null): self { $this->formatter = $formatter; + + return $this; } /** * Generates attachment field * - * @param string $title - * @param string|array $value + * @param string|mixed[] $value * - * @return array + * @return array{title: string, value: string, short: false} */ - private function generateAttachmentField($title, $value) + private function generateAttachmentField(string $title, $value): array { $value = is_array($value) - ? sprintf('```%s```', $this->stringify($value)) + ? sprintf('```%s```', substr($this->stringify($value), 0, 1990)) : $value; return array( 'title' => ucfirst($title), 'value' => $value, - 'short' => false + 'short' => false, ); } /** * Generates a collection of attachment fields from array * - * @param array $data + * @param mixed[] $data * - * @return array + * @return array */ - private function generateAttachmentFields(array $data) + private function generateAttachmentFields(array $data): array { + /** @var Record $data */ + $normalized = $this->normalizerFormatter->format($data); + $fields = array(); - foreach ($this->normalizerFormatter->format($data) as $key => $value) { - $fields[] = $this->generateAttachmentField($key, $value); + foreach ($normalized as $key => $value) { + $fields[] = $this->generateAttachmentField((string) $key, $value); } return $fields; @@ -272,11 +360,11 @@ private function generateAttachmentFields(array $data) /** * Get a copy of record with fields excluded according to $this->excludeFields * - * @param array $record + * @phpstan-param FormattedRecord $record * - * @return array + * @return mixed[] */ - private function excludeFields(array $record) + private function removeExcludedFields(array $record): array { foreach ($this->excludeFields as $field) { $keys = explode('.', $field); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php index 88c4c4d0..a648513e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SlackHandler.php @@ -1,4 +1,4 @@ - * @see https://api.slack.com/ + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SlackHandler extends SocketHandler { @@ -42,20 +44,42 @@ class SlackHandler extends SocketHandler * @param string|null $username Name of a bot * @param bool $useAttachment Whether the message should be added to Slack as attachment (plain text otherwise) * @param string|null $iconEmoji The emoji name to use (or null) - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param bool $useShortAttachment Whether the the context/extra messages added to Slack as attachments are in a short style + * @param bool $useShortAttachment Whether the context/extra messages added to Slack as attachments are in a short style * @param bool $includeContextAndExtra Whether the attachment should include context and extra data - * @param array $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] + * @param string[] $excludeFields Dot separated list of fields to exclude from slack message. E.g. ['context.field1', 'extra.field2'] * @throws MissingExtensionException If no OpenSSL PHP extension configured */ - public function __construct($token, $channel, $username = null, $useAttachment = true, $iconEmoji = null, $level = Logger::CRITICAL, $bubble = true, $useShortAttachment = false, $includeContextAndExtra = false, array $excludeFields = array()) - { + public function __construct( + string $token, + string $channel, + ?string $username = null, + bool $useAttachment = true, + ?string $iconEmoji = null, + $level = Logger::CRITICAL, + bool $bubble = true, + bool $useShortAttachment = false, + bool $includeContextAndExtra = false, + array $excludeFields = array(), + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { if (!extension_loaded('openssl')) { throw new MissingExtensionException('The OpenSSL PHP extension is required to use the SlackHandler'); } - parent::__construct('ssl://slack.com:443', $level, $bubble); + parent::__construct( + 'ssl://slack.com:443', + $level, + $bubble, + $persistent, + $timeout, + $writingTimeout, + $connectionTimeout, + $chunkSize + ); $this->slackRecord = new SlackRecord( $channel, @@ -64,30 +88,26 @@ public function __construct($token, $channel, $username = null, $useAttachment = $iconEmoji, $useShortAttachment, $includeContextAndExtra, - $excludeFields, - $this->formatter + $excludeFields ); $this->token = $token; } - public function getSlackRecord() + public function getSlackRecord(): SlackRecord { return $this->slackRecord; } - public function getToken() + public function getToken(): string { return $this->token; } /** - * {@inheritdoc} - * - * @param array $record - * @return string + * {@inheritDoc} */ - protected function generateDataStream($record) + protected function generateDataStream(array $record): string { $content = $this->buildContent($record); @@ -97,10 +117,9 @@ protected function generateDataStream($record) /** * Builds the body of API call * - * @param array $record - * @return string + * @phpstan-param FormattedRecord $record */ - private function buildContent($record) + private function buildContent(array $record): string { $dataArray = $this->prepareContentData($record); @@ -108,12 +127,10 @@ private function buildContent($record) } /** - * Prepares content data - * - * @param array $record - * @return array + * @phpstan-param FormattedRecord $record + * @return string[] */ - protected function prepareContentData($record) + protected function prepareContentData(array $record): array { $dataArray = $this->slackRecord->getSlackData($record); $dataArray['token'] = $this->token; @@ -127,11 +144,8 @@ protected function prepareContentData($record) /** * Builds the header of the API Call - * - * @param string $content - * @return string */ - private function buildHeader($content) + private function buildHeader(string $content): string { $header = "POST /api/chat.postMessage HTTP/1.1\r\n"; $header .= "Host: slack.com\r\n"; @@ -143,11 +157,9 @@ private function buildHeader($content) } /** - * {@inheritdoc} - * - * @param array $record + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { parent::write($record); $this->finalizeWrite(); @@ -159,7 +171,7 @@ protected function write(array $record) * If we do not read some but close the socket too early, slack sometimes * drops the request entirely. */ - protected function finalizeWrite() + protected function finalizeWrite(): void { $res = $this->getResource(); if (is_resource($res)) { @@ -168,54 +180,77 @@ protected function finalizeWrite() $this->closeSocket(); } + public function setFormatter(FormatterInterface $formatter): HandlerInterface + { + parent::setFormatter($formatter); + $this->slackRecord->setFormatter($formatter); + + return $this; + } + + public function getFormatter(): FormatterInterface + { + $formatter = parent::getFormatter(); + $this->slackRecord->setFormatter($formatter); + + return $formatter; + } + /** - * Returned a Slack message attachment color associated with - * provided level. - * - * @param int $level - * @return string - * @deprecated Use underlying SlackRecord instead + * Channel used by the bot when posting */ - protected function getAttachmentColor($level) + public function setChannel(string $channel): self { - trigger_error( - 'SlackHandler::getAttachmentColor() is deprecated. Use underlying SlackRecord instead.', - E_USER_DEPRECATED - ); + $this->slackRecord->setChannel($channel); - return $this->slackRecord->getAttachmentColor($level); + return $this; } /** - * Stringifies an array of key/value pairs to be used in attachment fields - * - * @param array $fields - * @return string - * @deprecated Use underlying SlackRecord instead + * Username used by the bot when posting */ - protected function stringify($fields) + public function setUsername(string $username): self { - trigger_error( - 'SlackHandler::stringify() is deprecated. Use underlying SlackRecord instead.', - E_USER_DEPRECATED - ); + $this->slackRecord->setUsername($username); - return $this->slackRecord->stringify($fields); + return $this; } - public function setFormatter(FormatterInterface $formatter) + public function useAttachment(bool $useAttachment): self { - parent::setFormatter($formatter); - $this->slackRecord->setFormatter($formatter); + $this->slackRecord->useAttachment($useAttachment); return $this; } - public function getFormatter() + public function setIconEmoji(string $iconEmoji): self { - $formatter = parent::getFormatter(); - $this->slackRecord->setFormatter($formatter); + $this->slackRecord->setUserIcon($iconEmoji); - return $formatter; + return $this; + } + + public function useShortAttachment(bool $useShortAttachment): self + { + $this->slackRecord->useShortAttachment($useShortAttachment); + + return $this; + } + + public function includeContextAndExtra(bool $includeContextAndExtra): self + { + $this->slackRecord->includeContextAndExtra($includeContextAndExtra); + + return $this; + } + + /** + * @param string[] $excludeFields + */ + public function excludeFields(array $excludeFields): self + { + $this->slackRecord->excludeFields($excludeFields); + + return $this; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php index b87be99a..8ae3c788 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SlackWebhookHandler.php @@ -1,4 +1,4 @@ -webhookUrl = $webhookUrl; @@ -61,27 +73,24 @@ public function __construct($webhookUrl, $channel = null, $username = null, $use $iconEmoji, $useShortAttachment, $includeContextAndExtra, - $excludeFields, - $this->formatter + $excludeFields ); } - public function getSlackRecord() + public function getSlackRecord(): SlackRecord { return $this->slackRecord; } - public function getWebhookUrl() + public function getWebhookUrl(): string { return $this->webhookUrl; } /** - * {@inheritdoc} - * - * @param array $record + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $postData = $this->slackRecord->getSlackData($record); $postString = Utils::jsonEncode($postData); @@ -92,7 +101,7 @@ protected function write(array $record) CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => array('Content-type: application/json'), - CURLOPT_POSTFIELDS => $postString + CURLOPT_POSTFIELDS => $postString, ); if (defined('CURLOPT_SAFE_UPLOAD')) { $options[CURLOPT_SAFE_UPLOAD] = true; @@ -103,7 +112,7 @@ protected function write(array $record) Curl\Util::execute($ch); } - public function setFormatter(FormatterInterface $formatter) + public function setFormatter(FormatterInterface $formatter): HandlerInterface { parent::setFormatter($formatter); $this->slackRecord->setFormatter($formatter); @@ -111,7 +120,7 @@ public function setFormatter(FormatterInterface $formatter) return $this; } - public function getFormatter() + public function getFormatter(): FormatterInterface { $formatter = parent::getFormatter(); $this->slackRecord->setFormatter($formatter); diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php deleted file mode 100644 index d3352ea0..00000000 --- a/vendor/monolog/monolog/src/Monolog/Handler/SlackbotHandler.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Monolog\Handler; - -use Monolog\Logger; - -/** - * Sends notifications through Slack's Slackbot - * - * @author Haralan Dobrev - * @see https://slack.com/apps/A0F81R8ET-slackbot - * @deprecated According to Slack the API used on this handler it is deprecated. - * Therefore this handler will be removed on 2.x - * Slack suggests to use webhooks instead. Please contact slack for more information. - */ -class SlackbotHandler extends AbstractProcessingHandler -{ - /** - * The slug of the Slack team - * @var string - */ - private $slackTeam; - - /** - * Slackbot token - * @var string - */ - private $token; - - /** - * Slack channel name - * @var string - */ - private $channel; - - /** - * @param string $slackTeam Slack team slug - * @param string $token Slackbot token - * @param string $channel Slack channel (encoded ID or name) - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - */ - public function __construct($slackTeam, $token, $channel, $level = Logger::CRITICAL, $bubble = true) - { - @trigger_error('SlackbotHandler is deprecated and will be removed on 2.x', E_USER_DEPRECATED); - parent::__construct($level, $bubble); - - $this->slackTeam = $slackTeam; - $this->token = $token; - $this->channel = $channel; - } - - /** - * {@inheritdoc} - * - * @param array $record - */ - protected function write(array $record) - { - $slackbotUrl = sprintf( - 'https://%s.slack.com/services/hooks/slackbot?token=%s&channel=%s', - $this->slackTeam, - $this->token, - $this->channel - ); - - $ch = curl_init(); - curl_setopt($ch, CURLOPT_URL, $slackbotUrl); - curl_setopt($ch, CURLOPT_POST, true); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_POSTFIELDS, $record['message']); - - Curl\Util::execute($ch); - } -} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php index db50d97f..21701afa 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SocketHandler.php @@ -1,4 +1,4 @@ - * @see http://php.net/manual/en/function.fsockopen.php + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class SocketHandler extends AbstractProcessingHandler { + /** @var string */ private $connectionString; + /** @var float */ private $connectionTimeout; + /** @var resource|null */ private $resource; - private $timeout = 0; - private $writingTimeout = 10; + /** @var float */ + private $timeout; + /** @var float */ + private $writingTimeout; + /** @var ?int */ private $lastSentBytes = null; - private $chunkSize = null; - private $persistent = false; - private $errno; - private $errstr; - private $lastWritingAt; + /** @var ?int */ + private $chunkSize; + /** @var bool */ + private $persistent; + /** @var ?int */ + private $errno = null; + /** @var ?string */ + private $errstr = null; + /** @var ?float */ + private $lastWritingAt = null; /** - * @param string $connectionString Socket connection string - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $connectionString Socket connection string + * @param bool $persistent Flag to enable/disable persistent connections + * @param float $timeout Socket timeout to wait until the request is being aborted + * @param float $writingTimeout Socket timeout to wait until the request should've been sent/written + * @param float|null $connectionTimeout Socket connect timeout to wait until the connection should've been + * established + * @param int|null $chunkSize Sets the chunk size. Only has effect during connection in the writing cycle + * + * @throws \InvalidArgumentException If an invalid timeout value (less than 0) is passed. */ - public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) - { + public function __construct( + string $connectionString, + $level = Logger::DEBUG, + bool $bubble = true, + bool $persistent = false, + float $timeout = 0.0, + float $writingTimeout = 10.0, + ?float $connectionTimeout = null, + ?int $chunkSize = null + ) { parent::__construct($level, $bubble); $this->connectionString = $connectionString; - $this->connectionTimeout = (float) ini_get('default_socket_timeout'); + + if ($connectionTimeout !== null) { + $this->validateTimeout($connectionTimeout); + } + + $this->connectionTimeout = $connectionTimeout ?? (float) ini_get('default_socket_timeout'); + $this->persistent = $persistent; + $this->validateTimeout($timeout); + $this->timeout = $timeout; + $this->validateTimeout($writingTimeout); + $this->writingTimeout = $writingTimeout; + $this->chunkSize = $chunkSize; } /** * Connect (if necessary) and write to the socket * - * @param array $record + * {@inheritDoc} * * @throws \UnexpectedValueException * @throws \RuntimeException */ - protected function write(array $record) + protected function write(array $record): void { $this->connectIfNotConnected(); $data = $this->generateDataStream($record); @@ -63,7 +102,7 @@ protected function write(array $record) /** * We will not close a PersistentSocket instance so it can be reused in other requests. */ - public function close() + public function close(): void { if (!$this->isPersistent()) { $this->closeSocket(); @@ -73,7 +112,7 @@ public function close() /** * Close socket, if open */ - public function closeSocket() + public function closeSocket(): void { if (is_resource($this->resource)) { fclose($this->resource); @@ -82,39 +121,39 @@ public function closeSocket() } /** - * Set socket connection to nbe persistent. It only has effect before the connection is initiated. - * - * @param bool $persistent + * Set socket connection to be persistent. It only has effect before the connection is initiated. */ - public function setPersistent($persistent) + public function setPersistent(bool $persistent): self { - $this->persistent = (bool) $persistent; + $this->persistent = $persistent; + + return $this; } /** * Set connection timeout. Only has effect before we connect. * - * @param float $seconds - * * @see http://php.net/manual/en/function.fsockopen.php */ - public function setConnectionTimeout($seconds) + public function setConnectionTimeout(float $seconds): self { $this->validateTimeout($seconds); - $this->connectionTimeout = (float) $seconds; + $this->connectionTimeout = $seconds; + + return $this; } /** * Set write timeout. Only has effect before we connect. * - * @param float $seconds - * * @see http://php.net/manual/en/function.stream-set-timeout.php */ - public function setTimeout($seconds) + public function setTimeout(float $seconds): self { $this->validateTimeout($seconds); - $this->timeout = (float) $seconds; + $this->timeout = $seconds; + + return $this; } /** @@ -122,58 +161,52 @@ public function setTimeout($seconds) * * @param float $seconds 0 for no timeout */ - public function setWritingTimeout($seconds) + public function setWritingTimeout(float $seconds): self { $this->validateTimeout($seconds); - $this->writingTimeout = (float) $seconds; + $this->writingTimeout = $seconds; + + return $this; } /** * Set chunk size. Only has effect during connection in the writing cycle. - * - * @param float $bytes */ - public function setChunkSize($bytes) + public function setChunkSize(int $bytes): self { $this->chunkSize = $bytes; + + return $this; } /** * Get current connection string - * - * @return string */ - public function getConnectionString() + public function getConnectionString(): string { return $this->connectionString; } /** * Get persistent setting - * - * @return bool */ - public function isPersistent() + public function isPersistent(): bool { return $this->persistent; } /** * Get current connection timeout setting - * - * @return float */ - public function getConnectionTimeout() + public function getConnectionTimeout(): float { return $this->connectionTimeout; } /** * Get current in-transfer timeout - * - * @return float */ - public function getTimeout() + public function getTimeout(): float { return $this->timeout; } @@ -183,17 +216,15 @@ public function getTimeout() * * @return float */ - public function getWritingTimeout() + public function getWritingTimeout(): float { return $this->writingTimeout; } /** * Get current chunk size - * - * @return float */ - public function getChunkSize() + public function getChunkSize(): ?int { return $this->chunkSize; } @@ -202,10 +233,8 @@ public function getChunkSize() * Check to see if the socket is currently available. * * UDP might appear to be connected but might fail when writing. See http://php.net/fsockopen for details. - * - * @return bool */ - public function isConnected() + public function isConnected(): bool { return is_resource($this->resource) && !feof($this->resource); // on TCP - other party can close connection. @@ -213,6 +242,8 @@ public function isConnected() /** * Wrapper to allow mocking + * + * @return resource|false */ protected function pfsockopen() { @@ -221,6 +252,8 @@ protected function pfsockopen() /** * Wrapper to allow mocking + * + * @return resource|false */ protected function fsockopen() { @@ -231,50 +264,77 @@ protected function fsockopen() * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-timeout.php + * + * @return bool */ protected function streamSetTimeout() { $seconds = floor($this->timeout); $microseconds = round(($this->timeout - $seconds) * 1e6); - return stream_set_timeout($this->resource, $seconds, $microseconds); + if (!is_resource($this->resource)) { + throw new \LogicException('streamSetTimeout called but $this->resource is not a resource'); + } + + return stream_set_timeout($this->resource, (int) $seconds, (int) $microseconds); } /** * Wrapper to allow mocking * * @see http://php.net/manual/en/function.stream-set-chunk-size.php + * + * @return int|bool */ protected function streamSetChunkSize() { + if (!is_resource($this->resource)) { + throw new \LogicException('streamSetChunkSize called but $this->resource is not a resource'); + } + + if (null === $this->chunkSize) { + throw new \LogicException('streamSetChunkSize called but $this->chunkSize is not set'); + } + return stream_set_chunk_size($this->resource, $this->chunkSize); } /** * Wrapper to allow mocking + * + * @return int|bool */ - protected function fwrite($data) + protected function fwrite(string $data) { + if (!is_resource($this->resource)) { + throw new \LogicException('fwrite called but $this->resource is not a resource'); + } + return @fwrite($this->resource, $data); } /** * Wrapper to allow mocking + * + * @return mixed[]|bool */ protected function streamGetMetadata() { + if (!is_resource($this->resource)) { + throw new \LogicException('streamGetMetadata called but $this->resource is not a resource'); + } + return stream_get_meta_data($this->resource); } - private function validateTimeout($value) + private function validateTimeout(float $value): void { - $ok = filter_var($value, FILTER_VALIDATE_FLOAT); - if ($ok === false || $value < 0) { + if ($value < 0) { throw new \InvalidArgumentException("Timeout must be 0 or a positive float (got $value)"); } } - private function connectIfNotConnected() + private function connectIfNotConnected(): void { if ($this->isConnected()) { return; @@ -282,7 +342,10 @@ private function connectIfNotConnected() $this->connect(); } - protected function generateDataStream($record) + /** + * @phpstan-param FormattedRecord $record + */ + protected function generateDataStream(array $record): string { return (string) $record['formatted']; } @@ -295,41 +358,41 @@ protected function getResource() return $this->resource; } - private function connect() + private function connect(): void { $this->createSocketResource(); $this->setSocketTimeout(); $this->setStreamChunkSize(); } - private function createSocketResource() + private function createSocketResource(): void { if ($this->isPersistent()) { $resource = $this->pfsockopen(); } else { $resource = $this->fsockopen(); } - if (!$resource) { + if (is_bool($resource)) { throw new \UnexpectedValueException("Failed connecting to $this->connectionString ($this->errno: $this->errstr)"); } $this->resource = $resource; } - private function setSocketTimeout() + private function setSocketTimeout(): void { if (!$this->streamSetTimeout()) { throw new \UnexpectedValueException("Failed setting timeout with stream_set_timeout()"); } } - private function setStreamChunkSize() + private function setStreamChunkSize(): void { if ($this->chunkSize && !$this->streamSetChunkSize()) { throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()"); } } - private function writeToSocket($data) + private function writeToSocket(string $data): void { $length = strlen($data); $sent = 0; @@ -345,7 +408,7 @@ private function writeToSocket($data) } $sent += $chunk; $socketInfo = $this->streamGetMetadata(); - if ($socketInfo['timed_out']) { + if (is_array($socketInfo) && $socketInfo['timed_out']) { throw new \RuntimeException("Write timed-out"); } @@ -358,15 +421,15 @@ private function writeToSocket($data) } } - private function writingIsTimedOut($sent) + private function writingIsTimedOut(int $sent): bool { - $writingTimeout = (int) floor($this->writingTimeout); - if (0 === $writingTimeout) { + // convert to ms + if (0.0 == $this->writingTimeout) { return false; } if ($sent !== $this->lastSentBytes) { - $this->lastWritingAt = time(); + $this->lastWritingAt = microtime(true); $this->lastSentBytes = $sent; return false; @@ -374,7 +437,7 @@ private function writingIsTimedOut($sent) usleep(100); } - if ((time() - $this->lastWritingAt) >= $writingTimeout) { + if ((microtime(true) - $this->lastWritingAt) >= $this->writingTimeout) { $this->closeSocket(); return true; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SqsHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SqsHandler.php new file mode 100644 index 00000000..dcf282b4 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/SqsHandler.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Aws\Sqs\SqsClient; +use Monolog\Logger; +use Monolog\Utils; + +/** + * Writes to any sqs queue. + * + * @author Martijn van Calker + */ +class SqsHandler extends AbstractProcessingHandler +{ + /** 256 KB in bytes - maximum message size in SQS */ + protected const MAX_MESSAGE_SIZE = 262144; + /** 100 KB in bytes - head message size for new error log */ + protected const HEAD_MESSAGE_SIZE = 102400; + + /** @var SqsClient */ + private $client; + /** @var string */ + private $queueUrl; + + public function __construct(SqsClient $sqsClient, string $queueUrl, $level = Logger::DEBUG, bool $bubble = true) + { + parent::__construct($level, $bubble); + + $this->client = $sqsClient; + $this->queueUrl = $queueUrl; + } + + /** + * {@inheritDoc} + */ + protected function write(array $record): void + { + if (!isset($record['formatted']) || 'string' !== gettype($record['formatted'])) { + throw new \InvalidArgumentException('SqsHandler accepts only formatted records as a string' . Utils::getRecordMessageForException($record)); + } + + $messageBody = $record['formatted']; + if (strlen($messageBody) >= static::MAX_MESSAGE_SIZE) { + $messageBody = Utils::substr($messageBody, 0, static::HEAD_MESSAGE_SIZE); + } + + $this->client->sendMessage([ + 'QueueUrl' => $this->queueUrl, + 'MessageBody' => $messageBody, + ]); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php index 74a613cb..65183512 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class StreamHandler extends AbstractProcessingHandler { - /** @private 512KB */ - const CHUNK_SIZE = 524288; - + /** @const int */ + protected const MAX_CHUNK_SIZE = 2147483647; + /** @const int 10MB */ + protected const DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024; + /** @var int */ + protected $streamChunkSize; /** @var resource|null */ protected $stream; - protected $url; - private $errorMessage; + /** @var ?string */ + protected $url = null; + /** @var ?string */ + private $errorMessage = null; + /** @var ?int */ protected $filePermission; + /** @var bool */ protected $useLocking; - private $dirCreated; + /** @var true|null */ + private $dirCreated = null; /** - * @param resource|string $stream - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param resource|string $stream If a missing path can't be created, an UnexpectedValueException will be thrown on first write * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param bool $useLocking Try to lock log file before doing any writes * - * @throws \Exception If a missing directory is not buildable * @throws \InvalidArgumentException If stream is not a resource or string */ - public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false) + public function __construct($stream, $level = Logger::DEBUG, bool $bubble = true, ?int $filePermission = null, bool $useLocking = false) { parent::__construct($level, $bubble); + + if (($phpMemoryLimit = Utils::expandIniShorthandBytes(ini_get('memory_limit'))) !== false) { + if ($phpMemoryLimit > 0) { + // use max 10% of allowed memory for the chunk size, and at least 100KB + $this->streamChunkSize = min(static::MAX_CHUNK_SIZE, max((int) ($phpMemoryLimit / 10), 100 * 1024)); + } else { + // memory is unlimited, set to the default 10MB + $this->streamChunkSize = static::DEFAULT_CHUNK_SIZE; + } + } else { + // no memory limit information, set to the default 10MB + $this->streamChunkSize = static::DEFAULT_CHUNK_SIZE; + } + if (is_resource($stream)) { $this->stream = $stream; - $this->streamSetChunkSize(); + + stream_set_chunk_size($this->stream, $this->streamChunkSize); } elseif (is_string($stream)) { $this->url = Utils::canonicalizePath($stream); } else { @@ -61,9 +83,9 @@ public function __construct($stream, $level = Logger::DEBUG, $bubble = true, $fi } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function close() + public function close(): void { if ($this->url && is_resource($this->stream)) { fclose($this->stream); @@ -87,78 +109,83 @@ public function getStream() * * @return string|null */ - public function getUrl() + public function getUrl(): ?string { return $this->url; } /** - * {@inheritdoc} + * @return int + */ + public function getStreamChunkSize(): int + { + return $this->streamChunkSize; + } + + /** + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!is_resource($this->stream)) { - if (null === $this->url || '' === $this->url) { - throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().'); + $url = $this->url; + if (null === $url || '' === $url) { + throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().' . Utils::getRecordMessageForException($record)); } - $this->createDir(); + $this->createDir($url); $this->errorMessage = null; - set_error_handler(array($this, 'customErrorHandler')); - $this->stream = fopen($this->url, 'a'); + set_error_handler([$this, 'customErrorHandler']); + $stream = fopen($url, 'a'); if ($this->filePermission !== null) { - @chmod($this->url, $this->filePermission); + @chmod($url, $this->filePermission); } restore_error_handler(); - if (!is_resource($this->stream)) { + if (!is_resource($stream)) { $this->stream = null; - throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $this->url)); + throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage, $url) . Utils::getRecordMessageForException($record)); } - $this->streamSetChunkSize(); + stream_set_chunk_size($stream, $this->streamChunkSize); + $this->stream = $stream; + } + + $stream = $this->stream; + if (!is_resource($stream)) { + throw new \LogicException('No stream was opened yet' . Utils::getRecordMessageForException($record)); } if ($this->useLocking) { // ignoring errors here, there's not much we can do about them - flock($this->stream, LOCK_EX); + flock($stream, LOCK_EX); } - $this->streamWrite($this->stream, $record); + $this->streamWrite($stream, $record); if ($this->useLocking) { - flock($this->stream, LOCK_UN); + flock($stream, LOCK_UN); } } /** * Write to stream * @param resource $stream - * @param array $record + * @param array $record + * + * @phpstan-param FormattedRecord $record */ - protected function streamWrite($stream, array $record) + protected function streamWrite($stream, array $record): void { fwrite($stream, (string) $record['formatted']); } - protected function streamSetChunkSize() - { - if (version_compare(PHP_VERSION, '5.4.0', '>=')) { - return stream_set_chunk_size($this->stream, self::CHUNK_SIZE); - } - - return false; - } - - private function customErrorHandler($code, $msg) + private function customErrorHandler(int $code, string $msg): bool { $this->errorMessage = preg_replace('{^(fopen|mkdir)\(.*?\): }', '', $msg); + + return true; } - /** - * @param string $stream - * - * @return null|string - */ - private function getDirFromStream($stream) + private function getDirFromStream(string $stream): ?string { $pos = strpos($stream, '://'); if ($pos === false) { @@ -172,21 +199,21 @@ private function getDirFromStream($stream) return null; } - private function createDir() + private function createDir(string $url): void { // Do not try to create dir if it has already been tried. if ($this->dirCreated) { return; } - $dir = $this->getDirFromStream($this->url); + $dir = $this->getDirFromStream($url); if (null !== $dir && !is_dir($dir)) { $this->errorMessage = null; - set_error_handler(array($this, 'customErrorHandler')); + set_error_handler([$this, 'customErrorHandler']); $status = mkdir($dir, 0777, true); restore_error_handler(); - if (false === $status && !is_dir($dir)) { - throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir)); + if (false === $status && !is_dir($dir) && strpos((string) $this->errorMessage, 'File exists') === false) { + throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and it could not be created: '.$this->errorMessage, $dir)); } } $this->dirCreated = true; diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php index ac7b16ff..fae92514 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SwiftMailerHandler.php @@ -1,4 +1,4 @@ -mailer = $mailer; $this->messageTemplate = $message; } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function send($content, array $records) + protected function send(string $content, array $records): void { $this->mailer->send($this->buildMessage($content, $records)); } @@ -51,10 +60,9 @@ protected function send($content, array $records) /** * Gets the formatter for the Swift_Message subject. * - * @param string $format The format of the subject - * @return FormatterInterface + * @param string|null $format The format of the subject */ - protected function getSubjectFormatter($format) + protected function getSubjectFormatter(?string $format): FormatterInterface { return new LineFormatter($format); } @@ -62,22 +70,25 @@ protected function getSubjectFormatter($format) /** * Creates instance of Swift_Message to be sent * - * @param string $content formatted email body to be sent - * @param array $records Log records that formed the content - * @return \Swift_Message + * @param string $content formatted email body to be sent + * @param array $records Log records that formed the content + * @return Swift_Message + * + * @phpstan-param Record[] $records */ - protected function buildMessage($content, array $records) + protected function buildMessage(string $content, array $records): Swift_Message { $message = null; - if ($this->messageTemplate instanceof \Swift_Message) { + if ($this->messageTemplate instanceof Swift_Message) { $message = clone $this->messageTemplate; $message->generateId(); } elseif (is_callable($this->messageTemplate)) { - $message = call_user_func($this->messageTemplate, $content, $records); + $message = ($this->messageTemplate)($content, $records); } - if (!$message instanceof \Swift_Message) { - throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it'); + if (!$message instanceof Swift_Message) { + $record = reset($records); + throw new \InvalidArgumentException('Could not resolve message as instance of Swift_Message or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : '')); } if ($records) { @@ -85,27 +96,20 @@ protected function buildMessage($content, array $records) $message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); } - $message->setBody($content); + $mime = 'text/plain'; + if ($this->isHtmlBody($content)) { + $mime = 'text/html'; + } + + $message->setBody($content, $mime); + /** @phpstan-ignore-next-line */ if (version_compare(Swift::VERSION, '6.0.0', '>=')) { $message->setDate(new \DateTimeImmutable()); } else { + /** @phpstan-ignore-next-line */ $message->setDate(time()); } return $message; } - - /** - * BC getter, to be removed in 2.0 - */ - public function __get($name) - { - if ($name === 'message') { - trigger_error('SwiftMailerHandler->message is deprecated, use ->buildMessage() instead to retrieve the message', E_USER_DEPRECATED); - - return $this->buildMessage(null, array()); - } - - throw new \InvalidArgumentException('Invalid property '.$name); - } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SymfonyMailerHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SymfonyMailerHandler.php new file mode 100644 index 00000000..130e6f1f --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/SymfonyMailerHandler.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use Monolog\Logger; +use Monolog\Utils; +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LineFormatter; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mailer\Transport\TransportInterface; +use Symfony\Component\Mime\Email; + +/** + * SymfonyMailerHandler uses Symfony's Mailer component to send the emails + * + * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + */ +class SymfonyMailerHandler extends MailHandler +{ + /** @var MailerInterface|TransportInterface */ + protected $mailer; + /** @var Email|callable(string, Record[]): Email */ + private $emailTemplate; + + /** + * @psalm-param Email|callable(string, Record[]): Email $email + * + * @param MailerInterface|TransportInterface $mailer The mailer to use + * @param callable|Email $email An email template, the subject/body will be replaced + */ + public function __construct($mailer, $email, $level = Logger::ERROR, bool $bubble = true) + { + parent::__construct($level, $bubble); + + $this->mailer = $mailer; + $this->emailTemplate = $email; + } + + /** + * {@inheritDoc} + */ + protected function send(string $content, array $records): void + { + $this->mailer->send($this->buildMessage($content, $records)); + } + + /** + * Gets the formatter for the Swift_Message subject. + * + * @param string|null $format The format of the subject + */ + protected function getSubjectFormatter(?string $format): FormatterInterface + { + return new LineFormatter($format); + } + + /** + * Creates instance of Email to be sent + * + * @param string $content formatted email body to be sent + * @param array $records Log records that formed the content + * + * @phpstan-param Record[] $records + */ + protected function buildMessage(string $content, array $records): Email + { + $message = null; + if ($this->emailTemplate instanceof Email) { + $message = clone $this->emailTemplate; + } elseif (is_callable($this->emailTemplate)) { + $message = ($this->emailTemplate)($content, $records); + } + + if (!$message instanceof Email) { + $record = reset($records); + throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it' . ($record ? Utils::getRecordMessageForException($record) : '')); + } + + if ($records) { + $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); + $message->subject($subjectFormatter->format($this->getHighestRecord($records))); + } + + if ($this->isHtmlBody($content)) { + if (null !== ($charset = $message->getHtmlCharset())) { + $message->html($content, $charset); + } else { + $message->html($content); + } + } else { + if (null !== ($charset = $message->getTextCharset())) { + $message->text($content, $charset); + } else { + $message->text($content); + } + } + + return $message->date(new \DateTimeImmutable()); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php index f770c802..1d543b7e 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogHandler.php @@ -1,4 +1,4 @@ -facilities, or a LOG_* facility constant + * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID */ - public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) + public function __construct(string $ident, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, int $logopts = LOG_PID) { parent::__construct($facility, $level, $bubble); @@ -47,20 +48,20 @@ public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function close() + public function close(): void { closelog(); } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { if (!openlog($this->ident, $this->logopts, $this->facility)) { - throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"'); + throw new \LogicException('Can\'t open syslog for ident "'.$this->ident.'" and facility "'.$this->facility.'"' . Utils::getRecordMessageForException($record)); } syslog($this->logLevels[$record['level']], (string) $record['formatted']); } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php index 3bff085b..dbd8ef69 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdp/UdpSocket.php @@ -1,4 +1,4 @@ -ip = $ip; $this->port = $port; - $this->socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); } + /** + * @param string $line + * @param string $header + * @return void + */ public function write($line, $header = "") { $this->send($this->assembleMessage($line, $header)); } - public function close() + public function close(): void { - if (is_resource($this->socket)) { + if (is_resource($this->socket) || $this->socket instanceof Socket) { socket_close($this->socket); $this->socket = null; } } - protected function send($chunk) + /** + * @return resource|Socket + */ + protected function getSocket() { - if (!is_resource($this->socket)) { - throw new \LogicException('The UdpSocket to '.$this->ip.':'.$this->port.' has been closed and can not be written to anymore'); + if (null !== $this->socket) { + return $this->socket; + } + + $domain = AF_INET; + $protocol = SOL_UDP; + // Check if we are using unix sockets. + if ($this->port === 0) { + $domain = AF_UNIX; + $protocol = IPPROTO_IP; + } + + $this->socket = socket_create($domain, SOCK_DGRAM, $protocol) ?: null; + if (null === $this->socket) { + throw new \RuntimeException('The UdpSocket to '.$this->ip.':'.$this->port.' could not be opened via socket_create'); } - socket_sendto($this->socket, $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); + + return $this->socket; + } + + protected function send(string $chunk): void + { + socket_sendto($this->getSocket(), $chunk, strlen($chunk), $flags = 0, $this->ip, $this->port); } - protected function assembleMessage($line, $header) + protected function assembleMessage(string $line, string $header): string { - $chunkSize = self::DATAGRAM_MAX_LENGTH - strlen($header); + $chunkSize = static::DATAGRAM_MAX_LENGTH - strlen($header); - return $header . substr($line, 0, $chunkSize); + return $header . Utils::substr($line, 0, $chunkSize); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php index 4dfd5f5e..deaa19f8 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/SyslogUdpHandler.php @@ -1,4 +1,4 @@ - */ private $dateFormats = array( self::RFC3164 => 'M d H:i:s', self::RFC5424 => \DateTime::RFC3339, + self::RFC5424e => \DateTime::RFC3339_EXTENDED, ); + /** @var UdpSocket */ protected $socket; + /** @var string */ protected $ident; + /** @var self::RFC* */ protected $rfc; /** - * @param string $host - * @param int $port - * @param mixed $facility - * @param int $level The minimum logging level at which this handler will be triggered - * @param bool $bubble Whether the messages that are handled can bubble up the stack or not - * @param string $ident Program name or tag for each log message. - * @param int $rfc RFC to format the message for. + * @param string $host Either IP/hostname or a path to a unix socket (port must be 0 then) + * @param int $port Port number, or 0 if $host is a unix socket + * @param string|int $facility Either one of the names of the keys in $this->facilities, or a LOG_* facility constant + * @param bool $bubble Whether the messages that are handled can bubble up the stack or not + * @param string $ident Program name or tag for each log message. + * @param int $rfc RFC to format the message for. + * @throws MissingExtensionException + * + * @phpstan-param self::RFC* $rfc */ - public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php', $rfc = self::RFC5424) + public function __construct(string $host, int $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, bool $bubble = true, string $ident = 'php', int $rfc = self::RFC5424) { + if (!extension_loaded('sockets')) { + throw new MissingExtensionException('The sockets extension is required to use the SyslogUdpHandler'); + } + parent::__construct($facility, $level, $bubble); $this->ident = $ident; $this->rfc = $rfc; - $this->socket = new UdpSocket($host, $port ?: 514); + $this->socket = new UdpSocket($host, $port); } - protected function write(array $record) + protected function write(array $record): void { $lines = $this->splitMessageIntoLines($record['formatted']); - $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']]); + $header = $this->makeCommonSyslogHeader($this->logLevels[$record['level']], $record['datetime']); foreach ($lines as $line) { $this->socket->write($line, $header); } } - public function close() + public function close(): void { $this->socket->close(); } - private function splitMessageIntoLines($message) + /** + * @param string|string[] $message + * @return string[] + */ + private function splitMessageIntoLines($message): array { if (is_array($message)) { $message = implode("\n", $message); } - return preg_split('/$\R?^/m', $message, -1, PREG_SPLIT_NO_EMPTY); + $lines = preg_split('/$\R?^/m', (string) $message, -1, PREG_SPLIT_NO_EMPTY); + if (false === $lines) { + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Could not preg_split: ' . $pcreErrorCode . ' / ' . Utils::pcreLastErrorMessage($pcreErrorCode)); + } + + return $lines; } /** * Make common syslog header (see rfc5424 or rfc3164) */ - protected function makeCommonSyslogHeader($severity) + protected function makeCommonSyslogHeader(int $severity, DateTimeInterface $datetime): string { $priority = $severity + $this->facility; @@ -93,32 +117,34 @@ protected function makeCommonSyslogHeader($severity) $hostname = '-'; } - $date = $this->getDateTime(); - if ($this->rfc === self::RFC3164) { + // see https://github.com/phpstan/phpstan/issues/5348 + // @phpstan-ignore-next-line + $dateNew = $datetime->setTimezone(new \DateTimeZone('UTC')); + $date = $dateNew->format($this->dateFormats[$this->rfc]); + return "<$priority>" . $date . " " . $hostname . " " . $this->ident . "[" . $pid . "]: "; - } else { - return "<$priority>1 " . - $date . " " . - $hostname . " " . - $this->ident . " " . - $pid . " - - "; } - } - protected function getDateTime() - { - return date($this->dateFormats[$this->rfc]); + $date = $datetime->format($this->dateFormats[$this->rfc]); + + return "<$priority>1 " . + $date . " " . + $hostname . " " . + $this->ident . " " . + $pid . " - - "; } /** * Inject your own socket, mainly used for testing */ - public function setSocket($socket) + public function setSocket(UdpSocket $socket): self { $this->socket = $socket; + + return $this; } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/TelegramBotHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/TelegramBotHandler.php new file mode 100644 index 00000000..8912eba5 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/TelegramBotHandler.php @@ -0,0 +1,274 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +use RuntimeException; +use Monolog\Logger; +use Monolog\Utils; + +/** + * Handler send logs to Telegram using Telegram Bot API. + * + * How to use: + * 1) Create telegram bot with https://telegram.me/BotFather + * 2) Create a telegram channel where logs will be recorded. + * 3) Add created bot from step 1 to the created channel from step 2. + * + * Use telegram bot API key from step 1 and channel name with '@' prefix from step 2 to create instance of TelegramBotHandler + * + * @link https://core.telegram.org/bots/api + * + * @author Mazur Alexandr + * + * @phpstan-import-type Record from \Monolog\Logger + */ +class TelegramBotHandler extends AbstractProcessingHandler +{ + private const BOT_API = 'https://api.telegram.org/bot'; + + /** + * The available values of parseMode according to the Telegram api documentation + */ + private const AVAILABLE_PARSE_MODES = [ + 'HTML', + 'MarkdownV2', + 'Markdown', // legacy mode without underline and strikethrough, use MarkdownV2 instead + ]; + + /** + * The maximum number of characters allowed in a message according to the Telegram api documentation + */ + private const MAX_MESSAGE_LENGTH = 4096; + + /** + * Telegram bot access token provided by BotFather. + * Create telegram bot with https://telegram.me/BotFather and use access token from it. + * @var string + */ + private $apiKey; + + /** + * Telegram channel name. + * Since to start with '@' symbol as prefix. + * @var string + */ + private $channel; + + /** + * The kind of formatting that is used for the message. + * See available options at https://core.telegram.org/bots/api#formatting-options + * or in AVAILABLE_PARSE_MODES + * @var ?string + */ + private $parseMode; + + /** + * Disables link previews for links in the message. + * @var ?bool + */ + private $disableWebPagePreview; + + /** + * Sends the message silently. Users will receive a notification with no sound. + * @var ?bool + */ + private $disableNotification; + + /** + * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages. + * False - truncates a message that is too long. + * @var bool + */ + private $splitLongMessages; + + /** + * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests). + * @var bool + */ + private $delayBetweenMessages; + + /** + * @param string $apiKey Telegram bot access token provided by BotFather + * @param string $channel Telegram channel name + * @param bool $splitLongMessages Split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages + * @param bool $delayBetweenMessages Adds delay between sending a split message according to Telegram API + * @throws MissingExtensionException + */ + public function __construct( + string $apiKey, + string $channel, + $level = Logger::DEBUG, + bool $bubble = true, + string $parseMode = null, + bool $disableWebPagePreview = null, + bool $disableNotification = null, + bool $splitLongMessages = false, + bool $delayBetweenMessages = false + ) + { + if (!extension_loaded('curl')) { + throw new MissingExtensionException('The curl extension is needed to use the TelegramBotHandler'); + } + + parent::__construct($level, $bubble); + + $this->apiKey = $apiKey; + $this->channel = $channel; + $this->setParseMode($parseMode); + $this->disableWebPagePreview($disableWebPagePreview); + $this->disableNotification($disableNotification); + $this->splitLongMessages($splitLongMessages); + $this->delayBetweenMessages($delayBetweenMessages); + } + + public function setParseMode(string $parseMode = null): self + { + if ($parseMode !== null && !in_array($parseMode, self::AVAILABLE_PARSE_MODES)) { + throw new \InvalidArgumentException('Unknown parseMode, use one of these: ' . implode(', ', self::AVAILABLE_PARSE_MODES) . '.'); + } + + $this->parseMode = $parseMode; + + return $this; + } + + public function disableWebPagePreview(bool $disableWebPagePreview = null): self + { + $this->disableWebPagePreview = $disableWebPagePreview; + + return $this; + } + + public function disableNotification(bool $disableNotification = null): self + { + $this->disableNotification = $disableNotification; + + return $this; + } + + /** + * True - split a message longer than MAX_MESSAGE_LENGTH into parts and send in multiple messages. + * False - truncates a message that is too long. + * @param bool $splitLongMessages + * @return $this + */ + public function splitLongMessages(bool $splitLongMessages = false): self + { + $this->splitLongMessages = $splitLongMessages; + + return $this; + } + + /** + * Adds 1-second delay between sending a split message (according to Telegram API to avoid 429 Too Many Requests). + * @param bool $delayBetweenMessages + * @return $this + */ + public function delayBetweenMessages(bool $delayBetweenMessages = false): self + { + $this->delayBetweenMessages = $delayBetweenMessages; + + return $this; + } + + /** + * {@inheritDoc} + */ + public function handleBatch(array $records): void + { + /** @var Record[] $messages */ + $messages = []; + + foreach ($records as $record) { + if (!$this->isHandling($record)) { + continue; + } + + if ($this->processors) { + /** @var Record $record */ + $record = $this->processRecord($record); + } + + $messages[] = $record; + } + + if (!empty($messages)) { + $this->send((string)$this->getFormatter()->formatBatch($messages)); + } + } + + /** + * @inheritDoc + */ + protected function write(array $record): void + { + $this->send($record['formatted']); + } + + /** + * Send request to @link https://api.telegram.org/bot on SendMessage action. + * @param string $message + */ + protected function send(string $message): void + { + $messages = $this->handleMessageLength($message); + + foreach ($messages as $key => $msg) { + if ($this->delayBetweenMessages && $key > 0) { + sleep(1); + } + + $this->sendCurl($msg); + } + } + + protected function sendCurl(string $message): void + { + $ch = curl_init(); + $url = self::BOT_API . $this->apiKey . '/SendMessage'; + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ + 'text' => $message, + 'chat_id' => $this->channel, + 'parse_mode' => $this->parseMode, + 'disable_web_page_preview' => $this->disableWebPagePreview, + 'disable_notification' => $this->disableNotification, + ])); + + $result = Curl\Util::execute($ch); + if (!is_string($result)) { + throw new RuntimeException('Telegram API error. Description: No response'); + } + $result = json_decode($result, true); + + if ($result['ok'] === false) { + throw new RuntimeException('Telegram API error. Description: ' . $result['description']); + } + } + + /** + * Handle a message that is too long: truncates or splits into several + * @param string $message + * @return string[] + */ + private function handleMessageLength(string $message): array + { + $truncatedMarker = ' (...truncated)'; + if (!$this->splitLongMessages && strlen($message) > self::MAX_MESSAGE_LENGTH) { + return [Utils::substr($message, 0, self::MAX_MESSAGE_LENGTH - strlen($truncatedMarker)) . $truncatedMarker]; + } + + return str_split($message, self::MAX_MESSAGE_LENGTH); + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php index 478db0ac..0986da27 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/TestHandler.php @@ -1,4 +1,4 @@ - */ + protected $recordsByLevel = []; + /** @var bool */ private $skipReset = false; + /** + * @return array + * + * @phpstan-return Record[] + */ public function getRecords() { return $this->records; } + /** + * @return void + */ public function clear() { - $this->records = array(); - $this->recordsByLevel = array(); + $this->records = []; + $this->recordsByLevel = []; } + /** + * @return void + */ public function reset() { if (!$this->skipReset) { @@ -87,21 +108,32 @@ public function reset() } } - public function setSkipReset($skipReset) + /** + * @return void + */ + public function setSkipReset(bool $skipReset) { $this->skipReset = $skipReset; } - public function hasRecords($level) + /** + * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ + public function hasRecords($level): bool { - return isset($this->recordsByLevel[$level]); + return isset($this->recordsByLevel[Logger::toMonologLevel($level)]); } /** * @param string|array $record Either a message string or an array containing message and optionally context keys that will be checked against all records - * @param int $level Logger::LEVEL constant value + * @param string|int $level Logging level value or name + * + * @phpstan-param array{message: string, context?: mixed[]}|string $record + * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function hasRecord($record, $level) + public function hasRecord($record, $level): bool { if (is_string($record)) { $record = array('message' => $record); @@ -114,36 +146,52 @@ public function hasRecord($record, $level) if (isset($record['context']) && $rec['context'] !== $record['context']) { return false; } + return true; }, $level); } - public function hasRecordThatContains($message, $level) + /** + * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ + public function hasRecordThatContains(string $message, $level): bool { return $this->hasRecordThatPasses(function ($rec) use ($message) { return strpos($rec['message'], $message) !== false; }, $level); } - public function hasRecordThatMatches($regex, $level) + /** + * @param string|int $level Logging level value or name + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ + public function hasRecordThatMatches(string $regex, $level): bool { - return $this->hasRecordThatPasses(function ($rec) use ($regex) { + return $this->hasRecordThatPasses(function (array $rec) use ($regex): bool { return preg_match($regex, $rec['message']) > 0; }, $level); } - public function hasRecordThatPasses($predicate, $level) + /** + * @param string|int $level Logging level value or name + * @return bool + * + * @psalm-param callable(Record, int): mixed $predicate + * @phpstan-param Level|LevelName|LogLevel::* $level + */ + public function hasRecordThatPasses(callable $predicate, $level) { - if (!is_callable($predicate)) { - throw new \InvalidArgumentException("Expected a callable for hasRecordThatSucceeds"); - } + $level = Logger::toMonologLevel($level); if (!isset($this->recordsByLevel[$level])) { return false; } foreach ($this->recordsByLevel[$level] as $i => $rec) { - if (call_user_func($predicate, $rec, $i)) { + if ($predicate($rec, $i)) { return true; } } @@ -152,23 +200,29 @@ public function hasRecordThatPasses($predicate, $level) } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->recordsByLevel[$record['level']][] = $record; $this->records[] = $record; } + /** + * @param string $method + * @param mixed[] $args + * @return bool + */ public function __call($method, $args) { if (preg_match('/(.*)(Debug|Info|Notice|Warning|Error|Critical|Alert|Emergency)(.*)/', $method, $matches) > 0) { $genericMethod = $matches[1] . ('Records' !== $matches[3] ? 'Record' : '') . $matches[3]; $level = constant('Monolog\Logger::' . strtoupper($matches[2])); - if (method_exists($this, $genericMethod)) { + $callback = [$this, $genericMethod]; + if (is_callable($callback)) { $args[] = $level; - return call_user_func_array(array($this, $genericMethod), $args); + return call_user_func_array($callback, $args); } } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/WebRequestRecognizerTrait.php b/vendor/monolog/monolog/src/Monolog/Handler/WebRequestRecognizerTrait.php new file mode 100644 index 00000000..c8183528 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Handler/WebRequestRecognizerTrait.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Handler; + +trait WebRequestRecognizerTrait +{ + /** + * Checks if PHP's serving a web request + * @return bool + */ + protected function isWebRequest(): bool + { + return 'cli' !== \PHP_SAPI && 'phpdbg' !== \PHP_SAPI; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php index 7d7622a3..b6d3d3b1 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/WhatFailureGroupHandler.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ class WhatFailureGroupHandler extends GroupHandler { /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handle(array $record) + public function handle(array $record): bool { if ($this->processors) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } + /** @var Record $record */ + $record = $this->processRecord($record); } foreach ($this->handlers as $handler) { try { $handler->handle($record); - } catch (\Exception $e) { - // What failure? } catch (\Throwable $e) { // What failure? } @@ -44,26 +43,36 @@ public function handle(array $record) } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function handleBatch(array $records) + public function handleBatch(array $records): void { if ($this->processors) { $processed = array(); foreach ($records as $record) { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); - } - $processed[] = $record; + $processed[] = $this->processRecord($record); } + /** @var Record[] $records */ $records = $processed; } foreach ($this->handlers as $handler) { try { $handler->handleBatch($records); - } catch (\Exception $e) { + } catch (\Throwable $e) { // What failure? + } + } + } + + /** + * {@inheritDoc} + */ + public function close(): void + { + foreach ($this->handlers as $handler) { + try { + $handler->close(); } catch (\Throwable $e) { // What failure? } diff --git a/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php index a20aeae0..ddd46d8c 100644 --- a/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php +++ b/vendor/monolog/monolog/src/Monolog/Handler/ZendMonitorHandler.php @@ -1,4 +1,5 @@ - * @author Jason Davis + * + * @phpstan-import-type FormattedRecord from AbstractProcessingHandler */ class ZendMonitorHandler extends AbstractProcessingHandler { /** * Monolog level / ZendMonitor Custom Event priority map * - * @var array + * @var array */ - protected $levelMap = array(); + protected $levelMap = []; /** - * Construct - * - * @param int $level - * @param bool $bubble * @throws MissingExtensionException */ - public function __construct($level = Logger::DEBUG, $bubble = true) + public function __construct($level = Logger::DEBUG, bool $bubble = true) { if (!function_exists('zend_monitor_custom_event')) { throw new MissingExtensionException( @@ -43,7 +43,7 @@ public function __construct($level = Logger::DEBUG, $bubble = true) ); } //zend monitor constants are not defined if zend monitor is not enabled. - $this->levelMap = array( + $this->levelMap = [ Logger::DEBUG => \ZEND_MONITOR_EVENT_SEVERITY_INFO, Logger::INFO => \ZEND_MONITOR_EVENT_SEVERITY_INFO, Logger::NOTICE => \ZEND_MONITOR_EVENT_SEVERITY_INFO, @@ -52,14 +52,14 @@ public function __construct($level = Logger::DEBUG, $bubble = true) Logger::CRITICAL => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, Logger::ALERT => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, Logger::EMERGENCY => \ZEND_MONITOR_EVENT_SEVERITY_ERROR, - ); + ]; parent::__construct($level, $bubble); } /** - * {@inheritdoc} + * {@inheritDoc} */ - protected function write(array $record) + protected function write(array $record): void { $this->writeZendMonitorCustomEvent( Logger::getLevelName($record['level']), @@ -71,30 +71,30 @@ protected function write(array $record) /** * Write to Zend Monitor Events - * @param string $type Text displayed in "Class Name (custom)" field - * @param string $message Text displayed in "Error String" - * @param mixed $formatted Displayed in Custom Variables tab - * @param int $severity Set the event severity level (-1,0,1) + * @param string $type Text displayed in "Class Name (custom)" field + * @param string $message Text displayed in "Error String" + * @param array $formatted Displayed in Custom Variables tab + * @param int $severity Set the event severity level (-1,0,1) + * + * @phpstan-param FormattedRecord $formatted */ - protected function writeZendMonitorCustomEvent($type, $message, $formatted, $severity) + protected function writeZendMonitorCustomEvent(string $type, string $message, array $formatted, int $severity): void { zend_monitor_custom_event($type, $message, $formatted, $severity); } /** - * {@inheritdoc} + * {@inheritDoc} */ - public function getDefaultFormatter() + public function getDefaultFormatter(): FormatterInterface { return new NormalizerFormatter(); } /** - * Get the level map - * - * @return array + * @return array */ - public function getLevelMap() + public function getLevelMap(): array { return $this->levelMap; } diff --git a/vendor/monolog/monolog/src/Monolog/LogRecord.php b/vendor/monolog/monolog/src/Monolog/LogRecord.php new file mode 100644 index 00000000..702807d7 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/LogRecord.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog; + +use ArrayAccess; + +/** + * Monolog log record interface for forward compatibility with Monolog 3.0 + * + * This is just present in Monolog 2.4+ to allow interoperable code to be written against + * both versions by type-hinting arguments as `array|\Monolog\LogRecord $record` + * + * Do not rely on this interface for other purposes, and do not implement it. + * + * @author Jordi Boggiano + * @template-extends \ArrayAccess<'message'|'level'|'context'|'level_name'|'channel'|'datetime'|'extra'|'formatted', mixed> + * @phpstan-import-type Record from Logger + */ +interface LogRecord extends \ArrayAccess +{ + /** + * @phpstan-return Record + */ + public function toArray(): array; +} diff --git a/vendor/monolog/monolog/src/Monolog/Logger.php b/vendor/monolog/monolog/src/Monolog/Logger.php index 7d26b291..84a2f551 100644 --- a/vendor/monolog/monolog/src/Monolog/Logger.php +++ b/vendor/monolog/monolog/src/Monolog/Logger.php @@ -1,4 +1,4 @@ - + * + * @phpstan-type Level Logger::DEBUG|Logger::INFO|Logger::NOTICE|Logger::WARNING|Logger::ERROR|Logger::CRITICAL|Logger::ALERT|Logger::EMERGENCY + * @phpstan-type LevelName 'DEBUG'|'INFO'|'NOTICE'|'WARNING'|'ERROR'|'CRITICAL'|'ALERT'|'EMERGENCY' + * @phpstan-type Record array{message: string, context: mixed[], level: Level, level_name: LevelName, channel: string, datetime: \DateTimeImmutable, extra: mixed[]} */ class Logger implements LoggerInterface, ResettableInterface { /** * Detailed debug information */ - const DEBUG = 100; + public const DEBUG = 100; /** * Interesting events * * Examples: User logs in, SQL logs. */ - const INFO = 200; + public const INFO = 200; /** * Uncommon events */ - const NOTICE = 250; + public const NOTICE = 250; /** * Exceptional occurrences that are not errors @@ -50,19 +56,19 @@ class Logger implements LoggerInterface, ResettableInterface * Examples: Use of deprecated APIs, poor use of an API, * undesirable things that are not necessarily wrong. */ - const WARNING = 300; + public const WARNING = 300; /** * Runtime errors */ - const ERROR = 400; + public const ERROR = 400; /** * Critical conditions * * Example: Application component unavailable, unexpected exception. */ - const CRITICAL = 500; + public const CRITICAL = 500; /** * Action must be taken immediately @@ -70,12 +76,12 @@ class Logger implements LoggerInterface, ResettableInterface * Example: Entire website down, database unavailable, etc. * This should trigger the SMS alerts and wake you up. */ - const ALERT = 550; + public const ALERT = 550; /** * Urgent alert. */ - const EMERGENCY = 600; + public const EMERGENCY = 600; /** * Monolog API version @@ -85,14 +91,16 @@ class Logger implements LoggerInterface, ResettableInterface * * @var int */ - const API = 1; + public const API = 2; /** - * Logging levels from syslog protocol defined in RFC 5424 + * This is a static variable and not a constant to serve as an extension point for custom levels + * + * @var array $levels Logging levels with the levels as key * - * @var array $levels Logging levels + * @phpstan-var array $levels Logging levels with the levels as key */ - protected static $levels = array( + protected static $levels = [ self::DEBUG => 'DEBUG', self::INFO => 'INFO', self::NOTICE => 'NOTICE', @@ -101,12 +109,23 @@ class Logger implements LoggerInterface, ResettableInterface self::CRITICAL => 'CRITICAL', self::ALERT => 'ALERT', self::EMERGENCY => 'EMERGENCY', - ); + ]; /** - * @var \DateTimeZone + * Mapping between levels numbers defined in RFC 5424 and Monolog ones + * + * @phpstan-var array $rfc_5424_levels */ - protected static $timezone; + private const RFC_5424_LEVELS = [ + 7 => self::DEBUG, + 6 => self::INFO, + 5 => self::NOTICE, + 4 => self::WARNING, + 3 => self::ERROR, + 2 => self::CRITICAL, + 1 => self::ALERT, + 0 => self::EMERGENCY, + ]; /** * @var string @@ -135,36 +154,64 @@ class Logger implements LoggerInterface, ResettableInterface protected $microsecondTimestamps = true; /** - * @var callable + * @var DateTimeZone + */ + protected $timezone; + + /** + * @var callable|null */ protected $exceptionHandler; /** - * @param string $name The logging channel + * @var int Keeps track of depth to prevent infinite logging loops + */ + private $logDepth = 0; + + /** + * @var \WeakMap<\Fiber, int>|null Keeps track of depth inside fibers to prevent infinite logging loops + */ + private $fiberLogDepth; + + /** + * @var bool Whether to detect infinite logging loops + * + * This can be disabled via {@see useLoggingLoopDetection} if you have async handlers that do not play well with this + */ + private $detectCycles = true; + + /** + * @psalm-param array $processors + * + * @param string $name The logging channel, a simple descriptive name that is attached to all log records * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. * @param callable[] $processors Optional array of processors + * @param DateTimeZone|null $timezone Optional timezone, if not provided date_default_timezone_get() will be used */ - public function __construct($name, array $handlers = array(), array $processors = array()) + public function __construct(string $name, array $handlers = [], array $processors = [], ?DateTimeZone $timezone = null) { $this->name = $name; $this->setHandlers($handlers); $this->processors = $processors; + $this->timezone = $timezone ?: new DateTimeZone(date_default_timezone_get() ?: 'UTC'); + + if (\PHP_VERSION_ID >= 80100) { + // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412 + /** @var \WeakMap<\Fiber, int> $fiberLogDepth */ + $fiberLogDepth = new \WeakMap(); + $this->fiberLogDepth = $fiberLogDepth; + } } - /** - * @return string - */ - public function getName() + public function getName(): string { return $this->name; } /** * Return a new cloned instance with the name changed - * - * @return static */ - public function withName($name) + public function withName(string $name): self { $new = clone $this; $new->name = $name; @@ -174,11 +221,8 @@ public function withName($name) /** * Pushes a handler on to the stack. - * - * @param HandlerInterface $handler - * @return $this */ - public function pushHandler(HandlerInterface $handler) + public function pushHandler(HandlerInterface $handler): self { array_unshift($this->handlers, $handler); @@ -188,9 +232,9 @@ public function pushHandler(HandlerInterface $handler) /** * Pops a handler from the stack * - * @return HandlerInterface + * @throws \LogicException If empty handler stack */ - public function popHandler() + public function popHandler(): HandlerInterface { if (!$this->handlers) { throw new \LogicException('You tried to pop from an empty handler stack.'); @@ -204,12 +248,11 @@ public function popHandler() * * If a map is passed, keys will be ignored. * - * @param HandlerInterface[] $handlers - * @return $this + * @param HandlerInterface[] $handlers */ - public function setHandlers(array $handlers) + public function setHandlers(array $handlers): self { - $this->handlers = array(); + $this->handlers = []; foreach (array_reverse($handlers) as $handler) { $this->pushHandler($handler); } @@ -220,22 +263,16 @@ public function setHandlers(array $handlers) /** * @return HandlerInterface[] */ - public function getHandlers() + public function getHandlers(): array { return $this->handlers; } /** * Adds a processor on to the stack. - * - * @param callable $callback - * @return $this */ - public function pushProcessor($callback) + public function pushProcessor(callable $callback): self { - if (!is_callable($callback)) { - throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given'); - } array_unshift($this->processors, $callback); return $this; @@ -244,9 +281,10 @@ public function pushProcessor($callback) /** * Removes the processor on top of the stack and returns it. * + * @throws \LogicException If empty processor stack * @return callable */ - public function popProcessor() + public function popProcessor(): callable { if (!$this->processors) { throw new \LogicException('You tried to pop from an empty processor stack.'); @@ -258,7 +296,7 @@ public function popProcessor() /** * @return callable[] */ - public function getProcessors() + public function getProcessors(): array { return $this->processors; } @@ -267,91 +305,117 @@ public function getProcessors() * Control the use of microsecond resolution timestamps in the 'datetime' * member of new records. * - * Generating microsecond resolution timestamps by calling - * microtime(true), formatting the result via sprintf() and then parsing - * the resulting string via \DateTime::createFromFormat() can incur - * a measurable runtime overhead vs simple usage of DateTime to capture - * a second resolution timestamp in systems which generate a large number - * of log events. + * As of PHP7.1 microseconds are always included by the engine, so + * there is no performance penalty and Monolog 2 enabled microseconds + * by default. This function lets you disable them though in case you want + * to suppress microseconds from the output. * * @param bool $micro True to use microtime() to create timestamps */ - public function useMicrosecondTimestamps($micro) + public function useMicrosecondTimestamps(bool $micro): self { - $this->microsecondTimestamps = (bool) $micro; + $this->microsecondTimestamps = $micro; + + return $this; + } + + public function useLoggingLoopDetection(bool $detectCycles): self + { + $this->detectCycles = $detectCycles; + + return $this; } /** * Adds a log record. * - * @param int $level The logging level - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param int $level The logging level (a Monolog or RFC 5424 level) + * @param string $message The log message + * @param mixed[] $context The log context + * @param DateTimeImmutable $datetime Optional log date to log into the past or future + * @return bool Whether the record has been processed + * + * @phpstan-param Level $level */ - public function addRecord($level, $message, array $context = array()) + public function addRecord(int $level, string $message, array $context = [], DateTimeImmutable $datetime = null): bool { - if (!$this->handlers) { - $this->pushHandler(new StreamHandler('php://stderr', static::DEBUG)); + if (isset(self::RFC_5424_LEVELS[$level])) { + $level = self::RFC_5424_LEVELS[$level]; } - $levelName = static::getLevelName($level); - - // check if any handler will handle this message so we can return early and save cycles - $handlerKey = null; - reset($this->handlers); - while ($handler = current($this->handlers)) { - if ($handler->isHandling(array('level' => $level))) { - $handlerKey = key($this->handlers); - break; + if ($this->detectCycles) { + if (\PHP_VERSION_ID >= 80100 && $fiber = \Fiber::getCurrent()) { + $this->fiberLogDepth[$fiber] = $this->fiberLogDepth[$fiber] ?? 0; + $logDepth = ++$this->fiberLogDepth[$fiber]; + } else { + $logDepth = ++$this->logDepth; } - - next($this->handlers); + } else { + $logDepth = 0; } - if (null === $handlerKey) { + if ($logDepth === 3) { + $this->warning('A possible infinite logging loop was detected and aborted. It appears some of your handler code is triggering logging, see the previous log record for a hint as to what may be the cause.'); + return false; + } elseif ($logDepth >= 5) { // log depth 4 is let through, so we can log the warning above return false; } - if (!static::$timezone) { - static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC'); - } - - // php7.1+ always has microseconds enabled, so we do not need this hack - if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) { - $ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone); - } else { - $ts = new \DateTime('now', static::$timezone); - } - $ts->setTimezone(static::$timezone); + try { + $record = null; + + foreach ($this->handlers as $handler) { + if (null === $record) { + // skip creating the record as long as no handler is going to handle it + if (!$handler->isHandling(['level' => $level])) { + continue; + } + + $levelName = static::getLevelName($level); + + $record = [ + 'message' => $message, + 'context' => $context, + 'level' => $level, + 'level_name' => $levelName, + 'channel' => $this->name, + 'datetime' => $datetime ?? new DateTimeImmutable($this->microsecondTimestamps, $this->timezone), + 'extra' => [], + ]; + + try { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + } catch (Throwable $e) { + $this->handleException($e, $record); + + return true; + } + } - $record = array( - 'message' => (string) $message, - 'context' => $context, - 'level' => $level, - 'level_name' => $levelName, - 'channel' => $this->name, - 'datetime' => $ts, - 'extra' => array(), - ); + // once the record exists, send it to all handlers as long as the bubbling chain is not interrupted + try { + if (true === $handler->handle($record)) { + break; + } + } catch (Throwable $e) { + $this->handleException($e, $record); - try { - foreach ($this->processors as $processor) { - $record = call_user_func($processor, $record); + return true; + } } - - while ($handler = current($this->handlers)) { - if (true === $handler->handle($record)) { - break; + } finally { + if ($this->detectCycles) { + if (isset($fiber)) { + $this->fiberLogDepth[$fiber]--; + } else { + $this->logDepth--; } - - next($this->handlers); } - } catch (Exception $e) { - $this->handleException($e, $record); } - return true; + return null !== $record; } /** @@ -364,12 +428,10 @@ public function addRecord($level, $message, array $context = array()) * This is useful at the end of a request and will be called automatically on every handler * when they get destructed. */ - public function close() + public function close(): void { foreach ($this->handlers as $handler) { - if (method_exists($handler, 'close')) { - $handler->close(); - } + $handler->close(); } } @@ -383,7 +445,7 @@ public function close() * have a long running process like a worker or an application server serving multiple requests * in one process. */ - public function reset() + public function reset(): void { foreach ($this->handlers as $handler) { if ($handler instanceof ResettableInterface) { @@ -398,108 +460,13 @@ public function reset() } } - /** - * Adds a log record at the DEBUG level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addDebug($message, array $context = array()) - { - return $this->addRecord(static::DEBUG, $message, $context); - } - - /** - * Adds a log record at the INFO level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addInfo($message, array $context = array()) - { - return $this->addRecord(static::INFO, $message, $context); - } - - /** - * Adds a log record at the NOTICE level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addNotice($message, array $context = array()) - { - return $this->addRecord(static::NOTICE, $message, $context); - } - - /** - * Adds a log record at the WARNING level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addWarning($message, array $context = array()) - { - return $this->addRecord(static::WARNING, $message, $context); - } - - /** - * Adds a log record at the ERROR level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addError($message, array $context = array()) - { - return $this->addRecord(static::ERROR, $message, $context); - } - - /** - * Adds a log record at the CRITICAL level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addCritical($message, array $context = array()) - { - return $this->addRecord(static::CRITICAL, $message, $context); - } - - /** - * Adds a log record at the ALERT level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addAlert($message, array $context = array()) - { - return $this->addRecord(static::ALERT, $message, $context); - } - - /** - * Adds a log record at the EMERGENCY level. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed - */ - public function addEmergency($message, array $context = array()) - { - return $this->addRecord(static::EMERGENCY, $message, $context); - } - /** * Gets all supported logging levels. * - * @return array Assoc array with human-readable level names => level codes. + * @return array Assoc array with human-readable level names => level codes. + * @phpstan-return array */ - public static function getLevels() + public static function getLevels(): array { return array_flip(static::$levels); } @@ -507,10 +474,12 @@ public static function getLevels() /** * Gets the name of the logging level. * - * @param int $level - * @return string + * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level $level + * @phpstan-return LevelName */ - public static function getLevelName($level) + public static function getLevelName(int $level): string { if (!isset(static::$levels[$level])) { throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels))); @@ -522,18 +491,32 @@ public static function getLevelName($level) /** * Converts PSR-3 levels to Monolog ones if necessary * - * @param string|int $level Level number (monolog) or name (PSR-3) - * @return int + * @param string|int $level Level number (monolog) or name (PSR-3) + * @throws \Psr\Log\InvalidArgumentException If level is not defined + * + * @phpstan-param Level|LevelName|LogLevel::* $level + * @phpstan-return Level */ - public static function toMonologLevel($level) + public static function toMonologLevel($level): int { if (is_string($level)) { + if (is_numeric($level)) { + /** @phpstan-ignore-next-line */ + return intval($level); + } + // Contains chars of all log levels and avoids using strtoupper() which may have - // strange results depending on locale (for example, "i" will become "İ") + // strange results depending on locale (for example, "i" will become "İ" in Turkish locale) $upper = strtr($level, 'abcdefgilmnortuwy', 'ABCDEFGILMNORTUWY'); if (defined(__CLASS__.'::'.$upper)) { return constant(__CLASS__ . '::' . $upper); } + + throw new InvalidArgumentException('Level "'.$level.'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); + } + + if (!is_int($level)) { + throw new InvalidArgumentException('Level "'.var_export($level, true).'" is not defined, use one of: '.implode(', ', array_keys(static::$levels) + static::$levels)); } return $level; @@ -542,14 +525,13 @@ public static function toMonologLevel($level) /** * Checks whether the Logger has a handler that listens on the given level * - * @param int $level - * @return bool + * @phpstan-param Level $level */ - public function isHandling($level) + public function isHandling(int $level): bool { - $record = array( + $record = [ 'level' => $level, - ); + ]; foreach ($this->handlers as $handler) { if ($handler->isHandling($record)) { @@ -561,57 +543,46 @@ public function isHandling($level) } /** - * Set a custom exception handler + * Set a custom exception handler that will be called if adding a new record fails * - * @param callable $callback - * @return $this + * The callable will receive an exception object and the record that failed to be logged */ - public function setExceptionHandler($callback) + public function setExceptionHandler(?callable $callback): self { - if (!is_callable($callback)) { - throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given'); - } $this->exceptionHandler = $callback; return $this; } - /** - * @return callable - */ - public function getExceptionHandler() + public function getExceptionHandler(): ?callable { return $this->exceptionHandler; } - /** - * Delegates exception management to the custom exception handler, - * or throws the exception if no custom handler is set. - */ - protected function handleException(Exception $e, array $record) - { - if (!$this->exceptionHandler) { - throw $e; - } - - call_user_func($this->exceptionHandler, $e, $record); - } - /** * Adds a log record at an arbitrary level. * * This method allows for compatibility with common interfaces. * - * @param mixed $level The log level - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param mixed $level The log level (a Monolog, PSR-3 or RFC 5424 level) + * @param string|Stringable $message The log message + * @param mixed[] $context The log context + * + * @phpstan-param Level|LevelName|LogLevel::* $level */ - public function log($level, $message, array $context = array()) + public function log($level, $message, array $context = []): void { + if (!is_int($level) && !is_string($level)) { + throw new \InvalidArgumentException('$level is expected to be a string or int'); + } + + if (isset(self::RFC_5424_LEVELS[$level])) { + $level = self::RFC_5424_LEVELS[$level]; + } + $level = static::toMonologLevel($level); - return $this->addRecord($level, $message, $context); + $this->addRecord($level, (string) $message, $context); } /** @@ -619,13 +590,12 @@ public function log($level, $message, array $context = array()) * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function debug($message, array $context = array()) + public function debug($message, array $context = []): void { - return $this->addRecord(static::DEBUG, $message, $context); + $this->addRecord(static::DEBUG, (string) $message, $context); } /** @@ -633,13 +603,12 @@ public function debug($message, array $context = array()) * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function info($message, array $context = array()) + public function info($message, array $context = []): void { - return $this->addRecord(static::INFO, $message, $context); + $this->addRecord(static::INFO, (string) $message, $context); } /** @@ -647,13 +616,12 @@ public function info($message, array $context = array()) * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function notice($message, array $context = array()) + public function notice($message, array $context = []): void { - return $this->addRecord(static::NOTICE, $message, $context); + $this->addRecord(static::NOTICE, (string) $message, $context); } /** @@ -661,136 +629,133 @@ public function notice($message, array $context = array()) * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function warn($message, array $context = array()) + public function warning($message, array $context = []): void { - return $this->addRecord(static::WARNING, $message, $context); + $this->addRecord(static::WARNING, (string) $message, $context); } /** - * Adds a log record at the WARNING level. + * Adds a log record at the ERROR level. * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function warning($message, array $context = array()) + public function error($message, array $context = []): void { - return $this->addRecord(static::WARNING, $message, $context); + $this->addRecord(static::ERROR, (string) $message, $context); } /** - * Adds a log record at the ERROR level. + * Adds a log record at the CRITICAL level. * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function err($message, array $context = array()) + public function critical($message, array $context = []): void { - return $this->addRecord(static::ERROR, $message, $context); + $this->addRecord(static::CRITICAL, (string) $message, $context); } /** - * Adds a log record at the ERROR level. + * Adds a log record at the ALERT level. * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function error($message, array $context = array()) + public function alert($message, array $context = []): void { - return $this->addRecord(static::ERROR, $message, $context); + $this->addRecord(static::ALERT, (string) $message, $context); } /** - * Adds a log record at the CRITICAL level. + * Adds a log record at the EMERGENCY level. * * This method allows for compatibility with common interfaces. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param string|Stringable $message The log message + * @param mixed[] $context The log context */ - public function crit($message, array $context = array()) + public function emergency($message, array $context = []): void { - return $this->addRecord(static::CRITICAL, $message, $context); + $this->addRecord(static::EMERGENCY, (string) $message, $context); } /** - * Adds a log record at the CRITICAL level. - * - * This method allows for compatibility with common interfaces. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * Sets the timezone to be used for the timestamp of log records. */ - public function critical($message, array $context = array()) + public function setTimezone(DateTimeZone $tz): self { - return $this->addRecord(static::CRITICAL, $message, $context); + $this->timezone = $tz; + + return $this; } /** - * Adds a log record at the ALERT level. - * - * This method allows for compatibility with common interfaces. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * Returns the timezone to be used for the timestamp of log records. */ - public function alert($message, array $context = array()) + public function getTimezone(): DateTimeZone { - return $this->addRecord(static::ALERT, $message, $context); + return $this->timezone; } /** - * Adds a log record at the EMERGENCY level. - * - * This method allows for compatibility with common interfaces. + * Delegates exception management to the custom exception handler, + * or throws the exception if no custom handler is set. * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @param array $record + * @phpstan-param Record $record */ - public function emerg($message, array $context = array()) + protected function handleException(Throwable $e, array $record): void { - return $this->addRecord(static::EMERGENCY, $message, $context); + if (!$this->exceptionHandler) { + throw $e; + } + + ($this->exceptionHandler)($e, $record); } /** - * Adds a log record at the EMERGENCY level. - * - * This method allows for compatibility with common interfaces. - * - * @param string $message The log message - * @param array $context The log context - * @return bool Whether the record has been processed + * @return array */ - public function emergency($message, array $context = array()) + public function __serialize(): array { - return $this->addRecord(static::EMERGENCY, $message, $context); + return [ + 'name' => $this->name, + 'handlers' => $this->handlers, + 'processors' => $this->processors, + 'microsecondTimestamps' => $this->microsecondTimestamps, + 'timezone' => $this->timezone, + 'exceptionHandler' => $this->exceptionHandler, + 'logDepth' => $this->logDepth, + 'detectCycles' => $this->detectCycles, + ]; } /** - * Set the timezone to be used for the timestamp of log records. - * - * This is stored globally for all Logger instances - * - * @param \DateTimeZone $tz Timezone object + * @param array $data */ - public static function setTimezone(\DateTimeZone $tz) + public function __unserialize(array $data): void { - self::$timezone = $tz; + foreach (['name', 'handlers', 'processors', 'microsecondTimestamps', 'timezone', 'exceptionHandler', 'logDepth', 'detectCycles'] as $property) { + if (isset($data[$property])) { + $this->$property = $data[$property]; + } + } + + if (\PHP_VERSION_ID >= 80100) { + // Local variable for phpstan, see https://github.com/phpstan/phpstan/issues/6732#issuecomment-1111118412 + /** @var \WeakMap<\Fiber, int> $fiberLogDepth */ + $fiberLogDepth = new \WeakMap(); + $this->fiberLogDepth = $fiberLogDepth; + } } } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php index cdf5ec73..8166bdca 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/GitProcessor.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class GitProcessor implements ProcessorInterface { + /** @var int */ private $level; - private static $cache; + /** @var array{branch: string, commit: string}|array|null */ + private static $cache = null; + /** + * @param string|int $level The minimum logging level at which this Processor will be triggered + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ public function __construct($level = Logger::DEBUG) { $this->level = Logger::toMonologLevel($level); } /** - * @param array $record - * @return array + * {@inheritDoc} */ - public function __invoke(array $record) + public function __invoke(array $record): array { // return if the level is not high enough if ($record['level'] < $this->level) { @@ -45,7 +55,10 @@ public function __invoke(array $record) return $record; } - private static function getGitInfo() + /** + * @return array{branch: string, commit: string}|array + */ + private static function getGitInfo(): array { if (self::$cache) { return self::$cache; @@ -53,12 +66,12 @@ private static function getGitInfo() $branches = `git branch -v --no-abbrev`; if ($branches && preg_match('{^\* (.+?)\s+([a-f0-9]{40})(?:\s|$)}m', $branches, $matches)) { - return self::$cache = array( + return self::$cache = [ 'branch' => $matches[1], 'commit' => $matches[2], - ); + ]; } - return self::$cache = array(); + return self::$cache = []; } } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/HostnameProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/HostnameProcessor.php new file mode 100644 index 00000000..91fda7d6 --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Processor/HostnameProcessor.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Processor; + +/** + * Injects value of gethostname in all records + */ +class HostnameProcessor implements ProcessorInterface +{ + /** @var string */ + private static $host; + + public function __construct() + { + self::$host = (string) gethostname(); + } + + /** + * {@inheritDoc} + */ + public function __invoke(array $record): array + { + $record['extra']['hostname'] = self::$host; + + return $record; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php index 6ae192a2..a32e76b2 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/IntrospectionProcessor.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class IntrospectionProcessor implements ProcessorInterface { + /** @var int */ private $level; - + /** @var string[] */ private $skipClassesPartials; - + /** @var int */ private $skipStackFramesCount; - - private $skipFunctions = array( + /** @var string[] */ + private $skipFunctions = [ 'call_user_func', 'call_user_func_array', - ); + ]; - public function __construct($level = Logger::DEBUG, array $skipClassesPartials = array(), $skipStackFramesCount = 0) + /** + * @param string|int $level The minimum logging level at which this Processor will be triggered + * @param string[] $skipClassesPartials + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ + public function __construct($level = Logger::DEBUG, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { $this->level = Logger::toMonologLevel($level); - $this->skipClassesPartials = array_merge(array('Monolog\\'), $skipClassesPartials); + $this->skipClassesPartials = array_merge(['Monolog\\'], $skipClassesPartials); $this->skipStackFramesCount = $skipStackFramesCount; } /** - * @param array $record - * @return array + * {@inheritDoc} */ - public function __invoke(array $record) + public function __invoke(array $record): array { // return if the level is not high enough if ($record['level'] < $this->level) { return $record; } - /* - * http://php.net/manual/en/function.debug-backtrace.php - * As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added. - * Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'. - */ - $trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS); + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); // skip first since it's always the current method array_shift($trace); @@ -74,11 +79,13 @@ public function __invoke(array $record) foreach ($this->skipClassesPartials as $part) { if (strpos($trace[$i]['class'], $part) !== false) { $i++; + continue 2; } } } elseif (in_array($trace[$i]['function'], $this->skipFunctions)) { $i++; + continue; } @@ -90,18 +97,22 @@ public function __invoke(array $record) // we should have the call source now $record['extra'] = array_merge( $record['extra'], - array( + [ 'file' => isset($trace[$i - 1]['file']) ? $trace[$i - 1]['file'] : null, 'line' => isset($trace[$i - 1]['line']) ? $trace[$i - 1]['line'] : null, 'class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : null, + 'callType' => isset($trace[$i]['type']) ? $trace[$i]['type'] : null, 'function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : null, - ) + ] ); return $record; } - private function isTraceClassOrSkippedFunction(array $trace, $index) + /** + * @param array[] $trace + */ + private function isTraceClassOrSkippedFunction(array $trace, int $index): bool { if (!isset($trace[$index])) { return false; diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php index 0543e929..37c756fc 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryPeakUsageProcessor.php @@ -1,4 +1,4 @@ -realUsage); - $formatted = $this->formatBytes($bytes); + $usage = memory_get_peak_usage($this->realUsage); - $record['extra']['memory_peak_usage'] = $formatted; + if ($this->useFormatting) { + $usage = $this->formatBytes($usage); + } + + $record['extra']['memory_peak_usage'] = $usage; return $record; } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php index 2a379a30..227deb7c 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryProcessor.php @@ -1,4 +1,4 @@ -realUsage = (bool) $realUsage; - $this->useFormatting = (bool) $useFormatting; + $this->realUsage = $realUsage; + $this->useFormatting = $useFormatting; } /** * Formats bytes into a human readable string if $this->useFormatting is true, otherwise return $bytes as is * * @param int $bytes - * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as is + * @return string|int Formatted string if $this->useFormatting is true, otherwise return $bytes as int */ - protected function formatBytes($bytes) + protected function formatBytes(int $bytes) { - $bytes = (int) $bytes; - if (!$this->useFormatting) { return $bytes; } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php index 2783d656..e141921e 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/MemoryUsageProcessor.php @@ -1,4 +1,4 @@ -realUsage); - $formatted = $this->formatBytes($bytes); + $usage = memory_get_usage($this->realUsage); - $record['extra']['memory_usage'] = $formatted; + if ($this->useFormatting) { + $usage = $this->formatBytes($usage); + } + + $record['extra']['memory_usage'] = $usage; return $record; } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php index 2f5b3265..d4a628f5 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/MercurialProcessor.php @@ -1,9 +1,9 @@ - + * (c) Jordi Boggiano * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. @@ -12,27 +12,37 @@ namespace Monolog\Processor; use Monolog\Logger; +use Psr\Log\LogLevel; /** * Injects Hg branch and Hg revision number in all records * * @author Jonathan A. Schweder + * + * @phpstan-import-type LevelName from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger */ class MercurialProcessor implements ProcessorInterface { + /** @var Level */ private $level; - private static $cache; + /** @var array{branch: string, revision: string}|array|null */ + private static $cache = null; + /** + * @param int|string $level The minimum logging level at which this Processor will be triggered + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ public function __construct($level = Logger::DEBUG) { $this->level = Logger::toMonologLevel($level); } /** - * @param array $record - * @return array + * {@inheritDoc} */ - public function __invoke(array $record) + public function __invoke(array $record): array { // return if the level is not high enough if ($record['level'] < $this->level) { @@ -44,20 +54,24 @@ public function __invoke(array $record) return $record; } - private static function getMercurialInfo() + /** + * @return array{branch: string, revision: string}|array + */ + private static function getMercurialInfo(): array { if (self::$cache) { return self::$cache; } $result = explode(' ', trim(`hg id -nb`)); + if (count($result) >= 3) { - return self::$cache = array( + return self::$cache = [ 'branch' => $result[1], 'revision' => $result[2], - ); + ]; } - return self::$cache = array(); + return self::$cache = []; } } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php index 66b80fbb..3b939a95 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/ProcessIdProcessor.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Record from \Monolog\Logger */ interface ProcessorInterface { /** - * @return array The processed records + * @return array The processed record + * + * @phpstan-param Record $record + * @phpstan-return Record */ - public function __invoke(array $records); + public function __invoke(array $record); } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php index a318af7e..e7c12176 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/PsrLogMessageProcessor.php @@ -1,4 +1,4 @@ -dateFormat = $dateFormat; $this->removeUsedContextFields = $removeUsedContextFields; } /** - * @param array $record - * @return array + * {@inheritDoc} */ - public function __invoke(array $record) + public function __invoke(array $record): array { if (false === strpos($record['message'], '{')) { return $record; } - $replacements = array(); + $replacements = []; foreach ($record['context'] as $key => $val) { $placeholder = '{' . $key . '}'; if (strpos($record['message'], $placeholder) === false) { @@ -59,8 +58,16 @@ public function __invoke(array $record) if (is_null($val) || is_scalar($val) || (is_object($val) && method_exists($val, "__toString"))) { $replacements[$placeholder] = $val; - } elseif ($val instanceof \DateTime) { - $replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE); + } elseif ($val instanceof \DateTimeInterface) { + if (!$this->dateFormat && $val instanceof \Monolog\DateTimeImmutable) { + // handle monolog dates using __toString if no specific dateFormat was asked for + // so that it follows the useMicroseconds flag + $replacements[$placeholder] = (string) $val; + } else { + $replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE); + } + } elseif ($val instanceof \UnitEnum) { + $replacements[$placeholder] = $val instanceof \BackedEnum ? $val->value : $val->name; } elseif (is_object($val)) { $replacements[$placeholder] = '[object '.Utils::getClass($val).']'; } elseif (is_array($val)) { diff --git a/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php index 615a4d99..80f18747 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/TagProcessor.php @@ -1,4 +1,4 @@ -setTags($tags); } - public function addTags(array $tags = array()) + /** + * @param string[] $tags + */ + public function addTags(array $tags = []): self { $this->tags = array_merge($this->tags, $tags); + + return $this; } - public function setTags(array $tags = array()) + /** + * @param string[] $tags + */ + public function setTags(array $tags = []): self { $this->tags = $tags; + + return $this; } - public function __invoke(array $record) + /** + * {@inheritDoc} + */ + public function __invoke(array $record): array { $record['extra']['tags'] = $this->tags; diff --git a/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php index d1f708cf..a27b74db 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/UidProcessor.php @@ -1,4 +1,4 @@ - 32 || $length < 1) { + if ($length > 32 || $length < 1) { throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32'); } - $this->uid = $this->generateUid($length); } - public function __invoke(array $record) + /** + * {@inheritDoc} + */ + public function __invoke(array $record): array { $record['extra']['uid'] = $this->uid; return $record; } - /** - * @return string - */ - public function getUid() + public function getUid(): string { return $this->uid; } @@ -52,8 +52,8 @@ public function reset() $this->uid = $this->generateUid(strlen($this->uid)); } - private function generateUid($length) + private function generateUid(int $length): string { - return substr(hash('md5', uniqid('', true)), 0, $length); + return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length); } } diff --git a/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php index 2e8dfae1..51850e17 100644 --- a/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php +++ b/vendor/monolog/monolog/src/Monolog/Processor/WebProcessor.php @@ -1,4 +1,4 @@ -|\ArrayAccess */ protected $serverData; @@ -28,19 +28,20 @@ class WebProcessor implements ProcessorInterface * * Array is structured as [key in record.extra => key in $serverData] * - * @var array + * @var array */ - protected $extraFields = array( + protected $extraFields = [ 'url' => 'REQUEST_URI', 'ip' => 'REMOTE_ADDR', 'http_method' => 'REQUEST_METHOD', 'server' => 'SERVER_NAME', 'referrer' => 'HTTP_REFERER', - ); + 'user_agent' => 'HTTP_USER_AGENT', + ]; /** - * @param array|\ArrayAccess $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data - * @param array|null $extraFields Field names and the related key inside $serverData to be added. If not provided it defaults to: url, ip, http_method, server, referrer + * @param array|\ArrayAccess|null $serverData Array or object w/ ArrayAccess that provides access to the $_SERVER data + * @param array|array|null $extraFields Field names and the related key inside $serverData to be added (or just a list of field names to use the default configured $serverData mapping). If not provided it defaults to: [url, ip, http_method, server, referrer] + unique_id if present in server data */ public function __construct($serverData = null, array $extraFields = null) { @@ -52,28 +53,30 @@ public function __construct($serverData = null, array $extraFields = null) throw new \UnexpectedValueException('$serverData must be an array or object implementing ArrayAccess.'); } + $defaultEnabled = ['url', 'ip', 'http_method', 'server', 'referrer']; if (isset($this->serverData['UNIQUE_ID'])) { $this->extraFields['unique_id'] = 'UNIQUE_ID'; + $defaultEnabled[] = 'unique_id'; } - if (null !== $extraFields) { - if (isset($extraFields[0])) { - foreach (array_keys($this->extraFields) as $fieldName) { - if (!in_array($fieldName, $extraFields)) { - unset($this->extraFields[$fieldName]); - } + if (null === $extraFields) { + $extraFields = $defaultEnabled; + } + if (isset($extraFields[0])) { + foreach (array_keys($this->extraFields) as $fieldName) { + if (!in_array($fieldName, $extraFields)) { + unset($this->extraFields[$fieldName]); } - } else { - $this->extraFields = $extraFields; } + } else { + $this->extraFields = $extraFields; } } /** - * @param array $record - * @return array + * {@inheritDoc} */ - public function __invoke(array $record) + public function __invoke(array $record): array { // skip processing if for some reason request data // is not present (CLI or wonky SAPIs) @@ -86,12 +89,7 @@ public function __invoke(array $record) return $record; } - /** - * @param string $extraName - * @param string $serverName - * @return $this - */ - public function addExtraField($extraName, $serverName) + public function addExtraField(string $extraName, string $serverName): self { $this->extraFields[$extraName] = $serverName; @@ -99,13 +97,13 @@ public function addExtraField($extraName, $serverName) } /** - * @param array $extra - * @return array + * @param mixed[] $extra + * @return mixed[] */ - private function appendExtraFields(array $extra) + private function appendExtraFields(array $extra): array { foreach ($this->extraFields as $extraName => $serverName) { - $extra[$extraName] = isset($this->serverData[$serverName]) ? $this->serverData[$serverName] : null; + $extra[$extraName] = $this->serverData[$serverName] ?? null; } return $extra; diff --git a/vendor/monolog/monolog/src/Monolog/Registry.php b/vendor/monolog/monolog/src/Monolog/Registry.php index 159b751c..ae94ae6c 100644 --- a/vendor/monolog/monolog/src/Monolog/Registry.php +++ b/vendor/monolog/monolog/src/Monolog/Registry.php @@ -1,4 +1,4 @@ -addError('Sent to $api Logger instance'); - * Monolog\Registry::application()->addError('Sent to $application Logger instance'); + * Monolog\Registry::api()->error('Sent to $api Logger instance'); + * Monolog\Registry::application()->error('Sent to $application Logger instance'); * } * * @@ -42,7 +42,7 @@ class Registry * * @var Logger[] */ - private static $loggers = array(); + private static $loggers = []; /** * Adds new logging channel to the registry @@ -51,8 +51,9 @@ class Registry * @param string|null $name Name of the logging channel ($logger->getName() by default) * @param bool $overwrite Overwrite instance in the registry if the given name already exists? * @throws \InvalidArgumentException If $overwrite set to false and named Logger instance already exists + * @return void */ - public static function addLogger(Logger $logger, $name = null, $overwrite = false) + public static function addLogger(Logger $logger, ?string $name = null, bool $overwrite = false) { $name = $name ?: $logger->getName(); @@ -68,15 +69,15 @@ public static function addLogger(Logger $logger, $name = null, $overwrite = fals * * @param string|Logger $logger Name or logger instance */ - public static function hasLogger($logger) + public static function hasLogger($logger): bool { if ($logger instanceof Logger) { $index = array_search($logger, self::$loggers, true); return false !== $index; - } else { - return isset(self::$loggers[$logger]); } + + return isset(self::$loggers[$logger]); } /** @@ -84,7 +85,7 @@ public static function hasLogger($logger) * * @param string|Logger $logger Name or logger instance */ - public static function removeLogger($logger) + public static function removeLogger($logger): void { if ($logger instanceof Logger) { if (false !== ($idx = array_search($logger, self::$loggers, true))) { @@ -98,9 +99,9 @@ public static function removeLogger($logger) /** * Clears the registry */ - public static function clear() + public static function clear(): void { - self::$loggers = array(); + self::$loggers = []; } /** @@ -108,9 +109,8 @@ public static function clear() * * @param string $name Name of the requested Logger instance * @throws \InvalidArgumentException If named Logger instance is not in the registry - * @return Logger Requested instance of Logger */ - public static function getInstance($name) + public static function getInstance($name): Logger { if (!isset(self::$loggers[$name])) { throw new InvalidArgumentException(sprintf('Requested "%s" logger instance is not in the registry', $name)); @@ -123,7 +123,7 @@ public static function getInstance($name) * Gets Logger instance from the registry via static method call * * @param string $name Name of the requested Logger instance - * @param array $arguments Arguments passed to static method call + * @param mixed[] $arguments Arguments passed to static method call * @throws \InvalidArgumentException If named Logger instance is not in the registry * @return Logger Requested instance of Logger */ diff --git a/vendor/monolog/monolog/src/Monolog/ResettableInterface.php b/vendor/monolog/monolog/src/Monolog/ResettableInterface.php index 635bc77d..2c5fd785 100644 --- a/vendor/monolog/monolog/src/Monolog/ResettableInterface.php +++ b/vendor/monolog/monolog/src/Monolog/ResettableInterface.php @@ -1,4 +1,4 @@ - + * + * @phpstan-import-type Level from \Monolog\Logger + * @phpstan-import-type LevelName from \Monolog\Logger */ class SignalHandler { + /** @var LoggerInterface */ private $logger; - private $previousSignalHandler = array(); - private $signalLevelMap = array(); - private $signalRestartSyscalls = array(); + /** @var array SIG_DFL, SIG_IGN or previous callable */ + private $previousSignalHandler = []; + /** @var array */ + private $signalLevelMap = []; + /** @var array */ + private $signalRestartSyscalls = []; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } - public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true) + /** + * @param int|string $level Level or level name + * @param bool $callPrevious + * @param bool $restartSyscalls + * @param bool|null $async + * @return $this + * + * @phpstan-param Level|LevelName|LogLevel::* $level + */ + public function registerSignalHandler(int $signo, $level = LogLevel::CRITICAL, bool $callPrevious = true, bool $restartSyscalls = true, ?bool $async = true): self { if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) { return $this; } + $level = Logger::toMonologLevel($level); + if ($callPrevious) { - if (function_exists('pcntl_signal_get_handler')) { - $handler = pcntl_signal_get_handler($signo); - if ($handler === false) { - return $this; - } - $this->previousSignalHandler[$signo] = $handler; - } else { - $this->previousSignalHandler[$signo] = true; - } + $handler = pcntl_signal_get_handler($signo); + $this->previousSignalHandler[$signo] = $handler; } else { unset($this->previousSignalHandler[$signo]); } $this->signalLevelMap[$signo] = $level; $this->signalRestartSyscalls[$signo] = $restartSyscalls; - if (function_exists('pcntl_async_signals') && $async !== null) { + if ($async !== null) { pcntl_async_signals($async); } - pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); + pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls); return $this; } - public function handleSignal($signo, array $siginfo = null) + /** + * @param mixed $siginfo + */ + public function handleSignal(int $signo, $siginfo = null): void { - static $signals = array(); + static $signals = []; if (!$signals && extension_loaded('pcntl')) { $pcntl = new ReflectionExtension('pcntl'); - $constants = $pcntl->getConstants(); - if (!$constants) { - // HHVM 3.24.2 returns an empty array. - $constants = get_defined_constants(true); - $constants = $constants['Core']; - } - foreach ($constants as $name => $value) { + // HHVM 3.24.2 returns an empty array. + foreach ($pcntl->getConstants() ?: get_defined_constants(true)['Core'] as $name => $value) { if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) { $signals[$value] = $name; } } - unset($constants); } - $level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL; - $signal = isset($signals[$signo]) ? $signals[$signo] : $signo; - $context = isset($siginfo) ? $siginfo : array(); + $level = $this->signalLevelMap[$signo] ?? LogLevel::CRITICAL; + $signal = $signals[$signo] ?? $signo; + $context = $siginfo ?? []; $this->logger->log($level, sprintf('Program received signal %s', $signal), $context); if (!isset($this->previousSignalHandler[$signo])) { return; } - if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) { + if ($this->previousSignalHandler[$signo] === SIG_DFL) { if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch') - && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) { - $restartSyscalls = isset($this->signalRestartSyscalls[$signo]) ? $this->signalRestartSyscalls[$signo] : true; - pcntl_signal($signo, SIG_DFL, $restartSyscalls); - pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset); - posix_kill(posix_getpid(), $signo); - pcntl_signal_dispatch(); - pcntl_sigprocmask(SIG_SETMASK, $oldset); - pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls); - } - } elseif (is_callable($this->previousSignalHandler[$signo])) { - if (PHP_VERSION_ID >= 70100) { - $this->previousSignalHandler[$signo]($signo, $siginfo); - } else { - $this->previousSignalHandler[$signo]($signo); + && extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill') + ) { + $restartSyscalls = $this->signalRestartSyscalls[$signo] ?? true; + pcntl_signal($signo, SIG_DFL, $restartSyscalls); + pcntl_sigprocmask(SIG_UNBLOCK, [$signo], $oldset); + posix_kill(posix_getpid(), $signo); + pcntl_signal_dispatch(); + pcntl_sigprocmask(SIG_SETMASK, $oldset); + pcntl_signal($signo, [$this, 'handleSignal'], $restartSyscalls); } + } elseif (is_callable($this->previousSignalHandler[$signo])) { + $this->previousSignalHandler[$signo]($signo, $siginfo); } } } diff --git a/vendor/monolog/monolog/src/Monolog/Test/TestCase.php b/vendor/monolog/monolog/src/Monolog/Test/TestCase.php new file mode 100644 index 00000000..bc0b425e --- /dev/null +++ b/vendor/monolog/monolog/src/Monolog/Test/TestCase.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Monolog\Test; + +use Monolog\Logger; +use Monolog\DateTimeImmutable; +use Monolog\Formatter\FormatterInterface; + +/** + * Lets you easily generate log records and a dummy formatter for testing purposes + * + * @author Jordi Boggiano + * + * @phpstan-import-type Record from \Monolog\Logger + * @phpstan-import-type Level from \Monolog\Logger + * + * @internal feel free to reuse this to test your own handlers, this is marked internal to avoid issues with PHPStorm https://github.com/Seldaek/monolog/issues/1677 + */ +class TestCase extends \PHPUnit\Framework\TestCase +{ + public function tearDown(): void + { + parent::tearDown(); + + if (isset($this->handler)) { + unset($this->handler); + } + } + + /** + * @param mixed[] $context + * + * @return array Record + * + * @phpstan-param Level $level + * @phpstan-return Record + */ + protected function getRecord(int $level = Logger::WARNING, string $message = 'test', array $context = []): array + { + return [ + 'message' => (string) $message, + 'context' => $context, + 'level' => $level, + 'level_name' => Logger::getLevelName($level), + 'channel' => 'test', + 'datetime' => new DateTimeImmutable(true), + 'extra' => [], + ]; + } + + /** + * @phpstan-return Record[] + */ + protected function getMultipleRecords(): array + { + return [ + $this->getRecord(Logger::DEBUG, 'debug message 1'), + $this->getRecord(Logger::DEBUG, 'debug message 2'), + $this->getRecord(Logger::INFO, 'information'), + $this->getRecord(Logger::WARNING, 'warning'), + $this->getRecord(Logger::ERROR, 'error'), + ]; + } + + protected function getIdentityFormatter(): FormatterInterface + { + $formatter = $this->createMock(FormatterInterface::class); + $formatter->expects($this->any()) + ->method('format') + ->will($this->returnCallback(function ($record) { + return $record['message']; + })); + + return $formatter; + } +} diff --git a/vendor/monolog/monolog/src/Monolog/Utils.php b/vendor/monolog/monolog/src/Monolog/Utils.php index 7f1ba129..360c4219 100644 --- a/vendor/monolog/monolog/src/Monolog/Utils.php +++ b/vendor/monolog/monolog/src/Monolog/Utils.php @@ -1,4 +1,4 @@ -=')) { - $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + if (null === $encodeFlags) { + $encodeFlags = self::DEFAULT_JSON_FLAGS; } if ($ignoreErrors) { @@ -90,16 +104,16 @@ public static function jsonEncode($data, $encodeFlags = null, $ignoreErrors = fa * * If the failure is due to invalid string encoding, try to clean the * input and encode again. If the second encoding attempt fails, the - * inital error is not encoding related or the input can't be cleaned then + * initial error is not encoding related or the input can't be cleaned then * raise a descriptive exception. * - * @param int $code return code of json_last_error function - * @param mixed $data data that was meant to be encoded - * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE + * @param int $code return code of json_last_error function + * @param mixed $data data that was meant to be encoded + * @param int $encodeFlags flags to pass to json encode, defaults to JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION * @throws \RuntimeException if failure can't be corrected * @return string JSON encoded data after error correction */ - public static function handleJsonError($code, $data, $encodeFlags = null) + public static function handleJsonError(int $code, $data, ?int $encodeFlags = null): string { if ($code !== JSON_ERROR_UTF8) { self::throwEncodeError($code, $data); @@ -113,8 +127,8 @@ public static function handleJsonError($code, $data, $encodeFlags = null) self::throwEncodeError($code, $data); } - if (null === $encodeFlags && version_compare(PHP_VERSION, '5.4.0', '>=')) { - $encodeFlags = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + if (null === $encodeFlags) { + $encodeFlags = self::DEFAULT_JSON_FLAGS; } $json = json_encode($data, $encodeFlags); @@ -126,14 +140,35 @@ public static function handleJsonError($code, $data, $encodeFlags = null) return $json; } + /** + * @internal + */ + public static function pcreLastErrorMessage(int $code): string + { + if (PHP_VERSION_ID >= 80000) { + return preg_last_error_msg(); + } + + $constants = (get_defined_constants(true))['pcre']; + $constants = array_filter($constants, function ($key) { + return substr($key, -6) == '_ERROR'; + }, ARRAY_FILTER_USE_KEY); + + $constants = array_flip($constants); + + return $constants[$code] ?? 'UNDEFINED_ERROR'; + } + /** * Throws an exception according to a given code with a customized message * * @param int $code return code of json_last_error function * @param mixed $data data that was meant to be encoded * @throws \RuntimeException + * + * @return never */ - private static function throwEncodeError($code, $data) + private static function throwEncodeError(int $code, $data): void { switch ($code) { case JSON_ERROR_DEPTH: @@ -169,21 +204,81 @@ private static function throwEncodeError($code, $data) * can be used as a callback for array_walk_recursive. * * @param mixed $data Input to check and convert if needed, passed by ref - * @private */ - public static function detectAndCleanUtf8(&$data) + private static function detectAndCleanUtf8(&$data): void { if (is_string($data) && !preg_match('//u', $data)) { $data = preg_replace_callback( '/[\x80-\xFF]+/', - function ($m) { return utf8_encode($m[0]); }, + function ($m) { + return function_exists('mb_convert_encoding') ? mb_convert_encoding($m[0], 'UTF-8', 'ISO-8859-1') : utf8_encode($m[0]); + }, $data ); + if (!is_string($data)) { + $pcreErrorCode = preg_last_error(); + throw new \RuntimeException('Failed to preg_replace_callback: ' . $pcreErrorCode . ' / ' . self::pcreLastErrorMessage($pcreErrorCode)); + } $data = str_replace( - array('¤', '¦', '¨', '´', '¸', '¼', '½', '¾'), - array('€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'), + ['¤', '¦', '¨', '´', '¸', '¼', '½', '¾'], + ['€', 'Š', 'š', 'Ž', 'ž', 'Œ', 'œ', 'Ÿ'], $data ); } } + + /** + * Converts a string with a valid 'memory_limit' format, to bytes. + * + * @param string|false $val + * @return int|false Returns an integer representing bytes. Returns FALSE in case of error. + */ + public static function expandIniShorthandBytes($val) + { + if (!is_string($val)) { + return false; + } + + // support -1 + if ((int) $val < 0) { + return (int) $val; + } + + if (!preg_match('/^\s*(?\d+)(?:\.\d+)?\s*(?[gmk]?)\s*$/i', $val, $match)) { + return false; + } + + $val = (int) $match['val']; + switch (strtolower($match['unit'] ?? '')) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + + return $val; + } + + /** + * @param array $record + */ + public static function getRecordMessageForException(array $record): string + { + $context = ''; + $extra = ''; + try { + if ($record['context']) { + $context = "\nContext: " . json_encode($record['context']); + } + if ($record['extra']) { + $extra = "\nExtra: " . json_encode($record['extra']); + } + } catch (\Throwable $e) { + // noop + } + + return "\nThe exception occurred while attempting to log: " . $record['message'] . $context . $extra; + } } diff --git a/vendor/phpseclib/phpseclib/README.md b/vendor/phpseclib/phpseclib/README.md index 64c06ba2..bbb1e9f0 100644 --- a/vendor/phpseclib/phpseclib/README.md +++ b/vendor/phpseclib/phpseclib/README.md @@ -51,8 +51,7 @@ SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 / * PHP4 compatible * Composer compatible (PSR-0 autoloading) * Install using Composer: `composer require phpseclib/phpseclib:~1.0` -* Install using PEAR: See [phpseclib PEAR Channel Documentation](http://phpseclib.sourceforge.net/pear.htm) -* [Download 1.0.20 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.20.zip/download) +* [Download 1.0.21 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.21.zip/download) ## Security contact information diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php index 407f0369..256c8690 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php @@ -130,7 +130,7 @@ protected static function initialize_static_variables() * * @param string $key * @param string $password optional - * @return AsymmetricKey + * @return \phpseclib3\Crypt\Common\PublicKey|\phpseclib3\Crypt\Common\PrivateKey */ public static function load($key, $password = false) { diff --git a/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php b/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php index cf23dd73..3096ff1a 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php +++ b/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php @@ -1402,7 +1402,7 @@ public static function convert($in, $from = self::TYPE_UTF8_STRING, $to = self:: return false; } break; - case ($c & 0x80000000) != 0: + case ($c & (PHP_INT_SIZE == 8 ? 0x80000000 : (1 << 31))) != 0: return false; case $c >= 0x04000000: $v .= chr(0x80 | ($c & 0x3F)); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php index 3524668e..c6609e4d 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php @@ -136,7 +136,7 @@ private static function initialize_static_variables() { if (!isset(self::$mainEngine)) { $engines = [ - ['GMP'], + ['GMP', ['DefaultEngine']], ['PHP64', ['OpenSSL']], ['BCMath', ['OpenSSL']], ['PHP32', ['OpenSSL']], @@ -145,7 +145,7 @@ private static function initialize_static_variables() ]; foreach ($engines as $engine) { try { - self::setEngine($engine[0], isset($engine[1]) ? $engine[1] : []); + self::setEngine($engine[0], $engine[1]); break; } catch (\Exception $e) { } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php index 964cd170..18f78cdb 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php @@ -80,10 +80,10 @@ protected function initialize($base) } $step = count($vals) & 3; if ($step) { - $digit = floor($digit / pow(2, 2 * $step)); + $digit = (int) floor($digit / pow(2, 2 * $step)); } if ($step != 3) { - $digit &= static::MAX_DIGIT; + $digit = (int) fmod($digit, static::BASE_FULL); $i++; } $vals[] = $digit; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php b/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php index 748f9a49..ddb04912 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField/Integer.php @@ -312,8 +312,11 @@ public function negate() */ public function toBytes() { - $length = static::$modulo[$this->instanceID]->getLengthInBytes(); - return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT); + if (isset(static::$modulo[$this->instanceID])) { + $length = static::$modulo[$this->instanceID]->getLengthInBytes(); + return str_pad($this->value->toBytes(), $length, "\0", STR_PAD_LEFT); + } + return $this->value->toBytes(); } /** diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php index fb136bd7..cdf0bec6 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php @@ -2489,14 +2489,6 @@ public function get($remote_file, $local_file = false, $offset = 0, $length = -1 } } - if ($length > 0 && $length <= $offset - $start) { - if ($local_file === false) { - $content = substr($content, 0, $length); - } else { - ftruncate($fp, $length + $res_offset); - } - } - if ($fclose_check) { fclose($fp); diff --git a/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php b/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php index 517106c3..b794d549 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php +++ b/vendor/phpseclib/phpseclib/phpseclib/bootstrap.php @@ -20,3 +20,13 @@ ); } } + +// see https://github.com/php/php-src/issues/11917 +if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && function_exists('opcache_get_status') && !defined('PHPSECLIB_ALLOW_JIT')) { + $status = opcache_get_status(); + if ($status && isset($status['jit']) && $status['jit']['enabled'] && $status['jit']['on']) { + throw new UnexpectedValueException( + 'JIT on Windows is not currently supported' + ); + } +} diff --git a/vendor/psr/container/README.md b/vendor/psr/container/README.md index 084f6df5..1b9d9e57 100644 --- a/vendor/psr/container/README.md +++ b/vendor/psr/container/README.md @@ -1,5 +1,13 @@ -# PSR Container +Container interface +============== -This repository holds all interfaces/classes/traits related to [PSR-11](https://github.com/container-interop/fig-standards/blob/master/proposed/container.md). +This repository holds all interfaces related to [PSR-11 (Container Interface)][psr-url]. + +Note that this is not a Container implementation of its own. It is merely abstractions that describe the components of a Dependency Injection Container. + +The installable [package][package-url] and [implementations][implementation-url] are listed on Packagist. + +[psr-url]: https://www.php-fig.org/psr/psr-11/ +[package-url]: https://packagist.org/packages/psr/container +[implementation-url]: https://packagist.org/providers/psr/container-implementation -Note that this is not a container implementation of its own. See the specification for more details. diff --git a/vendor/psr/container/composer.json b/vendor/psr/container/composer.json index b8ee0126..017f41ea 100644 --- a/vendor/psr/container/composer.json +++ b/vendor/psr/container/composer.json @@ -8,20 +8,15 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "require": { - "php": ">=5.3.0" + "php": ">=7.4.0" }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" } - }, - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } } } diff --git a/vendor/psr/container/src/ContainerExceptionInterface.php b/vendor/psr/container/src/ContainerExceptionInterface.php index d35c6b4d..0f213f2f 100644 --- a/vendor/psr/container/src/ContainerExceptionInterface.php +++ b/vendor/psr/container/src/ContainerExceptionInterface.php @@ -1,13 +1,12 @@ Permission is hereby granted, free of charge, to any person obtaining a copy -> of this software and associated documentation files (the "Software"), to deal -> in the Software without restriction, including without limitation the rights -> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -> copies of the Software, and to permit persons to whom the Software is -> furnished to do so, subject to the following conditions: -> -> The above copyright notice and this permission notice shall be included in -> all copies or substantial portions of the Software. -> -> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -> THE SOFTWARE. diff --git a/vendor/psr/simple-cache/README.md b/vendor/psr/simple-cache/README.md deleted file mode 100644 index 43641d17..00000000 --- a/vendor/psr/simple-cache/README.md +++ /dev/null @@ -1,8 +0,0 @@ -PHP FIG Simple Cache PSR -======================== - -This repository holds all interfaces related to PSR-16. - -Note that this is not a cache implementation of its own. It is merely an interface that describes a cache implementation. See [the specification](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-16-simple-cache.md) for more details. - -You can find implementations of the specification by looking for packages providing the [psr/simple-cache-implementation](https://packagist.org/providers/psr/simple-cache-implementation) virtual package. diff --git a/vendor/psr/simple-cache/composer.json b/vendor/psr/simple-cache/composer.json deleted file mode 100644 index 2978fa55..00000000 --- a/vendor/psr/simple-cache/composer.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "psr/simple-cache", - "description": "Common interfaces for simple caching", - "keywords": ["psr", "psr-16", "cache", "simple-cache", "caching"], - "license": "MIT", - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "require": { - "php": ">=5.3.0" - }, - "autoload": { - "psr-4": { - "Psr\\SimpleCache\\": "src/" - } - }, - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - } -} diff --git a/vendor/psr/simple-cache/src/CacheException.php b/vendor/psr/simple-cache/src/CacheException.php deleted file mode 100644 index eba53815..00000000 --- a/vendor/psr/simple-cache/src/CacheException.php +++ /dev/null @@ -1,10 +0,0 @@ - value pairs. Cache keys that do not exist or are stale will have $default as value. - * - * @throws \Psr\SimpleCache\InvalidArgumentException - * MUST be thrown if $keys is neither an array nor a Traversable, - * or if any of the $keys are not a legal value. - */ - public function getMultiple($keys, $default = null); - - /** - * Persists a set of key => value pairs in the cache, with an optional TTL. - * - * @param iterable $values A list of key => value pairs for a multiple-set operation. - * @param null|int|\DateInterval $ttl Optional. The TTL value of this item. If no value is sent and - * the driver supports TTL then the library may set a default value - * for it or let the driver take care of that. - * - * @return bool True on success and false on failure. - * - * @throws \Psr\SimpleCache\InvalidArgumentException - * MUST be thrown if $values is neither an array nor a Traversable, - * or if any of the $values are not a legal value. - */ - public function setMultiple($values, $ttl = null); - - /** - * Deletes multiple cache items in a single operation. - * - * @param iterable $keys A list of string-based keys to be deleted. - * - * @return bool True if the items were successfully removed. False if there was an error. - * - * @throws \Psr\SimpleCache\InvalidArgumentException - * MUST be thrown if $keys is neither an array nor a Traversable, - * or if any of the $keys are not a legal value. - */ - public function deleteMultiple($keys); - - /** - * Determines whether an item is present in the cache. - * - * NOTE: It is recommended that has() is only to be used for cache warming type purposes - * and not to be used within your live applications operations for get/set, as this method - * is subject to a race condition where your has() will return true and immediately after, - * another script can remove it making the state of your app out of date. - * - * @param string $key The cache item key. - * - * @return bool - * - * @throws \Psr\SimpleCache\InvalidArgumentException - * MUST be thrown if the $key string is not a legal value. - */ - public function has($key); -} diff --git a/vendor/psr/simple-cache/src/InvalidArgumentException.php b/vendor/psr/simple-cache/src/InvalidArgumentException.php deleted file mode 100644 index 6a9524a2..00000000 --- a/vendor/psr/simple-cache/src/InvalidArgumentException.php +++ /dev/null @@ -1,13 +0,0 @@ - + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * Covers most simple to advanced caching needs. + * + * @author Nicolas Grekas + */ +interface CacheInterface +{ + /** + * Fetches a value from the pool or computes it if not found. + * + * On cache misses, a callback is called that should return the missing value. + * This callback is given a PSR-6 CacheItemInterface instance corresponding to the + * requested key, that could be used e.g. for expiration control. It could also + * be an ItemInterface instance when its additional features are needed. + * + * @param string $key The key of the item to retrieve from the cache + * @param callable|CallbackInterface $callback Should return the computed value for the given key/item + * @param float|null $beta A float that, as it grows, controls the likeliness of triggering + * early expiration. 0 disables it, INF forces immediate expiration. + * The default (or providing null) is implementation dependent but should + * typically be 1.0, which should provide optimal stampede protection. + * See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration + * @param array &$metadata The metadata of the cached item {@see ItemInterface::getMetadata()} + * + * @return mixed + * + * @throws InvalidArgumentException When $key is not valid or when $beta is negative + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null); + + /** + * Removes an item from the pool. + * + * @param string $key The key to delete + * + * @throws InvalidArgumentException When $key is not valid + * + * @return bool True if the item was successfully removed, false if there was any error + */ + public function delete(string $key): bool; +} diff --git a/vendor/symfony/cache-contracts/CacheTrait.php b/vendor/symfony/cache-contracts/CacheTrait.php new file mode 100644 index 00000000..d340e069 --- /dev/null +++ b/vendor/symfony/cache-contracts/CacheTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheItemPoolInterface; +use Psr\Cache\InvalidArgumentException; +use Psr\Log\LoggerInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(InvalidArgumentException::class); + +/** + * An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes. + * + * @author Nicolas Grekas + */ +trait CacheTrait +{ + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + return $this->doGet($this, $key, $callback, $beta, $metadata); + } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); + } + + private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null, LoggerInterface $logger = null) + { + if (0 > $beta = $beta ?? 1.0) { + throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)) extends \InvalidArgumentException implements InvalidArgumentException { }; + } + + $item = $pool->getItem($key); + $recompute = !$item->isHit() || \INF === $beta; + $metadata = $item instanceof ItemInterface ? $item->getMetadata() : []; + + if (!$recompute && $metadata) { + $expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false; + $ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false; + + if ($recompute = $ctime && $expiry && $expiry <= ($now = microtime(true)) - $ctime / 1000 * $beta * log(random_int(1, \PHP_INT_MAX) / \PHP_INT_MAX)) { + // force applying defaultLifetime to expiry + $item->expiresAt(null); + $logger && $logger->info('Item "{key}" elected for early recomputation {delta}s before its expiration', [ + 'key' => $key, + 'delta' => sprintf('%.1f', $expiry - $now), + ]); + } + } + + if ($recompute) { + $save = true; + $item->set($callback($item, $save)); + if ($save) { + $pool->save($item); + } + } + + return $item->get(); + } +} diff --git a/vendor/symfony/cache-contracts/CallbackInterface.php b/vendor/symfony/cache-contracts/CallbackInterface.php new file mode 100644 index 00000000..7dae2aac --- /dev/null +++ b/vendor/symfony/cache-contracts/CallbackInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheItemInterface; + +/** + * Computes and returns the cached value of an item. + * + * @author Nicolas Grekas + */ +interface CallbackInterface +{ + /** + * @param CacheItemInterface|ItemInterface $item The item to compute the value for + * @param bool &$save Should be set to false when the value should not be saved in the pool + * + * @return mixed The computed value for the passed item + */ + public function __invoke(CacheItemInterface $item, bool &$save); +} diff --git a/vendor/symfony/cache-contracts/ItemInterface.php b/vendor/symfony/cache-contracts/ItemInterface.php new file mode 100644 index 00000000..10c04889 --- /dev/null +++ b/vendor/symfony/cache-contracts/ItemInterface.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\CacheException; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * Augments PSR-6's CacheItemInterface with support for tags and metadata. + * + * @author Nicolas Grekas + */ +interface ItemInterface extends CacheItemInterface +{ + /** + * References the Unix timestamp stating when the item will expire. + */ + public const METADATA_EXPIRY = 'expiry'; + + /** + * References the time the item took to be created, in milliseconds. + */ + public const METADATA_CTIME = 'ctime'; + + /** + * References the list of tags that were assigned to the item, as string[]. + */ + public const METADATA_TAGS = 'tags'; + + /** + * Reserved characters that cannot be used in a key or tag. + */ + public const RESERVED_CHARACTERS = '{}()/\@:'; + + /** + * Adds a tag to a cache item. + * + * Tags are strings that follow the same validation rules as keys. + * + * @param string|string[] $tags A tag or array of tags + * + * @return $this + * + * @throws InvalidArgumentException When $tag is not valid + * @throws CacheException When the item comes from a pool that is not tag-aware + */ + public function tag($tags): self; + + /** + * Returns a list of metadata info that were saved alongside with the cached value. + * + * See ItemInterface::METADATA_* consts for keys potentially found in the returned array. + */ + public function getMetadata(): array; +} diff --git a/vendor/symfony/cache-contracts/LICENSE b/vendor/symfony/cache-contracts/LICENSE new file mode 100644 index 00000000..74cdc2db --- /dev/null +++ b/vendor/symfony/cache-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/cache-contracts/README.md b/vendor/symfony/cache-contracts/README.md new file mode 100644 index 00000000..7085a699 --- /dev/null +++ b/vendor/symfony/cache-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Cache Contracts +======================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/vendor/symfony/cache-contracts/TagAwareCacheInterface.php b/vendor/symfony/cache-contracts/TagAwareCacheInterface.php new file mode 100644 index 00000000..7c4cf111 --- /dev/null +++ b/vendor/symfony/cache-contracts/TagAwareCacheInterface.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Cache; + +use Psr\Cache\InvalidArgumentException; + +/** + * Allows invalidating cached items using tags. + * + * @author Nicolas Grekas + */ +interface TagAwareCacheInterface extends CacheInterface +{ + /** + * Invalidates cached items using tags. + * + * When implemented on a PSR-6 pool, invalidation should not apply + * to deferred items. Instead, they should be committed as usual. + * This allows replacing old tagged values by new ones without + * race conditions. + * + * @param string[] $tags An array of tags to invalidate + * + * @return bool True on success + * + * @throws InvalidArgumentException When $tags is not valid + */ + public function invalidateTags(array $tags); +} diff --git a/vendor/symfony/cache-contracts/composer.json b/vendor/symfony/cache-contracts/composer.json new file mode 100644 index 00000000..9f45e178 --- /dev/null +++ b/vendor/symfony/cache-contracts/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/cache-contracts", + "type": "library", + "description": "Generic abstractions related to caching", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "suggest": { + "symfony/cache-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Cache\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/vendor/symfony/cache/.gitignore b/vendor/symfony/cache/.gitignore deleted file mode 100644 index 5414c2c6..00000000 --- a/vendor/symfony/cache/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -composer.lock -phpunit.xml -vendor/ diff --git a/vendor/symfony/cache/Adapter/AbstractAdapter.php b/vendor/symfony/cache/Adapter/AbstractAdapter.php index ab7dc960..65647442 100644 --- a/vendor/symfony/cache/Adapter/AbstractAdapter.php +++ b/vendor/symfony/cache/Adapter/AbstractAdapter.php @@ -11,37 +11,32 @@ namespace Symfony\Component\Cache\Adapter; -use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; -use Symfony\Component\Cache\Traits\AbstractTrait; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Nicolas Grekas */ -abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface +abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { + use AbstractAdapterTrait; + use ContractsTrait; + /** * @internal */ - const NS_SEPARATOR = ':'; - - use AbstractTrait; + protected const NS_SEPARATOR = ':'; private static $apcuSupported; private static $phpFilesSupported; - private $createCacheItem; - private $mergeByLifetime; - - /** - * @param string $namespace - * @param int $defaultLifetime - */ - protected function __construct($namespace = '', $defaultLifetime = 0) + protected function __construct(string $namespace = '', int $defaultLifetime = 0) { $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).static::NS_SEPARATOR; if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { @@ -51,31 +46,45 @@ protected function __construct($namespace = '', $defaultLifetime = 0) static function ($key, $value, $isHit) { $item = new CacheItem(); $item->key = $key; - $item->value = $value; + $item->value = $v = $value; $item->isHit = $isHit; + // Detect wrapped values that encode for their expiry and creation duration + // For compactness, these values are packed in the key of an array using + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + $item->value = $v[$k]; + $v = unpack('Ve/Nc', substr($k, 1, -1)); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } return $item; }, null, CacheItem::class ); - $getId = function ($key) { return $this->getId((string) $key); }; + $getId = \Closure::fromCallable([$this, 'getId']); $this->mergeByLifetime = \Closure::bind( static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifetime) { $byLifetime = []; - $now = time(); + $now = microtime(true); $expiredIds = []; foreach ($deferred as $key => $item) { + $key = (string) $key; if (null === $item->expiry) { - $byLifetime[0 < $defaultLifetime ? $defaultLifetime : 0][$getId($key)] = $item->value; - } elseif (0 === $item->expiry) { - $byLifetime[0][$getId($key)] = $item->value; - } elseif ($item->expiry > $now) { - $byLifetime[$item->expiry - $now][$getId($key)] = $item->value; - } else { + $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; + } elseif (!$item->expiry) { + $ttl = 0; + } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { $expiredIds[] = $getId($key); + continue; + } + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + unset($metadata[CacheItem::METADATA_TAGS]); } + // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators + $byLifetime[$ttl][$getId($key)] = $metadata ? ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item->value] : $item->value; } return $byLifetime; @@ -86,6 +95,10 @@ static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifet } /** + * Returns the best possible adapter that your runtime supports. + * + * Using ApcuAdapter makes system caches compatible with read-only filesystems. + * * @param string $namespace * @param int $defaultLifetime * @param string $version @@ -95,37 +108,25 @@ static function ($deferred, $namespace, &$expiredIds) use ($getId, $defaultLifet */ public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null) { - if (null === self::$apcuSupported) { - self::$apcuSupported = ApcuAdapter::isSupported(); - } - - if (!self::$apcuSupported && null === self::$phpFilesSupported) { - self::$phpFilesSupported = PhpFilesAdapter::isSupported(); + $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true); + if (null !== $logger) { + $opcache->setLogger($logger); } - if (self::$phpFilesSupported) { - $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory); - if (null !== $logger) { - $opcache->setLogger($logger); - } - + if (!self::$apcuSupported = self::$apcuSupported ?? ApcuAdapter::isSupported()) { return $opcache; } - $fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory); - if (null !== $logger) { - $fs->setLogger($logger); - } - if (!self::$apcuSupported || (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) { - return $fs; + if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) { + return $opcache; } - $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version); + $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version); if (null !== $logger) { $apcu->setLogger($logger); } - return new ChainAdapter([$apcu, $fs]); + return new ChainAdapter([$apcu, $opcache]); } public static function createConnection($dsn, array $options = []) @@ -133,10 +134,10 @@ public static function createConnection($dsn, array $options = []) if (!\is_string($dsn)) { throw new InvalidArgumentException(sprintf('The "%s()" method expect argument #1 to be string, "%s" given.', __METHOD__, \gettype($dsn))); } - if (0 === strpos($dsn, 'redis://')) { + if (str_starts_with($dsn, 'redis:') || str_starts_with($dsn, 'rediss:')) { return RedisAdapter::createConnection($dsn, $options); } - if (0 === strpos($dsn, 'memcached://')) { + if (str_starts_with($dsn, 'memcached:')) { return MemcachedAdapter::createConnection($dsn, $options); } @@ -145,81 +146,8 @@ public static function createConnection($dsn, array $options = []) /** * {@inheritdoc} - */ - public function getItem($key) - { - if ($this->deferred) { - $this->commit(); - } - $id = $this->getId($key); - - $f = $this->createCacheItem; - $isHit = false; - $value = null; - - try { - foreach ($this->doFetch([$id]) as $value) { - $isHit = true; - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); - } - - return $f($key, $value, $isHit); - } - - /** - * {@inheritdoc} - */ - public function getItems(array $keys = []) - { - if ($this->deferred) { - $this->commit(); - } - $ids = []; - - foreach ($keys as $key) { - $ids[] = $this->getId($key); - } - try { - $items = $this->doFetch($ids); - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => $keys, 'exception' => $e]); - $items = []; - } - $ids = array_combine($ids, $keys); - - return $this->generateItems($items, $ids); - } - - /** - * {@inheritdoc} - */ - public function save(CacheItemInterface $item) - { - if (!$item instanceof CacheItem) { - return false; - } - $this->deferred[$item->getKey()] = $item; - - return $this->commit(); - } - - /** - * {@inheritdoc} - */ - public function saveDeferred(CacheItemInterface $item) - { - if (!$item instanceof CacheItem) { - return false; - } - $this->deferred[$item->getKey()] = $item; - - return true; - } - - /** - * {@inheritdoc} + * + * @return bool */ public function commit() { @@ -229,7 +157,12 @@ public function commit() $retry = $this->deferred = []; if ($expiredIds) { - $this->doDelete($expiredIds); + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } } foreach ($byLifetime as $lifetime => $values) { try { @@ -244,7 +177,8 @@ public function commit() $ok = false; $v = $values[$id]; $type = \is_object($v) ? \get_class($v) : \gettype($v); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); } } else { foreach ($values as $id => $v) { @@ -266,49 +200,11 @@ public function commit() } $ok = false; $type = \is_object($v) ? \get_class($v) : \gettype($v); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => substr($id, \strlen($this->namespace)), 'type' => $type, 'exception' => $e instanceof \Exception ? $e : null]); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); } } return $ok; } - - public function __sleep() - { - throw new \BadMethodCallException('Cannot serialize '.__CLASS__); - } - - public function __wakeup() - { - throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); - } - - public function __destruct() - { - if ($this->deferred) { - $this->commit(); - } - } - - private function generateItems($items, &$keys) - { - $f = $this->createCacheItem; - - try { - foreach ($items as $id => $value) { - if (!isset($keys[$id])) { - $id = key($keys); - } - $key = $keys[$id]; - unset($keys[$id]); - yield $key => $f($key, $value, true); - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested items', ['keys' => array_values($keys), 'exception' => $e]); - } - - foreach ($keys as $key) { - yield $key => $f($key, null, false); - } - } } diff --git a/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php new file mode 100644 index 00000000..6b62ae98 --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -0,0 +1,334 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\Log\LoggerAwareInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\AbstractAdapterTrait; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + +/** + * Abstract for native TagAware adapters. + * + * To keep info on tags, the tags are both serialized as part of cache value and provided as tag ids + * to Adapters on operations when needed for storage to doSave(), doDelete() & doInvalidate(). + * + * @author Nicolas Grekas + * @author André Rømcke + * + * @internal + */ +abstract class AbstractTagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, LoggerAwareInterface, ResettableInterface +{ + use AbstractAdapterTrait; + use ContractsTrait; + + private const TAGS_PREFIX = "\0tags\0"; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) + { + $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; + if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { + throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); + } + $this->createCacheItem = \Closure::bind( + static function ($key, $value, $isHit) { + $item = new CacheItem(); + $item->key = $key; + $item->isTaggable = true; + // If structure does not match what we expect return item as is (no value and not a hit) + if (!\is_array($value) || !\array_key_exists('value', $value)) { + return $item; + } + $item->isHit = $isHit; + // Extract value, tags and meta data from the cache value + $item->value = $value['value']; + $item->metadata[CacheItem::METADATA_TAGS] = $value['tags'] ?? []; + if (isset($value['meta'])) { + // For compactness these values are packed, & expiry is offset to reduce size + $v = unpack('Ve/Nc', $value['meta']); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } + + return $item; + }, + null, + CacheItem::class + ); + $getId = \Closure::fromCallable([$this, 'getId']); + $tagPrefix = self::TAGS_PREFIX; + $this->mergeByLifetime = \Closure::bind( + static function ($deferred, &$expiredIds) use ($getId, $tagPrefix, $defaultLifetime) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $defaultLifetime ? $defaultLifetime : 0; + } elseif (!$item->expiry) { + $ttl = 0; + } elseif (0 >= $ttl = (int) (0.1 + $item->expiry - $now)) { + $expiredIds[] = $getId($key); + continue; + } + // Store Value and Tags on the cache value + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + $value = ['value' => $item->value, 'tags' => $metadata[CacheItem::METADATA_TAGS]]; + unset($metadata[CacheItem::METADATA_TAGS]); + } else { + $value = ['value' => $item->value, 'tags' => []]; + } + + if ($metadata) { + // For compactness, expiry and creation duration are packed, using magic numbers as separators + $value['meta'] = pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME]); + } + + // Extract tag changes, these should be removed from values in doSave() + $value['tag-operations'] = ['add' => [], 'remove' => []]; + $oldTags = $item->metadata[CacheItem::METADATA_TAGS] ?? []; + foreach (array_diff($value['tags'], $oldTags) as $addedTag) { + $value['tag-operations']['add'][] = $getId($tagPrefix.$addedTag); + } + foreach (array_diff($oldTags, $value['tags']) as $removedTag) { + $value['tag-operations']['remove'][] = $getId($tagPrefix.$removedTag); + } + + $byLifetime[$ttl][$getId($key)] = $value; + $item->metadata = $item->newMetadata; + } + + return $byLifetime; + }, + null, + CacheItem::class + ); + } + + /** + * Persists several cache items immediately. + * + * @param array $values The values to cache, indexed by their cache identifier + * @param int $lifetime The lifetime of the cached values, 0 for persisting until manual cleaning + * @param array[] $addTagData Hash where key is tag id, and array value is list of cache id's to add to tag + * @param array[] $removeTagData Hash where key is tag id, and array value is list of cache id's to remove to tag + * + * @return array The identifiers that failed to be cached or a boolean stating if caching succeeded or not + */ + abstract protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array; + + /** + * Removes multiple items from the pool and their corresponding tags. + * + * @param array $ids An array of identifiers that should be removed from the pool + * + * @return bool True if the items were successfully removed, false otherwise + */ + abstract protected function doDelete(array $ids); + + /** + * Removes relations between tags and deleted items. + * + * @param array $tagData Array of tag => key identifiers that should be removed from the pool + */ + abstract protected function doDeleteTagRelations(array $tagData): bool; + + /** + * Invalidates cached items using tags. + * + * @param string[] $tagIds An array of tags to invalidate, key is tag and value is tag id + * + * @return bool True on success + */ + abstract protected function doInvalidate(array $tagIds): bool; + + /** + * Delete items and yields the tags they were bound to. + */ + protected function doDeleteYieldTags(array $ids): iterable + { + foreach ($this->doFetch($ids) as $id => $value) { + yield $id => \is_array($value) && \is_array($value['tags'] ?? null) ? $value['tags'] : []; + } + + $this->doDelete($ids); + } + + /** + * {@inheritdoc} + */ + public function commit(): bool + { + $ok = true; + $byLifetime = $this->mergeByLifetime; + $byLifetime = $byLifetime($this->deferred, $expiredIds); + $retry = $this->deferred = []; + + if ($expiredIds) { + // Tags are not cleaned up in this case, however that is done on invalidateTags(). + try { + $this->doDelete($expiredIds); + } catch (\Exception $e) { + $ok = false; + CacheItem::log($this->logger, 'Failed to delete expired items: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + } + foreach ($byLifetime as $lifetime => $values) { + try { + $values = $this->extractTagData($values, $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + if (\is_array($e) || 1 === \count($values)) { + foreach (\is_array($e) ? $e : array_keys($values) as $id) { + $ok = false; + $v = $values[$id]; + $type = \is_object($v) ? \get_class($v) : \gettype($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); + } + } else { + foreach ($values as $id => $v) { + $retry[$lifetime][] = $id; + } + } + } + + // When bulk-save failed, retry each item individually + foreach ($retry as $lifetime => $ids) { + foreach ($ids as $id) { + try { + $v = $byLifetime[$lifetime][$id]; + $values = $this->extractTagData([$id => $v], $addTagData, $removeTagData); + $e = $this->doSave($values, $lifetime, $addTagData, $removeTagData); + } catch (\Exception $e) { + } + if (true === $e || [] === $e) { + continue; + } + $ok = false; + $type = \is_object($v) ? \get_class($v) : \gettype($v); + $message = sprintf('Failed to save key "{key}" of type %s%s', $type, $e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e instanceof \Exception ? $e : null]); + } + } + + return $ok; + } + + /** + * {@inheritdoc} + */ + public function deleteItems(array $keys): bool + { + if (!$keys) { + return true; + } + + $ok = true; + $ids = []; + $tagData = []; + + foreach ($keys as $key) { + $ids[$key] = $this->getId($key); + unset($this->deferred[$key]); + } + + try { + foreach ($this->doDeleteYieldTags(array_values($ids)) as $id => $tags) { + foreach ($tags as $tag) { + $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id; + } + } + } catch (\Exception $e) { + $ok = false; + } + + try { + if ((!$tagData || $this->doDeleteTagRelations($tagData)) && $ok) { + return true; + } + } catch (\Exception $e) { + } + + // When bulk-delete failed, retry each item individually + foreach ($ids as $key => $id) { + try { + $e = null; + if ($this->doDelete([$id])) { + continue; + } + } catch (\Exception $e) { + } + $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]); + $ok = false; + } + + return $ok; + } + + /** + * {@inheritdoc} + */ + public function invalidateTags(array $tags) + { + if (empty($tags)) { + return false; + } + + $tagIds = []; + foreach (array_unique($tags) as $tag) { + $tagIds[] = $this->getId(self::TAGS_PREFIX.$tag); + } + + try { + if ($this->doInvalidate($tagIds)) { + return true; + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to invalidate tags: '.$e->getMessage(), ['exception' => $e, 'cache-adapter' => get_debug_type($this)]); + } + + return false; + } + + /** + * Extracts tags operation data from $values set in mergeByLifetime, and returns values without it. + */ + private function extractTagData(array $values, ?array &$addTagData, ?array &$removeTagData): array + { + $addTagData = $removeTagData = []; + foreach ($values as $id => $value) { + foreach ($value['tag-operations']['add'] as $tag => $tagId) { + $addTagData[$tagId][] = $id; + } + + foreach ($value['tag-operations']['remove'] as $tag => $tagId) { + $removeTagData[$tagId][] = $id; + } + + unset($values[$id]['tag-operations']); + } + + return $values; + } +} diff --git a/vendor/symfony/cache/Adapter/AdapterInterface.php b/vendor/symfony/cache/Adapter/AdapterInterface.php index 85fe0768..9e359e17 100644 --- a/vendor/symfony/cache/Adapter/AdapterInterface.php +++ b/vendor/symfony/cache/Adapter/AdapterInterface.php @@ -14,6 +14,9 @@ use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\CacheItem; +// Help opcache.preload discover always-needed symbols +class_exists(CacheItem::class); + /** * Interface for adapters managing instances of Symfony's CacheItem. * @@ -34,4 +37,13 @@ public function getItem($key); * @return \Traversable|CacheItem[] */ public function getItems(array $keys = []); + + /** + * {@inheritdoc} + * + * @param string $prefix + * + * @return bool + */ + public function clear(/* string $prefix = '' */); } diff --git a/vendor/symfony/cache/Adapter/ApcuAdapter.php b/vendor/symfony/cache/Adapter/ApcuAdapter.php index 50554ed6..7db39565 100644 --- a/vendor/symfony/cache/Adapter/ApcuAdapter.php +++ b/vendor/symfony/cache/Adapter/ApcuAdapter.php @@ -18,13 +18,9 @@ class ApcuAdapter extends AbstractAdapter use ApcuTrait; /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $version - * * @throws CacheException if APCu is not enabled */ - public function __construct($namespace = '', $defaultLifetime = 0, $version = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null) { $this->init($namespace, $defaultLifetime, $version); } diff --git a/vendor/symfony/cache/Adapter/ArrayAdapter.php b/vendor/symfony/cache/Adapter/ArrayAdapter.php index 33f55a86..20043dec 100644 --- a/vendor/symfony/cache/Adapter/ArrayAdapter.php +++ b/vendor/symfony/cache/Adapter/ArrayAdapter.php @@ -16,11 +16,12 @@ use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\ArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Nicolas Grekas */ -class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface +class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { use ArrayTrait; @@ -28,10 +29,9 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable private $defaultLifetime; /** - * @param int $defaultLifetime * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise */ - public function __construct($defaultLifetime = 0, $storeSerialized = true) + public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true) { $this->defaultLifetime = $defaultLifetime; $this->storeSerialized = $storeSerialized; @@ -52,24 +52,32 @@ static function ($key, $value, $isHit) { /** * {@inheritdoc} */ - public function getItem($key) + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) { - $isHit = $this->hasItem($key); - try { - if (!$isHit) { - $this->values[$key] = $value = null; - } elseif (!$this->storeSerialized) { - $value = $this->values[$key]; - } elseif ('b:0;' === $value = $this->values[$key]) { - $value = false; - } elseif (false === $value = unserialize($value)) { - $this->values[$key] = $value = null; - $isHit = false; + $item = $this->getItem($key); + $metadata = $item->getMetadata(); + + // ArrayAdapter works in memory, we don't care about stampede protection + if (\INF === $beta || !$item->isHit()) { + $save = true; + $item->set($callback($item, $save)); + if ($save) { + $this->save($item); } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]); + } + + return $item->get(); + } + + /** + * {@inheritdoc} + */ + public function getItem($key) + { + if (!$isHit = $this->hasItem($key)) { $this->values[$key] = $value = null; - $isHit = false; + } else { + $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key]; } $f = $this->createCacheItem; @@ -82,14 +90,18 @@ public function getItem($key) public function getItems(array $keys = []) { foreach ($keys as $key) { - CacheItem::validateKey($key); + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } } - return $this->generateItems($keys, time(), $this->createCacheItem); + return $this->generateItems($keys, microtime(true), $this->createCacheItem); } /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -102,6 +114,8 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { @@ -113,37 +127,32 @@ public function save(CacheItemInterface $item) $value = $item["\0*\0value"]; $expiry = $item["\0*\0expiry"]; - if (0 === $expiry) { - $expiry = \PHP_INT_MAX; - } + if (null !== $expiry) { + if (!$expiry) { + $expiry = \PHP_INT_MAX; + } elseif ($expiry <= microtime(true)) { + $this->deleteItem($key); - if (null !== $expiry && $expiry <= time()) { - $this->deleteItem($key); - - return true; - } - if ($this->storeSerialized) { - try { - $value = serialize($value); - } catch (\Exception $e) { - $type = \is_object($value) ? \get_class($value) : \gettype($value); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]); - - return false; + return true; } } + if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) { + return false; + } if (null === $expiry && 0 < $this->defaultLifetime) { - $expiry = time() + $this->defaultLifetime; + $expiry = microtime(true) + $this->defaultLifetime; } $this->values[$key] = $value; - $this->expiries[$key] = null !== $expiry ? $expiry : \PHP_INT_MAX; + $this->expiries[$key] = $expiry ?? \PHP_INT_MAX; return true; } /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { @@ -152,9 +161,19 @@ public function saveDeferred(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function commit() { return true; } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); + } } diff --git a/vendor/symfony/cache/Adapter/ChainAdapter.php b/vendor/symfony/cache/Adapter/ChainAdapter.php index fdb28846..57fb096b 100644 --- a/vendor/symfony/cache/Adapter/ChainAdapter.php +++ b/vendor/symfony/cache/Adapter/ChainAdapter.php @@ -17,6 +17,9 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; /** * Chains several adapters together. @@ -26,8 +29,10 @@ * * @author Kévin Dunglas */ -class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { + use ContractsTrait; + private $adapters = []; private $adapterCount; private $syncItem; @@ -36,7 +41,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn * @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items * @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones */ - public function __construct(array $adapters, $defaultLifetime = 0) + public function __construct(array $adapters, int $defaultLifetime = 0) { if (!$adapters) { throw new InvalidArgumentException('At least one adapter must be specified.'); @@ -46,7 +51,7 @@ public function __construct(array $adapters, $defaultLifetime = 0) if (!$adapter instanceof CacheItemPoolInterface) { throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($adapter), CacheItemPoolInterface::class)); } - if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) { + if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && $adapter instanceof ApcuAdapter && !filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) { continue; // skip putting APCu in the chain when the backend is disabled } @@ -59,11 +64,18 @@ public function __construct(array $adapters, $defaultLifetime = 0) $this->adapterCount = \count($this->adapters); $this->syncItem = \Closure::bind( - static function ($sourceItem, $item) use ($defaultLifetime) { + static function ($sourceItem, $item, $sourceMetadata = null) use ($defaultLifetime) { + $sourceItem->isTaggable = false; + $sourceMetadata = $sourceMetadata ?? $sourceItem->metadata; + unset($sourceMetadata[CacheItem::METADATA_TAGS]); + $item->value = $sourceItem->value; $item->isHit = $sourceItem->isHit; + $item->metadata = $item->newMetadata = $sourceItem->metadata = $sourceMetadata; - if (0 < $defaultLifetime) { + if (isset($item->metadata[CacheItem::METADATA_EXPIRY])) { + $item->expiresAt(\DateTime::createFromFormat('U.u', sprintf('%.6F', $item->metadata[CacheItem::METADATA_EXPIRY]))); + } elseif (0 < $defaultLifetime) { $item->expiresAfter($defaultLifetime); } @@ -74,6 +86,43 @@ static function ($sourceItem, $item) use ($defaultLifetime) { ); } + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + $doSave = true; + $callback = static function (CacheItem $item, bool &$save) use ($callback, &$doSave) { + $value = $callback($item, $save); + $doSave = $save; + + return $value; + }; + + $lastItem = null; + $i = 0; + $wrap = function (CacheItem $item = null, bool &$save = true) use ($key, $callback, $beta, &$wrap, &$i, &$doSave, &$lastItem, &$metadata) { + $adapter = $this->adapters[$i]; + if (isset($this->adapters[++$i])) { + $callback = $wrap; + $beta = \INF === $beta ? \INF : 0; + } + if ($adapter instanceof CacheInterface) { + $value = $adapter->get($key, $callback, $beta, $metadata); + } else { + $value = $this->doGet($adapter, $key, $callback, $beta, $metadata); + } + if (null !== $item) { + ($this->syncItem)($lastItem = $lastItem ?? $item, $item, $metadata); + } + $save = $doSave; + + return $value; + }; + + return $wrap(); + } + /** * {@inheritdoc} */ @@ -107,12 +156,12 @@ public function getItems(array $keys = []) return $this->generateItems($this->adapters[0]->getItems($keys), 0); } - private function generateItems($items, $adapterIndex) + private function generateItems(iterable $items, int $adapterIndex) { $missing = []; $misses = []; $nextAdapterIndex = $adapterIndex + 1; - $nextAdapter = isset($this->adapters[$nextAdapterIndex]) ? $this->adapters[$nextAdapterIndex] : null; + $nextAdapter = $this->adapters[$nextAdapterIndex] ?? null; foreach ($items as $k => $item) { if (!$nextAdapter || $item->isHit()) { @@ -140,6 +189,8 @@ private function generateItems($items, $adapterIndex) /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { @@ -154,14 +205,23 @@ public function hasItem($key) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; $cleared = true; $i = $this->adapterCount; while ($i--) { - $cleared = $this->adapters[$i]->clear() && $cleared; + if ($this->adapters[$i] instanceof AdapterInterface) { + $cleared = $this->adapters[$i]->clear($prefix) && $cleared; + } else { + $cleared = $this->adapters[$i]->clear() && $cleared; + } } return $cleared; @@ -169,6 +229,8 @@ public function clear() /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -184,6 +246,8 @@ public function deleteItem($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -199,6 +263,8 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { @@ -214,6 +280,8 @@ public function save(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { @@ -229,6 +297,8 @@ public function saveDeferred(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function commit() { @@ -264,7 +334,7 @@ public function prune() public function reset() { foreach ($this->adapters as $adapter) { - if ($adapter instanceof ResettableInterface) { + if ($adapter instanceof ResetInterface) { $adapter->reset(); } } diff --git a/vendor/symfony/cache/Adapter/DoctrineAdapter.php b/vendor/symfony/cache/Adapter/DoctrineAdapter.php index 8081d7dc..75ae4cb7 100644 --- a/vendor/symfony/cache/Adapter/DoctrineAdapter.php +++ b/vendor/symfony/cache/Adapter/DoctrineAdapter.php @@ -18,11 +18,7 @@ class DoctrineAdapter extends AbstractAdapter { use DoctrineTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0) { parent::__construct('', $defaultLifetime); $this->provider = $provider; diff --git a/vendor/symfony/cache/Adapter/FilesystemAdapter.php b/vendor/symfony/cache/Adapter/FilesystemAdapter.php index d071964e..7185dd48 100644 --- a/vendor/symfony/cache/Adapter/FilesystemAdapter.php +++ b/vendor/symfony/cache/Adapter/FilesystemAdapter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\FilesystemTrait; @@ -18,13 +20,9 @@ class FilesystemAdapter extends AbstractAdapter implements PruneableInterface { use FilesystemTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory - */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); } diff --git a/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php new file mode 100644 index 00000000..6dccbf08 --- /dev/null +++ b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php @@ -0,0 +1,239 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Marshaller\TagAwareMarshaller; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Traits\FilesystemTrait; + +/** + * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls. + * + * @author Nicolas Grekas + * @author André Rømcke + */ +class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface +{ + use FilesystemTrait { + doClear as private doClearCache; + doSave as private doSaveCache; + } + + /** + * Folder used for tag symlinks. + */ + private const TAG_FOLDER = 'tags'; + + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) + { + $this->marshaller = new TagAwareMarshaller($marshaller); + parent::__construct('', $defaultLifetime); + $this->init($namespace, $directory); + } + + /** + * {@inheritdoc} + */ + protected function doClear($namespace) + { + $ok = $this->doClearCache($namespace); + + if ('' !== $namespace) { + return $ok; + } + + set_error_handler(static function () {}); + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + try { + foreach ($this->scanHashDir($this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR) as $dir) { + if (rename($dir, $renamed = substr_replace($dir, bin2hex(random_bytes(4)), -8))) { + $dir = $renamed.\DIRECTORY_SEPARATOR; + } else { + $dir .= \DIRECTORY_SEPARATOR; + $renamed = null; + } + + for ($i = 0; $i < 38; ++$i) { + if (!file_exists($dir.$chars[$i])) { + continue; + } + for ($j = 0; $j < 38; ++$j) { + if (!file_exists($d = $dir.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + foreach (scandir($d, \SCANDIR_SORT_NONE) ?: [] as $link) { + if ('.' !== $link && '..' !== $link && (null !== $renamed || !realpath($d.\DIRECTORY_SEPARATOR.$link))) { + unlink($d.\DIRECTORY_SEPARATOR.$link); + } + } + null === $renamed ?: rmdir($d); + } + null === $renamed ?: rmdir($dir.$chars[$i]); + } + null === $renamed ?: rmdir($renamed); + } + } finally { + restore_error_handler(); + } + + return $ok; + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, int $lifetime, array $addTagData = [], array $removeTagData = []): array + { + $failed = $this->doSaveCache($values, $lifetime); + + // Add Tags as symlinks + foreach ($addTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $file = $this->getFile($id); + + if (!@symlink($file, $tagLink = $this->getFile($id, true, $tagFolder)) && !is_link($tagLink)) { + @unlink($file); + $failed[] = $id; + } + } + } + + // Unlink removed Tags + foreach ($removeTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + @unlink($this->getFile($id, false, $tagFolder)); + } + } + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDeleteYieldTags(array $ids): iterable + { + foreach ($ids as $id) { + $file = $this->getFile($id); + if (!file_exists($file) || !$h = @fopen($file, 'r')) { + continue; + } + + if ((\PHP_VERSION_ID >= 70300 || '\\' !== \DIRECTORY_SEPARATOR) && !@unlink($file)) { + fclose($h); + continue; + } + + $meta = explode("\n", fread($h, 4096), 3)[2] ?? ''; + + // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (13 < \strlen($meta) && "\x9D" === $meta[0] && "\0" === $meta[5] && "\x5F" === $meta[9]) { + $meta[9] = "\0"; + $tagLen = unpack('Nlen', $meta, 9)['len']; + $meta = substr($meta, 13, $tagLen); + + if (0 < $tagLen -= \strlen($meta)) { + $meta .= fread($h, $tagLen); + } + + try { + yield $id => '' === $meta ? [] : $this->marshaller->unmarshall($meta); + } catch (\Exception $e) { + yield $id => []; + } + } + + fclose($h); + + if (\PHP_VERSION_ID < 70300 && '\\' === \DIRECTORY_SEPARATOR) { + @unlink($file); + } + } + } + + /** + * {@inheritdoc} + */ + protected function doDeleteTagRelations(array $tagData): bool + { + foreach ($tagData as $tagId => $idList) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($idList as $id) { + @unlink($this->getFile($id, false, $tagFolder)); + } + } + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + foreach ($tagIds as $tagId) { + if (!file_exists($tagFolder = $this->getTagFolder($tagId))) { + continue; + } + + set_error_handler(static function () {}); + + try { + if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -9))) { + $tagFolder = $renamed.\DIRECTORY_SEPARATOR; + } else { + $renamed = null; + } + + foreach ($this->scanHashDir($tagFolder) as $itemLink) { + unlink(realpath($itemLink) ?: $itemLink); + unlink($itemLink); + } + + if (null === $renamed) { + continue; + } + + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + for ($i = 0; $i < 38; ++$i) { + for ($j = 0; $j < 38; ++$j) { + rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]); + } + rmdir($tagFolder.$chars[$i]); + } + rmdir($renamed); + } finally { + restore_error_handler(); + } + } + + return true; + } + + private function getTagFolder(string $tagId): string + { + return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR; + } +} diff --git a/vendor/symfony/cache/Adapter/MemcachedAdapter.php b/vendor/symfony/cache/Adapter/MemcachedAdapter.php index 5637141a..b678bb5d 100644 --- a/vendor/symfony/cache/Adapter/MemcachedAdapter.php +++ b/vendor/symfony/cache/Adapter/MemcachedAdapter.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\MemcachedTrait; class MemcachedAdapter extends AbstractAdapter @@ -29,8 +30,8 @@ class MemcachedAdapter extends AbstractAdapter * * Using a MemcachedAdapter as a pure items store is fine. */ - public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) + public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($client, $namespace, $defaultLifetime); + $this->init($client, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Adapter/NullAdapter.php b/vendor/symfony/cache/Adapter/NullAdapter.php index c81a1cd6..3c2979bd 100644 --- a/vendor/symfony/cache/Adapter/NullAdapter.php +++ b/vendor/symfony/cache/Adapter/NullAdapter.php @@ -13,11 +13,12 @@ use Psr\Cache\CacheItemInterface; use Symfony\Component\Cache\CacheItem; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Titouan Galopin */ -class NullAdapter implements AdapterInterface +class NullAdapter implements AdapterInterface, CacheInterface { private $createCacheItem; @@ -36,6 +37,16 @@ function ($key) { ); } + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + $save = true; + + return $callback(($this->createCacheItem)($key), $save); + } + /** * {@inheritdoc} */ @@ -56,6 +67,8 @@ public function getItems(array $keys = []) /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { @@ -64,14 +77,20 @@ public function hasItem($key) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { return true; } /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -80,6 +99,8 @@ public function deleteItem($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -88,26 +109,40 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { - return false; + return true; } /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { - return false; + return true; } /** * {@inheritdoc} + * + * @return bool */ public function commit() { - return false; + return true; + } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); } private function generateItems(array $keys) diff --git a/vendor/symfony/cache/Adapter/PdoAdapter.php b/vendor/symfony/cache/Adapter/PdoAdapter.php index 59038679..d118736a 100644 --- a/vendor/symfony/cache/Adapter/PdoAdapter.php +++ b/vendor/symfony/cache/Adapter/PdoAdapter.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Connection; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PdoTrait; @@ -27,6 +28,9 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface * a Doctrine DBAL Connection or a DSN string that will be used to * lazy-connect to the database when the cache is actually used. * + * When a Doctrine DBAL Connection is passed, the cache table is created + * automatically when possible. Otherwise, use the createTable() method. + * * List of available options: * * db_table: The name of the table [default: cache_items] * * db_id_col: The column where to store the cache id [default: item_id] @@ -37,17 +41,14 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface * * db_password: The password when lazy-connect [default: ''] * * db_connection_options: An array of driver-specific connection options [default: []] * - * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null - * @param string $namespace - * @param int $defaultLifetime - * @param array $options An associative array of options + * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null * * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION * @throws InvalidArgumentException When namespace contains invalid characters */ - public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = []) + public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null) { - $this->init($connOrDsn, $namespace, $defaultLifetime, $options); + $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller); } } diff --git a/vendor/symfony/cache/Adapter/PhpArrayAdapter.php b/vendor/symfony/cache/Adapter/PhpArrayAdapter.php index 47a259c1..bdce6e1a 100644 --- a/vendor/symfony/cache/Adapter/PhpArrayAdapter.php +++ b/vendor/symfony/cache/Adapter/PhpArrayAdapter.php @@ -17,7 +17,9 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Component\Cache\Traits\PhpArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0. @@ -26,8 +28,9 @@ * @author Titouan Galopin * @author Nicolas Grekas */ -class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { + use ContractsTrait; use PhpArrayTrait; private $createCacheItem; @@ -36,11 +39,10 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl * @param string $file The PHP file were values are cached * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit */ - public function __construct($file, AdapterInterface $fallbackPool) + public function __construct(string $file, AdapterInterface $fallbackPool) { $this->file = $file; $this->pool = $fallbackPool; - $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN); $this->createCacheItem = \Closure::bind( static function ($key, $value, $isHit) { $item = new CacheItem(); @@ -56,9 +58,7 @@ static function ($key, $value, $isHit) { } /** - * This adapter should only be used on PHP 7.0+ to take advantage of how PHP - * stores arrays in its latest versions. This factory method decorates the given - * fallback pool with this adapter only if the current PHP version is supported. + * This adapter takes advantage of how PHP stores arrays in its latest versions. * * @param string $file The PHP file were values are cached * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit @@ -67,15 +67,44 @@ static function ($key, $value, $isHit) { */ public static function create($file, CacheItemPoolInterface $fallbackPool) { - if (\PHP_VERSION_ID >= 70000) { - if (!$fallbackPool instanceof AdapterInterface) { - $fallbackPool = new ProxyAdapter($fallbackPool); + if (!$fallbackPool instanceof AdapterInterface) { + $fallbackPool = new ProxyAdapter($fallbackPool); + } + + return new static($file, $fallbackPool); + } + + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + if (null === $this->values) { + $this->initialize(); + } + if (!isset($this->keys[$key])) { + get_from_pool: + if ($this->pool instanceof CacheInterface) { + return $this->pool->get($key, $callback, $beta, $metadata); } - return new static($file, $fallbackPool); + return $this->doGet($this->pool, $key, $callback, $beta, $metadata); } + $value = $this->values[$this->keys[$key]]; - return $fallbackPool; + if ('N;' === $value) { + return null; + } + try { + if ($value instanceof \Closure) { + return $value(); + } + } catch (\Throwable $e) { + unset($this->keys[$key]); + goto get_from_pool; + } + + return $value; } /** @@ -89,23 +118,19 @@ public function getItem($key) if (null === $this->values) { $this->initialize(); } - if (!isset($this->values[$key])) { + if (!isset($this->keys[$key])) { return $this->pool->getItem($key); } - $value = $this->values[$key]; + $value = $this->values[$this->keys[$key]]; $isHit = true; if ('N;' === $value) { $value = null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + } elseif ($value instanceof \Closure) { try { - $e = null; - $value = unserialize($value); - } catch (\Error $e) { - } catch (\Exception $e) { - } - if (null !== $e) { + $value = $value(); + } catch (\Throwable $e) { $value = null; $isHit = false; } @@ -135,6 +160,8 @@ public function getItems(array $keys = []) /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { @@ -145,11 +172,13 @@ public function hasItem($key) $this->initialize(); } - return isset($this->values[$key]) || $this->pool->hasItem($key); + return isset($this->keys[$key]) || $this->pool->hasItem($key); } /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -160,11 +189,13 @@ public function deleteItem($key) $this->initialize(); } - return !isset($this->values[$key]) && $this->pool->deleteItem($key); + return !isset($this->keys[$key]) && $this->pool->deleteItem($key); } /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -176,7 +207,7 @@ public function deleteItems(array $keys) throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); } - if (isset($this->values[$key])) { + if (isset($this->keys[$key])) { $deleted = false; } else { $fallbackKeys[] = $key; @@ -195,6 +226,8 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { @@ -202,11 +235,13 @@ public function save(CacheItemInterface $item) $this->initialize(); } - return !isset($this->values[$item->getKey()]) && $this->pool->save($item); + return !isset($this->keys[$item->getKey()]) && $this->pool->save($item); } /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { @@ -214,37 +249,34 @@ public function saveDeferred(CacheItemInterface $item) $this->initialize(); } - return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item); + return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item); } /** * {@inheritdoc} + * + * @return bool */ public function commit() { return $this->pool->commit(); } - /** - * @return \Generator - */ - private function generateItems(array $keys) + private function generateItems(array $keys): \Generator { $f = $this->createCacheItem; $fallbackKeys = []; foreach ($keys as $key) { - if (isset($this->values[$key])) { - $value = $this->values[$key]; + if (isset($this->keys[$key])) { + $value = $this->values[$this->keys[$key]]; if ('N;' === $value) { yield $key => $f($key, null, true); - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + } elseif ($value instanceof \Closure) { try { - yield $key => $f($key, unserialize($value), true); - } catch (\Error $e) { - yield $key => $f($key, null, false); - } catch (\Exception $e) { + yield $key => $f($key, $value(), true); + } catch (\Throwable $e) { yield $key => $f($key, null, false); } } else { @@ -256,9 +288,7 @@ private function generateItems(array $keys) } if ($fallbackKeys) { - foreach ($this->pool->getItems($fallbackKeys) as $key => $item) { - yield $key => $item; - } + yield from $this->pool->getItems($fallbackKeys); } } diff --git a/vendor/symfony/cache/Adapter/PhpFilesAdapter.php b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php index b56143c2..10938a0a 100644 --- a/vendor/symfony/cache/Adapter/PhpFilesAdapter.php +++ b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php @@ -20,22 +20,19 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface use PhpFilesTrait; /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory + * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire. + * Doing so is encouraged because it fits perfectly OPcache's memory model. * * @throws CacheException if OPcache is not enabled */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false) { - if (!static::isSupported()) { - throw new CacheException('OPcache is not enabled.'); - } + $this->appendOnly = $appendOnly; + self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); - - $e = new \Exception(); - $this->includeHandler = function () use ($e) { throw $e; }; - $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN); + $this->includeHandler = static function ($type, $msg, $file, $line) { + throw new \ErrorException($msg, 0, $type, $file, $line); + }; } } diff --git a/vendor/symfony/cache/Adapter/ProxyAdapter.php b/vendor/symfony/cache/Adapter/ProxyAdapter.php index c89a760e..e006ea01 100644 --- a/vendor/symfony/cache/Adapter/ProxyAdapter.php +++ b/vendor/symfony/cache/Adapter/ProxyAdapter.php @@ -16,26 +16,26 @@ use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Nicolas Grekas */ -class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { + use ContractsTrait; use ProxyTrait; private $namespace; private $namespaceLen; private $createCacheItem; + private $setInnerItem; private $poolHash; private $defaultLifetime; - /** - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0) { $this->pool = $pool; $this->poolHash = $poolHash = spl_object_hash($pool); @@ -46,20 +46,71 @@ public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defa static function ($key, $innerItem) use ($poolHash) { $item = new CacheItem(); $item->key = $key; + + if (null === $innerItem) { + return $item; + } + + $item->value = $v = $innerItem->get(); + $item->isHit = $innerItem->isHit(); + $item->innerItem = $innerItem; $item->poolHash = $poolHash; - if (null !== $innerItem) { - $item->value = $innerItem->get(); - $item->isHit = $innerItem->isHit(); - $item->innerItem = $innerItem; - $innerItem->set(null); + // Detect wrapped values that encode for their expiry and creation duration + // For compactness, these values are packed in the key of an array using + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = (string) array_key_first($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + $item->value = $v[$k]; + $v = unpack('Ve/Nc', substr($k, 1, -1)); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } elseif ($innerItem instanceof CacheItem) { + $item->metadata = $innerItem->metadata; } + $innerItem->set(null); return $item; }, null, CacheItem::class ); + $this->setInnerItem = \Closure::bind( + /** + * @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix + */ + static function (CacheItemInterface $innerItem, array $item) { + // Tags are stored separately, no need to account for them when considering this item's newly set metadata + if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) { + unset($metadata[CacheItem::METADATA_TAGS]); + } + if ($metadata) { + // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators + $item["\0*\0value"] = ["\x9D".pack('VN', (int) (0.1 + $metadata[self::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[self::METADATA_CTIME])."\x5F" => $item["\0*\0value"]]; + } + $innerItem->set($item["\0*\0value"]); + $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6F', $item["\0*\0expiry"])) : null); + }, + null, + CacheItem::class + ); + } + + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + if (!$this->pool instanceof CacheInterface) { + return $this->doGet($this, $key, $callback, $beta, $metadata); + } + + return $this->pool->get($this->getId($key), function ($innerItem, bool &$save) use ($key, $callback) { + $item = ($this->createCacheItem)($key, $innerItem); + $item->set($value = $callback($item, $save)); + ($this->setInnerItem)($innerItem, (array) $item); + + return $value; + }, $beta, $metadata); } /** @@ -89,6 +140,8 @@ public function getItems(array $keys = []) /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { @@ -97,14 +150,26 @@ public function hasItem($key) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; + + if ($this->pool instanceof AdapterInterface) { + return $this->pool->clear($this->namespace.$prefix); + } + return $this->pool->clear(); } /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -113,6 +178,8 @@ public function deleteItem($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -127,6 +194,8 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { @@ -135,6 +204,8 @@ public function save(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { @@ -143,21 +214,22 @@ public function saveDeferred(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function commit() { return $this->pool->commit(); } - private function doSave(CacheItemInterface $item, $method) + private function doSave(CacheItemInterface $item, string $method) { if (!$item instanceof CacheItem) { return false; } $item = (array) $item; - $expiry = $item["\0*\0expiry"]; - if (null === $expiry && 0 < $this->defaultLifetime) { - $expiry = time() + $this->defaultLifetime; + if (null === $item["\0*\0expiry"] && 0 < $this->defaultLifetime) { + $item["\0*\0expiry"] = microtime(true) + $this->defaultLifetime; } if ($item["\0*\0poolHash"] === $this->poolHash && $item["\0*\0innerItem"]) { @@ -171,13 +243,12 @@ private function doSave(CacheItemInterface $item, $method) $innerItem = $this->pool->getItem($this->namespace.$item["\0*\0key"]); } - $innerItem->set($item["\0*\0value"]); - $innerItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null); + ($this->setInnerItem)($innerItem, $item); return $this->pool->$method($innerItem); } - private function generateItems($items) + private function generateItems(iterable $items) { $f = $this->createCacheItem; @@ -190,7 +261,7 @@ private function generateItems($items) } } - private function getId($key) + private function getId($key): string { CacheItem::validateKey($key); diff --git a/vendor/symfony/cache/Adapter/Psr16Adapter.php b/vendor/symfony/cache/Adapter/Psr16Adapter.php new file mode 100644 index 00000000..e959d784 --- /dev/null +++ b/vendor/symfony/cache/Adapter/Psr16Adapter.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ProxyTrait; + +/** + * Turns a PSR-16 cache into a PSR-6 one. + * + * @author Nicolas Grekas + */ +class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + /** + * @internal + */ + protected const NS_SEPARATOR = '_'; + + private $miss; + + public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0) + { + parent::__construct($namespace, $defaultLifetime); + + $this->pool = $pool; + $this->miss = new \stdClass(); + } + + /** + * {@inheritdoc} + */ + protected function doFetch(array $ids) + { + foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) { + if ($this->miss !== $value) { + yield $key => $value; + } + } + } + + /** + * {@inheritdoc} + */ + protected function doHave($id) + { + return $this->pool->has($id); + } + + /** + * {@inheritdoc} + */ + protected function doClear($namespace) + { + return $this->pool->clear(); + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids) + { + return $this->pool->deleteMultiple($ids); + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, int $lifetime) + { + return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); + } +} diff --git a/vendor/symfony/cache/Adapter/RedisAdapter.php b/vendor/symfony/cache/Adapter/RedisAdapter.php index c1e17997..eb5950e5 100644 --- a/vendor/symfony/cache/Adapter/RedisAdapter.php +++ b/vendor/symfony/cache/Adapter/RedisAdapter.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Traits\RedisClusterProxy; +use Symfony\Component\Cache\Traits\RedisProxy; use Symfony\Component\Cache\Traits\RedisTrait; class RedisAdapter extends AbstractAdapter @@ -18,12 +21,12 @@ class RedisAdapter extends AbstractAdapter use RedisTrait; /** - * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client - * @param string $namespace The default namespace - * @param int $defaultLifetime The default lifetime + * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis The redis client + * @param string $namespace The default namespace + * @param int $defaultLifetime The default lifetime */ - public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) + public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($redisClient, $namespace, $defaultLifetime); + $this->init($redis, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php new file mode 100644 index 00000000..fd263da3 --- /dev/null +++ b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php @@ -0,0 +1,321 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Adapter; + +use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Connection\Aggregate\PredisCluster; +use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Response\ErrorInterface; +use Predis\Response\Status; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\DeflateMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Marshaller\TagAwareMarshaller; +use Symfony\Component\Cache\Traits\RedisClusterProxy; +use Symfony\Component\Cache\Traits\RedisProxy; +use Symfony\Component\Cache\Traits\RedisTrait; + +/** + * Stores tag id <> cache id relationship as a Redis Set. + * + * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even + * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache + * relationship survives eviction (cache cleanup when Redis runs out of memory). + * + * Redis server 2.8+ with any `volatile-*` eviction policy, OR `noeviction` if you're sure memory will NEVER fill up + * + * Design limitations: + * - Max 4 billion cache keys per cache tag as limited by Redis Set datatype. + * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 4 billion cache items also. + * + * @see https://redis.io/topics/lru-cache#eviction-policies Documentation for Redis eviction policies. + * @see https://redis.io/topics/data-types#sets Documentation for Redis Set datatype. + * + * @author Nicolas Grekas + * @author André Rømcke + */ +class RedisTagAwareAdapter extends AbstractTagAwareAdapter +{ + use RedisTrait; + + /** + * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are + * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements. + */ + private const DEFAULT_CACHE_TTL = 8640000; + + /** + * @var string|null detected eviction policy used on Redis server + */ + private $redisEvictionPolicy; + private $namespace; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis The redis client + * @param string $namespace The default namespace + * @param int $defaultLifetime The default lifetime + */ + public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) + { + if ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof ClusterInterface && !$redis->getConnection() instanceof PredisCluster) { + throw new InvalidArgumentException(sprintf('Unsupported Predis cluster connection: only "%s" is, "%s" given.', PredisCluster::class, \get_class($redis->getConnection()))); + } + + if (\defined('Redis::OPT_COMPRESSION') && ($redis instanceof \Redis || $redis instanceof \RedisArray || $redis instanceof \RedisCluster)) { + $compression = $redis->getOption(\Redis::OPT_COMPRESSION); + + foreach (\is_array($compression) ? $compression : [$compression] as $c) { + if (\Redis::COMPRESSION_NONE !== $c) { + throw new InvalidArgumentException(sprintf('phpredis compression must be disabled when using "%s", use "%s" instead.', static::class, DeflateMarshaller::class)); + } + } + } + + $this->init($redis, $namespace, $defaultLifetime, new TagAwareMarshaller($marshaller)); + $this->namespace = $namespace; + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, int $lifetime, array $addTagData = [], array $delTagData = []): array + { + $eviction = $this->getRedisEvictionPolicy(); + if ('noeviction' !== $eviction && !str_starts_with($eviction, 'volatile-')) { + throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction)); + } + + // serialize values + if (!$serialized = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + + // While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op + $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData, $failed) { + // Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one + foreach ($serialized as $id => $value) { + yield 'setEx' => [ + $id, + 0 >= $lifetime ? self::DEFAULT_CACHE_TTL : $lifetime, + $value, + ]; + } + + // Add and Remove Tags + foreach ($addTagData as $tagId => $ids) { + if (!$failed || $ids = array_diff($ids, $failed)) { + yield 'sAdd' => array_merge([$tagId], $ids); + } + } + + foreach ($delTagData as $tagId => $ids) { + if (!$failed || $ids = array_diff($ids, $failed)) { + yield 'sRem' => array_merge([$tagId], $ids); + } + } + }); + + foreach ($results as $id => $result) { + // Skip results of SADD/SREM operations, they'll be 1 or 0 depending on if set value already existed or not + if (is_numeric($result)) { + continue; + } + // setEx results + if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) { + $failed[] = $id; + } + } + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDeleteYieldTags(array $ids): iterable + { + $lua = <<<'EOLUA' + local v = redis.call('GET', KEYS[1]) + redis.call('DEL', KEYS[1]) + + if not v or v:len() <= 13 or v:byte(1) ~= 0x9D or v:byte(6) ~= 0 or v:byte(10) ~= 0x5F then + return '' + end + + return v:sub(14, 13 + v:byte(13) + v:byte(12) * 256 + v:byte(11) * 65536) +EOLUA; + + $results = $this->pipeline(function () use ($ids, $lua) { + foreach ($ids as $id) { + yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id] : [$lua, [$id], 1]; + } + }); + + foreach ($results as $id => $result) { + if ($result instanceof \RedisException || $result instanceof ErrorInterface) { + CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]); + + continue; + } + + try { + yield $id => !\is_string($result) || '' === $result ? [] : $this->marshaller->unmarshall($result); + } catch (\Exception $e) { + yield $id => []; + } + } + } + + /** + * {@inheritdoc} + */ + protected function doDeleteTagRelations(array $tagData): bool + { + $results = $this->pipeline(static function () use ($tagData) { + foreach ($tagData as $tagId => $idList) { + array_unshift($idList, $tagId); + yield 'sRem' => $idList; + } + }); + foreach ($results as $result) { + // no-op + } + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + // This script scans the set of items linked to tag: it empties the set + // and removes the linked items. When the set is still not empty after + // the scan, it means we're in cluster mode and that the linked items + // are on other nodes: we move the links to a temporary set and we + // garbage collect that set from the client side. + + $lua = <<<'EOLUA' + redis.replicate_commands() + + local cursor = '0' + local id = KEYS[1] + repeat + local result = redis.call('SSCAN', id, cursor, 'COUNT', 5000); + cursor = result[1]; + local rems = {} + + for _, v in ipairs(result[2]) do + local ok, _ = pcall(redis.call, 'DEL', ARGV[1]..v) + if ok then + table.insert(rems, v) + end + end + if 0 < #rems then + redis.call('SREM', id, unpack(rems)) + end + until '0' == cursor; + + redis.call('SUNIONSTORE', '{'..id..'}'..id, id) + redis.call('DEL', id) + + return redis.call('SSCAN', '{'..id..'}'..id, '0', 'COUNT', 5000) +EOLUA; + + $results = $this->pipeline(function () use ($tagIds, $lua) { + if ($this->redis instanceof \Predis\ClientInterface) { + $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : ''; + } elseif (\is_array($prefix = $this->redis->getOption(\Redis::OPT_PREFIX) ?? '')) { + $prefix = current($prefix); + } + + foreach ($tagIds as $id) { + yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id, $prefix] : [$lua, [$id, $prefix], 1]; + } + }); + + $lua = <<<'EOLUA' + redis.replicate_commands() + + local id = KEYS[1] + local cursor = table.remove(ARGV) + redis.call('SREM', '{'..id..'}'..id, unpack(ARGV)) + + return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000) +EOLUA; + + $success = true; + foreach ($results as $id => $values) { + if ($values instanceof \RedisException || $values instanceof ErrorInterface) { + CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]); + $success = false; + + continue; + } + + [$cursor, $ids] = $values; + + while ($ids || '0' !== $cursor) { + $this->doDelete($ids); + + $evalArgs = [$id, $cursor]; + array_splice($evalArgs, 1, 0, $ids); + + if ($this->redis instanceof \Predis\ClientInterface) { + array_unshift($evalArgs, $lua, 1); + } else { + $evalArgs = [$lua, $evalArgs, 1]; + } + + $results = $this->pipeline(function () use ($evalArgs) { + yield 'eval' => $evalArgs; + }); + + foreach ($results as [$cursor, $ids]) { + // no-op + } + } + } + + return $success; + } + + private function getRedisEvictionPolicy(): string + { + if (null !== $this->redisEvictionPolicy) { + return $this->redisEvictionPolicy; + } + + $hosts = $this->getHosts(); + $host = reset($hosts); + if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { + // Predis supports info command only on the master in replication environments + $hosts = [$host->getClientFor('master')]; + } + + foreach ($hosts as $host) { + $info = $host->info('Memory'); + + if ($info instanceof ErrorInterface) { + continue; + } + + $info = $info['Memory'] ?? $info; + + return $this->redisEvictionPolicy = $info['maxmemory_policy']; + } + + return $this->redisEvictionPolicy = ''; + } +} diff --git a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php index d3d0ede6..5f14a85b 100644 --- a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php +++ b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php @@ -11,73 +11,11 @@ namespace Symfony\Component\Cache\Adapter; -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\Traits\ProxyTrait; +@trigger_error(sprintf('The "%s" class is @deprecated since Symfony 4.3, use "Psr16Adapter" instead.', SimpleCacheAdapter::class), \E_USER_DEPRECATED); /** - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use Psr16Adapter instead. */ -class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface +class SimpleCacheAdapter extends Psr16Adapter { - /** - * @internal - */ - const NS_SEPARATOR = '_'; - - use ProxyTrait; - - private $miss; - - public function __construct(CacheInterface $pool, $namespace = '', $defaultLifetime = 0) - { - parent::__construct($namespace, $defaultLifetime); - - $this->pool = $pool; - $this->miss = new \stdClass(); - } - - /** - * {@inheritdoc} - */ - protected function doFetch(array $ids) - { - foreach ($this->pool->getMultiple($ids, $this->miss) as $key => $value) { - if ($this->miss !== $value) { - yield $key => $value; - } - } - } - - /** - * {@inheritdoc} - */ - protected function doHave($id) - { - return $this->pool->has($id); - } - - /** - * {@inheritdoc} - */ - protected function doClear($namespace) - { - return $this->pool->clear(); - } - - /** - * {@inheritdoc} - */ - protected function doDelete(array $ids) - { - return $this->pool->deleteMultiple($ids); - } - - /** - * {@inheritdoc} - */ - protected function doSave(array $values, $lifetime) - { - return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); - } } diff --git a/vendor/symfony/cache/Adapter/TagAwareAdapter.php b/vendor/symfony/cache/Adapter/TagAwareAdapter.php index febe5090..105d4a64 100644 --- a/vendor/symfony/cache/Adapter/TagAwareAdapter.php +++ b/vendor/symfony/cache/Adapter/TagAwareAdapter.php @@ -13,20 +13,26 @@ use Psr\Cache\CacheItemInterface; use Psr\Cache\InvalidArgumentException; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; /** * @author Nicolas Grekas */ -class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface +class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface, LoggerAwareInterface { - const TAGS_PREFIX = "\0tags\0"; - + use ContractsTrait; + use LoggerAwareTrait; use ProxyTrait; + public const TAGS_PREFIX = "\0tags\0"; + private $deferred = []; private $createCacheItem; private $setCacheItemTags; @@ -36,7 +42,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R private $knownTagVersions = []; private $knownTagVersionsTtl; - public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, $knownTagVersionsTtl = 0.15) + public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15) { $this->pool = $itemsPool; $this->tags = $tagsPool ?: $itemsPool; @@ -56,12 +62,13 @@ static function ($key, $value, CacheItem $protoItem) { ); $this->setCacheItemTags = \Closure::bind( static function (CacheItem $item, $key, array &$itemTags) { + $item->isTaggable = true; if (!$item->isHit) { return $item; } if (isset($itemTags[$key])) { foreach ($itemTags[$key] as $tag => $version) { - $item->prevTags[$tag] = $tag; + $item->metadata[CacheItem::METADATA_TAGS][$tag] = $tag; } unset($itemTags[$key]); } else { @@ -78,7 +85,8 @@ static function (CacheItem $item, $key, array &$itemTags) { static function ($deferred) { $tagsByKey = []; foreach ($deferred as $key => $item) { - $tagsByKey[$key] = $item->tags; + $tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? []; + $item->metadata = $item->newMetadata; } return $tagsByKey; @@ -145,12 +153,15 @@ public function invalidateTags(array $tags) /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { - if ($this->deferred) { + if (\is_string($key) && isset($this->deferred[$key])) { $this->commit(); } + if (!$this->pool->hasItem($key)) { return false; } @@ -166,9 +177,11 @@ public function hasItem($key) } foreach ($this->getTagVersions([$itemTags]) as $tag => $version) { - if ($itemTags[$tag] !== $version && 1 !== $itemTags[$tag] - $version) { - return false; + if ($itemTags[$tag] === $version || \is_int($itemTags[$tag]) && \is_int($version) && 1 === $itemTags[$tag] - $version) { + continue; } + + return false; } return true; @@ -191,18 +204,21 @@ public function getItem($key) */ public function getItems(array $keys = []) { - if ($this->deferred) { - $this->commit(); - } $tagKeys = []; + $commit = false; foreach ($keys as $key) { if ('' !== $key && \is_string($key)) { + $commit = $commit || isset($this->deferred[$key]); $key = static::TAGS_PREFIX.$key; $tagKeys[$key] = $key; } } + if ($commit) { + $this->commit(); + } + try { $items = $this->pool->getItems($tagKeys + $keys); } catch (InvalidArgumentException $e) { @@ -216,16 +232,36 @@ public function getItems(array $keys = []) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { - $this->deferred = []; + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; + + if ('' !== $prefix) { + foreach ($this->deferred as $key => $item) { + if (str_starts_with($key, $prefix)) { + unset($this->deferred[$key]); + } + } + } else { + $this->deferred = []; + } + + if ($this->pool instanceof AdapterInterface) { + return $this->pool->clear($prefix); + } return $this->pool->clear(); } /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -234,6 +270,8 @@ public function deleteItem($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -248,6 +286,8 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { @@ -261,6 +301,8 @@ public function save(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { @@ -274,12 +316,17 @@ public function saveDeferred(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function commit() { return $this->invalidateTags([]); } + /** + * @return array + */ public function __sleep() { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); @@ -295,7 +342,7 @@ public function __destruct() $this->commit(); } - private function generateItems($items, array $tagKeys) + private function generateItems(iterable $items, array $tagKeys) { $bufferedItems = $itemTags = []; $f = $this->setCacheItemTags; @@ -321,10 +368,11 @@ private function generateItems($items, array $tagKeys) foreach ($itemTags as $key => $tags) { foreach ($tags as $tag => $version) { - if ($tagVersions[$tag] !== $version && 1 !== $version - $tagVersions[$tag]) { - unset($itemTags[$key]); - continue 2; + if ($tagVersions[$tag] === $version || \is_int($version) && \is_int($tagVersions[$tag]) && 1 === $version - $tagVersions[$tag]) { + continue; } + unset($itemTags[$key]); + continue 2; } } $tagVersions = $tagKeys = null; @@ -363,7 +411,7 @@ private function getTagVersions(array $tagsByKey, array &$invalidatedTags = []) $tags = []; foreach ($tagVersions as $tag => $version) { $tags[$tag.static::TAGS_PREFIX] = $tag; - if ($fetchTagVersions || !isset($this->knownTagVersions[$tag])) { + if ($fetchTagVersions || !isset($this->knownTagVersions[$tag]) || !\is_int($version)) { $fetchTagVersions = true; continue; } @@ -385,6 +433,10 @@ private function getTagVersions(array $tagsByKey, array &$invalidatedTags = []) if (isset($invalidatedTags[$tag])) { $invalidatedTags[$tag] = $version->set(++$tagVersions[$tag]); } + if (!\is_int($tagVersions[$tag])) { + unset($this->knownTagVersions[$tag]); + continue; + } $this->knownTagVersions[$tag] = [$now, $tagVersions[$tag]]; } diff --git a/vendor/symfony/cache/Adapter/TraceableAdapter.php b/vendor/symfony/cache/Adapter/TraceableAdapter.php index cc855c13..9e65b2ef 100644 --- a/vendor/symfony/cache/Adapter/TraceableAdapter.php +++ b/vendor/symfony/cache/Adapter/TraceableAdapter.php @@ -12,8 +12,11 @@ namespace Symfony\Component\Cache\Adapter; use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; /** * An adapter that collects data about all cache calls. @@ -22,7 +25,7 @@ * @author Tobias Nyholm * @author Nicolas Grekas */ -class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { protected $pool; private $calls = []; @@ -32,6 +35,38 @@ public function __construct(AdapterInterface $pool) $this->pool = $pool; } + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + if (!$this->pool instanceof CacheInterface) { + throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', \get_class($this->pool), CacheInterface::class)); + } + + $isHit = true; + $callback = function (CacheItem $item, bool &$save) use ($callback, &$isHit) { + $isHit = $item->isHit(); + + return $callback($item, $save); + }; + + $event = $this->start(__FUNCTION__); + try { + $value = $this->pool->get($key, $callback, $beta, $metadata); + $event->result[$key] = \is_object($value) ? \get_class($value) : \gettype($value); + } finally { + $event->end = microtime(true); + } + if ($isHit) { + ++$event->hits; + } else { + ++$event->misses; + } + + return $value; + } + /** * {@inheritdoc} */ @@ -54,6 +89,8 @@ public function getItem($key) /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { @@ -67,6 +104,8 @@ public function hasItem($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -80,6 +119,8 @@ public function deleteItem($key) /** * {@inheritdoc} + * + * @return bool */ public function save(CacheItemInterface $item) { @@ -93,6 +134,8 @@ public function save(CacheItemInterface $item) /** * {@inheritdoc} + * + * @return bool */ public function saveDeferred(CacheItemInterface $item) { @@ -132,11 +175,20 @@ public function getItems(array $keys = []) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; $event = $this->start(__FUNCTION__); try { + if ($this->pool instanceof AdapterInterface) { + return $event->result = $this->pool->clear($prefix); + } + return $event->result = $this->pool->clear(); } finally { $event->end = microtime(true); @@ -145,6 +197,8 @@ public function clear() /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -159,6 +213,8 @@ public function deleteItems(array $keys) /** * {@inheritdoc} + * + * @return bool */ public function commit() { @@ -191,13 +247,26 @@ public function prune() */ public function reset() { - if ($this->pool instanceof ResettableInterface) { + if ($this->pool instanceof ResetInterface) { $this->pool->reset(); } $this->clearCalls(); } + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$key] = $this->pool->deleteItem($key); + } finally { + $event->end = microtime(true); + } + } + public function getCalls() { return $this->calls; diff --git a/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php index de68955d..69461b8b 100644 --- a/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php +++ b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php @@ -11,10 +11,12 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + /** * @author Robin Chalas */ -class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface +class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface { public function __construct(TagAwareAdapterInterface $pool) { diff --git a/vendor/symfony/cache/CHANGELOG.md b/vendor/symfony/cache/CHANGELOG.md index 11c1b936..435eaf3d 100644 --- a/vendor/symfony/cache/CHANGELOG.md +++ b/vendor/symfony/cache/CHANGELOG.md @@ -1,6 +1,43 @@ CHANGELOG ========= +4.4.0 +----- + + * added support for connecting to Redis Sentinel clusters + * added argument `$prefix` to `AdapterInterface::clear()` + * improved `RedisTagAwareAdapter` to support Redis server >= 2.8 and up to 4B items per tag + * added `TagAwareMarshaller` for optimized data storage when using `AbstractTagAwareAdapter` + * added `DeflateMarshaller` to compress serialized values + * removed support for phpredis 4 `compression` + * [BC BREAK] `RedisTagAwareAdapter` is not compatible with `RedisCluster` from `Predis` anymore, use `phpredis` instead + * Marked the `CacheDataCollector` class as `@final`. + +4.3.0 +----- + + * removed `psr/simple-cache` dependency, run `composer require psr/simple-cache` if you need it + * deprecated all PSR-16 adapters, use `Psr16Cache` or `Symfony\Contracts\Cache\CacheInterface` implementations instead + * deprecated `SimpleCacheAdapter`, use `Psr16Adapter` instead + +4.2.0 +----- + + * added support for connecting to Redis clusters via DSN + * added support for configuring multiple Memcached servers via DSN + * added `MarshallerInterface` and `DefaultMarshaller` to allow changing the serializer and provide one that automatically uses igbinary when available + * implemented `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache + * added sub-second expiry accuracy for backends that support it + * added support for phpredis 4 `compression` and `tcp_keepalive` options + * added automatic table creation when using Doctrine DBAL with PDO-based backends + * throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool + * deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead + * deprecated the `AbstractAdapter::unserialize()` and `AbstractCache::unserialize()` methods + * added `CacheCollectorPass` (originally in `FrameworkBundle`) + * added `CachePoolClearerPass` (originally in `FrameworkBundle`) + * added `CachePoolPass` (originally in `FrameworkBundle`) + * added `CachePoolPrunerPass` (originally in `FrameworkBundle`) + 3.4.0 ----- @@ -13,7 +50,7 @@ CHANGELOG 3.3.0 ----- - * [EXPERIMENTAL] added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any + * added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any * added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters * added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16 * added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16) diff --git a/vendor/symfony/cache/CacheItem.php b/vendor/symfony/cache/CacheItem.php index 7ae6568c..4dd6fd7c 100644 --- a/vendor/symfony/cache/CacheItem.php +++ b/vendor/symfony/cache/CacheItem.php @@ -11,34 +11,40 @@ namespace Symfony\Component\Cache; -use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Contracts\Cache\ItemInterface; /** * @author Nicolas Grekas */ -final class CacheItem implements CacheItemInterface +final class CacheItem implements ItemInterface { + private const METADATA_EXPIRY_OFFSET = 1527506807; + protected $key; protected $value; protected $isHit = false; protected $expiry; - protected $tags = []; - protected $prevTags = []; + protected $metadata = []; + protected $newMetadata = []; protected $innerItem; protected $poolHash; + protected $isTaggable = false; /** * {@inheritdoc} */ - public function getKey() + public function getKey(): string { return $this->key; } /** * {@inheritdoc} + * + * @return mixed */ public function get() { @@ -48,7 +54,7 @@ public function get() /** * {@inheritdoc} */ - public function isHit() + public function isHit(): bool { return $this->isHit; } @@ -58,7 +64,7 @@ public function isHit() * * @return $this */ - public function set($value) + public function set($value): self { $this->value = $value; @@ -70,12 +76,12 @@ public function set($value) * * @return $this */ - public function expiresAt($expiration) + public function expiresAt($expiration): self { if (null === $expiration) { $this->expiry = null; } elseif ($expiration instanceof \DateTimeInterface) { - $this->expiry = (int) $expiration->format('U'); + $this->expiry = (float) $expiration->format('U.u'); } else { throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given.', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration))); } @@ -88,14 +94,14 @@ public function expiresAt($expiration) * * @return $this */ - public function expiresAfter($time) + public function expiresAfter($time): self { if (null === $time) { $this->expiry = null; } elseif ($time instanceof \DateInterval) { - $this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U'); + $this->expiry = microtime(true) + \DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); } elseif (\is_int($time)) { - $this->expiry = $time + time(); + $this->expiry = $time + microtime(true); } else { throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($time) ? \get_class($time) : \gettype($time))); } @@ -104,58 +110,64 @@ public function expiresAfter($time) } /** - * Adds a tag to a cache item. - * - * @param string|string[] $tags A tag or array of tags - * - * @return $this - * - * @throws InvalidArgumentException When $tag is not valid + * {@inheritdoc} */ - public function tag($tags) + public function tag($tags): ItemInterface { - if (!\is_array($tags)) { + if (!$this->isTaggable) { + throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key)); + } + if (!is_iterable($tags)) { $tags = [$tags]; } foreach ($tags as $tag) { - if (!\is_string($tag)) { - throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag))); + if (!\is_string($tag) && !(\is_object($tag) && method_exists($tag, '__toString'))) { + throw new InvalidArgumentException(sprintf('Cache tag must be string or object that implements __toString(), "%s" given.', \is_object($tag) ? \get_class($tag) : \gettype($tag))); } - if (isset($this->tags[$tag])) { + $tag = (string) $tag; + if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) { continue; } if ('' === $tag) { throw new InvalidArgumentException('Cache tag length must be greater than zero.'); } - if (false !== strpbrk($tag, '{}()/\@:')) { - throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:.', $tag)); + if (false !== strpbrk($tag, self::RESERVED_CHARACTERS)) { + throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters "%s".', $tag, self::RESERVED_CHARACTERS)); } - $this->tags[$tag] = $tag; + $this->newMetadata[self::METADATA_TAGS][$tag] = $tag; } return $this; } + /** + * {@inheritdoc} + */ + public function getMetadata(): array + { + return $this->metadata; + } + /** * Returns the list of tags bound to the value coming from the pool storage if any. * - * @return array + * @deprecated since Symfony 4.2, use the "getMetadata()" method instead. */ - public function getPreviousTags() + public function getPreviousTags(): array { - return $this->prevTags; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "getMetadata()" method instead.', __METHOD__), \E_USER_DEPRECATED); + + return $this->metadata[self::METADATA_TAGS] ?? []; } /** * Validates a cache key according to PSR-6. * - * @param string $key The key to validate - * - * @return string + * @param mixed $key The key to validate * * @throws InvalidArgumentException When $key is not valid */ - public static function validateKey($key) + public static function validateKey($key): string { if (!\is_string($key)) { throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); @@ -163,8 +175,8 @@ public static function validateKey($key) if ('' === $key) { throw new InvalidArgumentException('Cache key length must be greater than zero.'); } - if (false !== strpbrk($key, '{}()/\@:')) { - throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:.', $key)); + if (false !== strpbrk($key, self::RESERVED_CHARACTERS)) { + throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS)); } return $key; @@ -175,14 +187,14 @@ public static function validateKey($key) * * @internal */ - public static function log(LoggerInterface $logger = null, $message, $context = []) + public static function log(?LoggerInterface $logger, string $message, array $context = []) { if ($logger) { $logger->warning($message, $context); } else { $replace = []; foreach ($context as $k => $v) { - if (is_scalar($v)) { + if (\is_scalar($v)) { $replace['{'.$k.'}'] = $v; } } diff --git a/vendor/symfony/cache/DataCollector/CacheDataCollector.php b/vendor/symfony/cache/DataCollector/CacheDataCollector.php index c9e87d5c..9bcd5b06 100644 --- a/vendor/symfony/cache/DataCollector/CacheDataCollector.php +++ b/vendor/symfony/cache/DataCollector/CacheDataCollector.php @@ -21,6 +21,8 @@ /** * @author Aaron Scherer * @author Tobias Nyholm + * + * @final since Symfony 4.4 */ class CacheDataCollector extends DataCollector implements LateDataCollectorInterface { @@ -39,8 +41,10 @@ public function addInstance($name, TraceableAdapter $instance) /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { $empty = ['calls' => [], 'config' => [], 'options' => [], 'statistics' => []]; $this->data = ['instances' => $empty, 'total' => $empty]; @@ -62,7 +66,7 @@ public function reset() public function lateCollect() { - $this->data = $this->cloneVar($this->data); + $this->data['instances']['calls'] = $this->cloneVar($this->data['instances']['calls']); } /** @@ -103,10 +107,7 @@ public function getCalls() return $this->data['instances']['calls']; } - /** - * @return array - */ - private function calculateStatistics() + private function calculateStatistics(): array { $statistics = []; foreach ($this->data['instances']['calls'] as $name => $calls) { @@ -123,7 +124,15 @@ private function calculateStatistics() foreach ($calls as $call) { ++$statistics[$name]['calls']; $statistics[$name]['time'] += $call->end - $call->start; - if ('getItem' === $call->name) { + if ('get' === $call->name) { + ++$statistics[$name]['reads']; + if ($call->hits) { + ++$statistics[$name]['hits']; + } else { + ++$statistics[$name]['misses']; + ++$statistics[$name]['writes']; + } + } elseif ('getItem' === $call->name) { ++$statistics[$name]['reads']; if ($call->hits) { ++$statistics[$name]['hits']; @@ -157,10 +166,7 @@ private function calculateStatistics() return $statistics; } - /** - * @return array - */ - private function calculateTotalStatistics() + private function calculateTotalStatistics(): array { $statistics = $this->getStatistics(); $totals = [ diff --git a/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php new file mode 100644 index 00000000..6bbab9da --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; +use Symfony\Component\Cache\Adapter\TraceableAdapter; +use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Inject a data collector to all the cache services to be able to get detailed statistics. + * + * @author Tobias Nyholm + */ +class CacheCollectorPass implements CompilerPassInterface +{ + private $dataCollectorCacheId; + private $cachePoolTag; + private $cachePoolRecorderInnerSuffix; + + public function __construct(string $dataCollectorCacheId = 'data_collector.cache', string $cachePoolTag = 'cache.pool', string $cachePoolRecorderInnerSuffix = '.recorder_inner') + { + $this->dataCollectorCacheId = $dataCollectorCacheId; + $this->cachePoolTag = $cachePoolTag; + $this->cachePoolRecorderInnerSuffix = $cachePoolRecorderInnerSuffix; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->dataCollectorCacheId)) { + return; + } + + foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $attributes) { + $poolName = $attributes[0]['name'] ?? $id; + + $this->addToCollector($id, $poolName, $container); + } + } + + private function addToCollector(string $id, string $name, ContainerBuilder $container) + { + $definition = $container->getDefinition($id); + if ($definition->isAbstract()) { + return; + } + + $collectorDefinition = $container->getDefinition($this->dataCollectorCacheId); + $recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class); + $recorder->setTags($definition->getTags()); + if (!$definition->isPublic() || !$definition->isPrivate()) { + $recorder->setPublic($definition->isPublic()); + } + $recorder->setArguments([new Reference($innerId = $id.$this->cachePoolRecorderInnerSuffix)]); + + $definition->setTags([]); + $definition->setPublic(false); + + $container->setDefinition($innerId, $definition); + $container->setDefinition($id, $recorder); + + // Tell the collector to add the new instance + $collectorDefinition->addMethodCall('addInstance', [$name, new Reference($id)]); + $collectorDefinition->setPublic(false); + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php new file mode 100644 index 00000000..3ca89a36 --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas + */ +class CachePoolClearerPass implements CompilerPassInterface +{ + private $cachePoolClearerTag; + + public function __construct(string $cachePoolClearerTag = 'cache.pool.clearer') + { + $this->cachePoolClearerTag = $cachePoolClearerTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $container->getParameterBag()->remove('cache.prefix.seed'); + + foreach ($container->findTaggedServiceIds($this->cachePoolClearerTag) as $id => $attr) { + $clearer = $container->getDefinition($id); + $pools = []; + foreach ($clearer->getArgument(0) as $name => $ref) { + if ($container->hasDefinition($ref)) { + $pools[$name] = new Reference($ref); + } + } + $clearer->replaceArgument(0, $pools); + } + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php new file mode 100644 index 00000000..c707ad9a --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\ChainAdapter; +use Symfony\Component\Cache\Adapter\NullAdapter; +use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas + */ +class CachePoolPass implements CompilerPassInterface +{ + private $cachePoolTag; + private $kernelResetTag; + private $cacheClearerId; + private $cachePoolClearerTag; + private $cacheSystemClearerId; + private $cacheSystemClearerTag; + + public function __construct(string $cachePoolTag = 'cache.pool', string $kernelResetTag = 'kernel.reset', string $cacheClearerId = 'cache.global_clearer', string $cachePoolClearerTag = 'cache.pool.clearer', string $cacheSystemClearerId = 'cache.system_clearer', string $cacheSystemClearerTag = 'kernel.cache_clearer') + { + $this->cachePoolTag = $cachePoolTag; + $this->kernelResetTag = $kernelResetTag; + $this->cacheClearerId = $cacheClearerId; + $this->cachePoolClearerTag = $cachePoolClearerTag; + $this->cacheSystemClearerId = $cacheSystemClearerId; + $this->cacheSystemClearerTag = $cacheSystemClearerTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if ($container->hasParameter('cache.prefix.seed')) { + $seed = '.'.$container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed')); + } else { + $seed = '_'.$container->getParameter('kernel.project_dir'); + } + $seed .= '.'.$container->getParameter('kernel.container_class'); + + $allPools = []; + $clearers = []; + $attributes = [ + 'provider', + 'name', + 'namespace', + 'default_lifetime', + 'reset', + ]; + foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) { + $adapter = $pool = $container->getDefinition($id); + if ($pool->isAbstract()) { + continue; + } + $class = $adapter->getClass(); + while ($adapter instanceof ChildDefinition) { + $adapter = $container->findDefinition($adapter->getParent()); + $class = $class ?: $adapter->getClass(); + if ($t = $adapter->getTag($this->cachePoolTag)) { + $tags[0] += $t[0]; + } + } + $name = $tags[0]['name'] ?? $id; + if (!isset($tags[0]['namespace'])) { + $namespaceSeed = $seed; + if (null !== $class) { + $namespaceSeed .= '.'.$class; + } + + $tags[0]['namespace'] = $this->getNamespace($namespaceSeed, $name); + } + if (isset($tags[0]['clearer'])) { + $clearer = $tags[0]['clearer']; + while ($container->hasAlias($clearer)) { + $clearer = (string) $container->getAlias($clearer); + } + } else { + $clearer = null; + } + unset($tags[0]['clearer'], $tags[0]['name']); + + if (isset($tags[0]['provider'])) { + $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider'])); + } + + if (ChainAdapter::class === $class) { + $adapters = []; + foreach ($adapter->getArgument(0) as $provider => $adapter) { + if ($adapter instanceof ChildDefinition) { + $chainedPool = $adapter; + } else { + $chainedPool = $adapter = new ChildDefinition($adapter); + } + + $chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]]; + $chainedClass = ''; + + while ($adapter instanceof ChildDefinition) { + $adapter = $container->findDefinition($adapter->getParent()); + $chainedClass = $chainedClass ?: $adapter->getClass(); + if ($t = $adapter->getTag($this->cachePoolTag)) { + $chainedTags[0] += $t[0]; + } + } + + if (ChainAdapter::class === $chainedClass) { + throw new InvalidArgumentException(sprintf('Invalid service "%s": chain of adapters cannot reference another chain, found "%s".', $id, $chainedPool->getParent())); + } + + $i = 0; + + if (isset($chainedTags[0]['provider'])) { + $chainedPool->replaceArgument($i++, new Reference(static::getServiceProvider($container, $chainedTags[0]['provider']))); + } + + if (isset($tags[0]['namespace']) && !\in_array($adapter->getClass(), [ArrayAdapter::class, NullAdapter::class], true)) { + $chainedPool->replaceArgument($i++, $tags[0]['namespace']); + } + + if (isset($tags[0]['default_lifetime'])) { + $chainedPool->replaceArgument($i++, $tags[0]['default_lifetime']); + } + + $adapters[] = $chainedPool; + } + + $pool->replaceArgument(0, $adapters); + unset($tags[0]['provider'], $tags[0]['namespace']); + $i = 1; + } else { + $i = 0; + } + + foreach ($attributes as $attr) { + if (!isset($tags[0][$attr])) { + // no-op + } elseif ('reset' === $attr) { + if ($tags[0][$attr]) { + $pool->addTag($this->kernelResetTag, ['method' => $tags[0][$attr]]); + } + } elseif ('namespace' !== $attr || !\in_array($class, [ArrayAdapter::class, NullAdapter::class], true)) { + $pool->replaceArgument($i++, $tags[0][$attr]); + } + unset($tags[0][$attr]); + } + if (!empty($tags[0])) { + throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime" and "reset", found "%s".', $this->cachePoolTag, $id, implode('", "', array_keys($tags[0])))); + } + + if (null !== $clearer) { + $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + + $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + + $notAliasedCacheClearerId = $this->cacheClearerId; + while ($container->hasAlias($this->cacheClearerId)) { + $this->cacheClearerId = (string) $container->getAlias($this->cacheClearerId); + } + if ($container->hasDefinition($this->cacheClearerId)) { + $clearers[$notAliasedCacheClearerId] = $allPools; + } + + foreach ($clearers as $id => $pools) { + $clearer = $container->getDefinition($id); + if ($clearer instanceof ChildDefinition) { + $clearer->replaceArgument(0, $pools); + } else { + $clearer->setArgument(0, $pools); + } + $clearer->addTag($this->cachePoolClearerTag); + + if ($this->cacheSystemClearerId === $id) { + $clearer->addTag($this->cacheSystemClearerTag); + } + } + + if ($container->hasDefinition('console.command.cache_pool_list')) { + $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($allPools)); + } + } + + private function getNamespace(string $seed, string $id) + { + return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$seed, true))), 0, 10); + } + + /** + * @internal + */ + public static function getServiceProvider(ContainerBuilder $container, $name) + { + $container->resolveEnvPlaceholders($name, null, $usedEnvs); + + if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) { + $dsn = $name; + + if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) { + $definition = new Definition(AbstractAdapter::class); + $definition->setPublic(false); + $definition->setFactory([AbstractAdapter::class, 'createConnection']); + $definition->setArguments([$dsn, ['lazy' => true]]); + $container->setDefinition($name, $definition); + } + } + + return $name; + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php new file mode 100644 index 00000000..e5699623 --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\DependencyInjection; + +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Rob Frawley 2nd + */ +class CachePoolPrunerPass implements CompilerPassInterface +{ + private $cacheCommandServiceId; + private $cachePoolTag; + + public function __construct(string $cacheCommandServiceId = 'console.command.cache_pool_prune', string $cachePoolTag = 'cache.pool') + { + $this->cacheCommandServiceId = $cacheCommandServiceId; + $this->cachePoolTag = $cachePoolTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->cacheCommandServiceId)) { + return; + } + + $services = []; + + foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) { + $class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass()); + + if (!$reflection = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + + if ($reflection->implementsInterface(PruneableInterface::class)) { + $services[$id] = new Reference($id); + } + } + + $container->getDefinition($this->cacheCommandServiceId)->replaceArgument(0, new IteratorArgument($services)); + } +} diff --git a/vendor/symfony/cache/DoctrineProvider.php b/vendor/symfony/cache/DoctrineProvider.php index 4c5cd0cb..f6ac5745 100644 --- a/vendor/symfony/cache/DoctrineProvider.php +++ b/vendor/symfony/cache/DoctrineProvider.php @@ -13,6 +13,11 @@ use Doctrine\Common\Cache\CacheProvider; use Psr\Cache\CacheItemPoolInterface; +use Symfony\Contracts\Service\ResetInterface; + +if (!class_exists(CacheProvider::class)) { + return; +} /** * @author Nicolas Grekas @@ -39,7 +44,7 @@ public function prune() */ public function reset() { - if ($this->pool instanceof ResettableInterface) { + if ($this->pool instanceof ResetInterface) { $this->pool->reset(); } $this->setNamespace($this->getNamespace()); @@ -47,6 +52,8 @@ public function reset() /** * {@inheritdoc} + * + * @return mixed */ protected function doFetch($id) { @@ -57,6 +64,8 @@ protected function doFetch($id) /** * {@inheritdoc} + * + * @return bool */ protected function doContains($id) { @@ -65,6 +74,8 @@ protected function doContains($id) /** * {@inheritdoc} + * + * @return bool */ protected function doSave($id, $data, $lifeTime = 0) { @@ -79,6 +90,8 @@ protected function doSave($id, $data, $lifeTime = 0) /** * {@inheritdoc} + * + * @return bool */ protected function doDelete($id) { @@ -87,6 +100,8 @@ protected function doDelete($id) /** * {@inheritdoc} + * + * @return bool */ protected function doFlush() { @@ -95,6 +110,8 @@ protected function doFlush() /** * {@inheritdoc} + * + * @return array|null */ protected function doGetStats() { diff --git a/vendor/symfony/cache/Exception/CacheException.php b/vendor/symfony/cache/Exception/CacheException.php index e87b2db8..d2e975b2 100644 --- a/vendor/symfony/cache/Exception/CacheException.php +++ b/vendor/symfony/cache/Exception/CacheException.php @@ -14,6 +14,12 @@ use Psr\Cache\CacheException as Psr6CacheInterface; use Psr\SimpleCache\CacheException as SimpleCacheInterface; -class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface -{ +if (interface_exists(SimpleCacheInterface::class)) { + class CacheException extends \Exception implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class CacheException extends \Exception implements Psr6CacheInterface + { + } } diff --git a/vendor/symfony/cache/Exception/InvalidArgumentException.php b/vendor/symfony/cache/Exception/InvalidArgumentException.php index 828bf3ed..7f9584a2 100644 --- a/vendor/symfony/cache/Exception/InvalidArgumentException.php +++ b/vendor/symfony/cache/Exception/InvalidArgumentException.php @@ -14,6 +14,12 @@ use Psr\Cache\InvalidArgumentException as Psr6CacheInterface; use Psr\SimpleCache\InvalidArgumentException as SimpleCacheInterface; -class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface -{ +if (interface_exists(SimpleCacheInterface::class)) { + class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class InvalidArgumentException extends \InvalidArgumentException implements Psr6CacheInterface + { + } } diff --git a/vendor/symfony/cache/Exception/LogicException.php b/vendor/symfony/cache/Exception/LogicException.php new file mode 100644 index 00000000..9ffa7ed6 --- /dev/null +++ b/vendor/symfony/cache/Exception/LogicException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Exception; + +use Psr\Cache\CacheException as Psr6CacheInterface; +use Psr\SimpleCache\CacheException as SimpleCacheInterface; + +if (interface_exists(SimpleCacheInterface::class)) { + class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface + { + } +} else { + class LogicException extends \LogicException implements Psr6CacheInterface + { + } +} diff --git a/vendor/symfony/cache/LICENSE b/vendor/symfony/cache/LICENSE index a7ec7080..7fa95390 100644 --- a/vendor/symfony/cache/LICENSE +++ b/vendor/symfony/cache/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2020 Fabien Potencier +Copyright (c) 2016-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/cache/LockRegistry.php b/vendor/symfony/cache/LockRegistry.php new file mode 100644 index 00000000..26574f10 --- /dev/null +++ b/vendor/symfony/cache/LockRegistry.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Psr\Log\LoggerInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * LockRegistry is used internally by existing adapters to protect against cache stampede. + * + * It does so by wrapping the computation of items in a pool of locks. + * Foreach each apps, there can be at most 20 concurrent processes that + * compute items at the same time and only one per cache-key. + * + * @author Nicolas Grekas + */ +final class LockRegistry +{ + private static $openedFiles = []; + private static $lockedFiles; + private static $signalingException; + private static $signalingCallback; + + /** + * The number of items in this list controls the max number of concurrent processes. + */ + private static $files = [ + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractTagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AdapterInterface.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ApcuAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ArrayAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ChainAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'DoctrineAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'FilesystemTagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'MemcachedAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'NullAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PdoAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpArrayAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'PhpFilesAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'ProxyAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'Psr16Adapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'RedisTagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'SimpleCacheAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableTagAwareAdapter.php', + ]; + + /** + * Defines a set of existing files that will be used as keys to acquire locks. + * + * @return array The previously defined set of files + */ + public static function setFiles(array $files): array + { + $previousFiles = self::$files; + self::$files = $files; + + foreach (self::$openedFiles as $file) { + if ($file) { + flock($file, \LOCK_UN); + fclose($file); + } + } + self::$openedFiles = self::$lockedFiles = []; + + return $previousFiles; + } + + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null) + { + if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) { + // disable locking on Windows by default + self::$files = self::$lockedFiles = []; + } + + $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1; + + if ($key < 0 || self::$lockedFiles || !$lock = self::open($key)) { + return $callback($item, $save); + } + + self::$signalingException ?? self::$signalingException = unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}"); + self::$signalingCallback ?? self::$signalingCallback = function () { throw self::$signalingException; }; + + while (true) { + try { + // race to get the lock in non-blocking mode + $locked = flock($lock, \LOCK_EX | \LOCK_NB, $wouldBlock); + + if ($locked || !$wouldBlock) { + $logger && $logger->info(sprintf('Lock %s, now computing item "{key}"', $locked ? 'acquired' : 'not supported'), ['key' => $item->getKey()]); + self::$lockedFiles[$key] = true; + + $value = $callback($item, $save); + + if ($save) { + if ($setMetadata) { + $setMetadata($item); + } + + $pool->save($item->set($value)); + $save = false; + } + + return $value; + } + // if we failed the race, retry locking in blocking mode to wait for the winner + $logger && $logger->info('Item "{key}" is locked, waiting for it to be released', ['key' => $item->getKey()]); + flock($lock, \LOCK_SH); + } finally { + flock($lock, \LOCK_UN); + unset(self::$lockedFiles[$key]); + } + + try { + $value = $pool->get($item->getKey(), self::$signalingCallback, 0); + $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]); + $save = false; + + return $value; + } catch (\Exception $e) { + if (self::$signalingException !== $e) { + throw $e; + } + $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]); + } + } + + return null; + } + + private static function open(int $key) + { + if (null !== $h = self::$openedFiles[$key] ?? null) { + return $h; + } + set_error_handler(function () {}); + try { + $h = fopen(self::$files[$key], 'r+'); + } finally { + restore_error_handler(); + } + + return self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r'); + } +} diff --git a/vendor/symfony/cache/Marshaller/DefaultMarshaller.php b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php new file mode 100644 index 00000000..7493a2ef --- /dev/null +++ b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +use Symfony\Component\Cache\Exception\CacheException; + +/** + * Serializes/unserializes values using igbinary_serialize() if available, serialize() otherwise. + * + * @author Nicolas Grekas + */ +class DefaultMarshaller implements MarshallerInterface +{ + private $useIgbinarySerialize = true; + + public function __construct(bool $useIgbinarySerialize = null) + { + if (null === $useIgbinarySerialize) { + $useIgbinarySerialize = \extension_loaded('igbinary') && (\PHP_VERSION_ID < 70400 || version_compare('3.1.6', phpversion('igbinary'), '<=')); + } elseif ($useIgbinarySerialize && (!\extension_loaded('igbinary') || (\PHP_VERSION_ID >= 70400 && version_compare('3.1.6', phpversion('igbinary'), '>')))) { + throw new CacheException(\extension_loaded('igbinary') && \PHP_VERSION_ID >= 70400 ? 'Please upgrade the "igbinary" PHP extension to v3.1.6 or higher.' : 'The "igbinary" PHP extension is not loaded.'); + } + $this->useIgbinarySerialize = $useIgbinarySerialize; + } + + /** + * {@inheritdoc} + */ + public function marshall(array $values, ?array &$failed): array + { + $serialized = $failed = []; + + foreach ($values as $id => $value) { + try { + if ($this->useIgbinarySerialize) { + $serialized[$id] = igbinary_serialize($value); + } else { + $serialized[$id] = serialize($value); + } + } catch (\Exception $e) { + $failed[] = $id; + } + } + + return $serialized; + } + + /** + * {@inheritdoc} + */ + public function unmarshall(string $value) + { + if ('b:0;' === $value) { + return false; + } + if ('N;' === $value) { + return null; + } + static $igbinaryNull; + if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) { + return null; + } + $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); + try { + if (':' === ($value[1] ?? ':')) { + if (false !== $value = unserialize($value)) { + return $value; + } + } elseif (false === $igbinaryNull) { + throw new \RuntimeException('Failed to unserialize values, did you forget to install the "igbinary" extension?'); + } elseif (null !== $value = igbinary_unserialize($value)) { + return $value; + } + + throw new \DomainException(error_get_last() ? error_get_last()['message'] : 'Failed to unserialize values.'); + } catch (\Error $e) { + throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine()); + } finally { + ini_set('unserialize_callback_func', $unserializeCallbackHandler); + } + } + + /** + * @internal + */ + public static function handleUnserializeCallback($class) + { + throw new \DomainException('Class not found: '.$class); + } +} diff --git a/vendor/symfony/cache/Marshaller/DeflateMarshaller.php b/vendor/symfony/cache/Marshaller/DeflateMarshaller.php new file mode 100644 index 00000000..55448061 --- /dev/null +++ b/vendor/symfony/cache/Marshaller/DeflateMarshaller.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +use Symfony\Component\Cache\Exception\CacheException; + +/** + * Compresses values using gzdeflate(). + * + * @author Nicolas Grekas + */ +class DeflateMarshaller implements MarshallerInterface +{ + private $marshaller; + + public function __construct(MarshallerInterface $marshaller) + { + if (!\function_exists('gzdeflate')) { + throw new CacheException('The "zlib" PHP extension is not loaded.'); + } + + $this->marshaller = $marshaller; + } + + /** + * {@inheritdoc} + */ + public function marshall(array $values, ?array &$failed): array + { + return array_map('gzdeflate', $this->marshaller->marshall($values, $failed)); + } + + /** + * {@inheritdoc} + */ + public function unmarshall(string $value) + { + if (false !== $inflatedValue = @gzinflate($value)) { + $value = $inflatedValue; + } + + return $this->marshaller->unmarshall($value); + } +} diff --git a/vendor/symfony/cache/Marshaller/MarshallerInterface.php b/vendor/symfony/cache/Marshaller/MarshallerInterface.php new file mode 100644 index 00000000..cdd6c402 --- /dev/null +++ b/vendor/symfony/cache/Marshaller/MarshallerInterface.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +/** + * Serializes/unserializes PHP values. + * + * Implementations of this interface MUST deal with errors carefully. They MUST + * also deal with forward and backward compatibility at the storage format level. + * + * @author Nicolas Grekas + */ +interface MarshallerInterface +{ + /** + * Serializes a list of values. + * + * When serialization fails for a specific value, no exception should be + * thrown. Instead, its key should be listed in $failed. + */ + public function marshall(array $values, ?array &$failed): array; + + /** + * Unserializes a single value and throws an exception if anything goes wrong. + * + * @return mixed + * + * @throws \Exception Whenever unserialization fails + */ + public function unmarshall(string $value); +} diff --git a/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php b/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php new file mode 100644 index 00000000..5d1e303b --- /dev/null +++ b/vendor/symfony/cache/Marshaller/TagAwareMarshaller.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Marshaller; + +/** + * A marshaller optimized for data structures generated by AbstractTagAwareAdapter. + * + * @author Nicolas Grekas + */ +class TagAwareMarshaller implements MarshallerInterface +{ + private $marshaller; + + public function __construct(MarshallerInterface $marshaller = null) + { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); + } + + /** + * {@inheritdoc} + */ + public function marshall(array $values, ?array &$failed): array + { + $failed = $notSerialized = $serialized = []; + + foreach ($values as $id => $value) { + if (\is_array($value) && \is_array($value['tags'] ?? null) && \array_key_exists('value', $value) && \count($value) === 2 + (\is_string($value['meta'] ?? null) && 8 === \strlen($value['meta']))) { + // if the value is an array with keys "tags", "value" and "meta", use a compact serialization format + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F allow detecting this format quickly in unmarshall() + + $v = $this->marshaller->marshall($value, $f); + + if ($f) { + $f = []; + $failed[] = $id; + } else { + if ([] === $value['tags']) { + $v['tags'] = ''; + } + + $serialized[$id] = "\x9D".($value['meta'] ?? "\0\0\0\0\0\0\0\0").pack('N', \strlen($v['tags'])).$v['tags'].$v['value']; + $serialized[$id][9] = "\x5F"; + } + } else { + // other arbitratry values are serialized using the decorated marshaller below + $notSerialized[$id] = $value; + } + } + + if ($notSerialized) { + $serialized += $this->marshaller->marshall($notSerialized, $f); + $failed = array_merge($failed, $f); + } + + return $serialized; + } + + /** + * {@inheritdoc} + */ + public function unmarshall(string $value) + { + // detect the compact format used in marshall() using magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (13 >= \strlen($value) || "\x9D" !== $value[0] || "\0" !== $value[5] || "\x5F" !== $value[9]) { + return $this->marshaller->unmarshall($value); + } + + // data consists of value, tags and metadata which we need to unpack + $meta = substr($value, 1, 12); + $meta[8] = "\0"; + $tagLen = unpack('Nlen', $meta, 8)['len']; + $meta = substr($meta, 0, 8); + + return [ + 'value' => $this->marshaller->unmarshall(substr($value, 13 + $tagLen)), + 'tags' => $tagLen ? $this->marshaller->unmarshall(substr($value, 13, $tagLen)) : [], + 'meta' => "\0\0\0\0\0\0\0\0" === $meta ? null : $meta, + ]; + } +} diff --git a/vendor/symfony/cache/Psr16Cache.php b/vendor/symfony/cache/Psr16Cache.php new file mode 100644 index 00000000..ac265a57 --- /dev/null +++ b/vendor/symfony/cache/Psr16Cache.php @@ -0,0 +1,284 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache; + +use Psr\Cache\CacheException as Psr6CacheException; +use Psr\Cache\CacheItemPoolInterface; +use Psr\SimpleCache\CacheException as SimpleCacheException; +use Psr\SimpleCache\CacheInterface; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Traits\ProxyTrait; + +if (null !== (new \ReflectionMethod(CacheInterface::class, 'get'))->getReturnType()) { + throw new \LogicException('psr/simple-cache 3.0+ is not compatible with this version of symfony/cache. Please upgrade symfony/cache to 6.0+ or downgrade psr/simple-cache to 1.x or 2.x.'); +} + +/** + * Turns a PSR-6 cache into a PSR-16 one. + * + * @author Nicolas Grekas + */ +class Psr16Cache implements CacheInterface, PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + private const METADATA_EXPIRY_OFFSET = 1527506807; + + private $createCacheItem; + private $cacheItemPrototype; + + public function __construct(CacheItemPoolInterface $pool) + { + $this->pool = $pool; + + if (!$pool instanceof AdapterInterface) { + return; + } + $cacheItemPrototype = &$this->cacheItemPrototype; + $createCacheItem = \Closure::bind( + static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) { + $item = clone $cacheItemPrototype; + $item->poolHash = $item->innerItem = null; + $item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key); + $item->value = $value; + $item->isHit = false; + + return $item; + }, + null, + CacheItem::class + ); + $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) { + if (null === $this->cacheItemPrototype) { + $this->get($allowInt && \is_int($key) ? (string) $key : $key); + } + $this->createCacheItem = $createCacheItem; + + return $createCacheItem($key, null, $allowInt)->set($value); + }; + } + + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get($key, $default = null) + { + try { + $item = $this->pool->getItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + if (null === $this->cacheItemPrototype) { + $this->cacheItemPrototype = clone $item; + $this->cacheItemPrototype->set(null); + } + + return $item->isHit() ? $item->get() : $default; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function set($key, $value, $ttl = null) + { + try { + if (null !== $f = $this->createCacheItem) { + $item = $f($key, $value); + } else { + $item = $this->pool->getItem($key)->set($value); + } + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + + return $this->pool->save($item); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function delete($key) + { + try { + return $this->pool->deleteItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function clear() + { + return $this->pool->clear(); + } + + /** + * {@inheritdoc} + * + * @return iterable + */ + public function getMultiple($keys, $default = null) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!\is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys))); + } + + try { + $items = $this->pool->getItems($keys); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $values = []; + + if (!$this->pool instanceof AdapterInterface) { + foreach ($items as $key => $item) { + $values[$key] = $item->isHit() ? $item->get() : $default; + } + + return $values; + } + + foreach ($items as $key => $item) { + if (!$item->isHit()) { + $values[$key] = $default; + continue; + } + $values[$key] = $item->get(); + + if (!$metadata = $item->getMetadata()) { + continue; + } + unset($metadata[CacheItem::METADATA_TAGS]); + + if ($metadata) { + $values[$key] = ["\x9D".pack('VN', (int) (0.1 + $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET), $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]]; + } + } + + return $values; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function setMultiple($values, $ttl = null) + { + $valuesIsArray = \is_array($values); + if (!$valuesIsArray && !$values instanceof \Traversable) { + throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', \is_object($values) ? \get_class($values) : \gettype($values))); + } + $items = []; + + try { + if (null !== $f = $this->createCacheItem) { + $valuesIsArray = false; + foreach ($values as $key => $value) { + $items[$key] = $f($key, $value, true); + } + } elseif ($valuesIsArray) { + $items = []; + foreach ($values as $key => $value) { + $items[] = (string) $key; + } + $items = $this->pool->getItems($items); + } else { + foreach ($values as $key => $value) { + if (\is_int($key)) { + $key = (string) $key; + } + $items[$key] = $this->pool->getItem($key)->set($value); + } + } + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + $ok = true; + + foreach ($items as $key => $item) { + if ($valuesIsArray) { + $item->set($values[$key]); + } + if (null !== $ttl) { + $item->expiresAfter($ttl); + } + $ok = $this->pool->saveDeferred($item) && $ok; + } + + return $this->pool->commit() && $ok; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function deleteMultiple($keys) + { + if ($keys instanceof \Traversable) { + $keys = iterator_to_array($keys, false); + } elseif (!\is_array($keys)) { + throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys))); + } + + try { + return $this->pool->deleteItems($keys); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function has($key) + { + try { + return $this->pool->hasItem($key); + } catch (SimpleCacheException $e) { + throw $e; + } catch (Psr6CacheException $e) { + throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); + } + } +} diff --git a/vendor/symfony/cache/README.md b/vendor/symfony/cache/README.md index c4ab7520..c466d578 100644 --- a/vendor/symfony/cache/README.md +++ b/vendor/symfony/cache/README.md @@ -1,18 +1,19 @@ Symfony PSR-6 implementation for caching ======================================== -This component provides an extended [PSR-6](http://www.php-fig.org/psr/psr-6/) -implementation for adding cache to your applications. It is designed to have a -low overhead so that caching is fastest. It ships with a few caching adapters -for the most widespread and suited to caching backends. It also provides a -`doctrine/cache` proxy adapter to cover more advanced caching needs and a proxy -adapter for greater interoperability between PSR-6 implementations. +The Cache component provides extended +[PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to +your applications. It is designed to have a low overhead so that caching is +fastest. It ships with adapters for the most widespread caching backends. +It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter, +and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)' +`CacheInterface` and `TagAwareCacheInterface`. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/cache.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Documentation](https://symfony.com/doc/current/components/cache.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/cache/ResettableInterface.php b/vendor/symfony/cache/ResettableInterface.php index 6be72861..7b0a853f 100644 --- a/vendor/symfony/cache/ResettableInterface.php +++ b/vendor/symfony/cache/ResettableInterface.php @@ -11,10 +11,11 @@ namespace Symfony\Component\Cache; +use Symfony\Contracts\Service\ResetInterface; + /** * Resets a pool's local state. */ -interface ResettableInterface +interface ResettableInterface extends ResetInterface { - public function reset(); } diff --git a/vendor/symfony/cache/Simple/AbstractCache.php b/vendor/symfony/cache/Simple/AbstractCache.php index baedb737..c3d8b38c 100644 --- a/vendor/symfony/cache/Simple/AbstractCache.php +++ b/vendor/symfony/cache/Simple/AbstractCache.php @@ -12,37 +12,37 @@ namespace Symfony\Component\Cache\Simple; use Psr\Log\LoggerAwareInterface; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\AbstractTrait; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', AbstractCache::class, AbstractAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); /** - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use AbstractAdapter and type-hint for CacheInterface instead. */ -abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, ResettableInterface +abstract class AbstractCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface { - /** - * @internal - */ - const NS_SEPARATOR = ':'; - use AbstractTrait { deleteItems as private; AbstractTrait::deleteItem as delete; AbstractTrait::hasItem as has; } - private $defaultLifetime; - /** - * @param string $namespace - * @param int $defaultLifetime + * @internal */ - protected function __construct($namespace = '', $defaultLifetime = 0) + protected const NS_SEPARATOR = ':'; + + private $defaultLifetime; + + protected function __construct(string $namespace = '', int $defaultLifetime = 0) { - $this->defaultLifetime = max(0, (int) $defaultLifetime); + $this->defaultLifetime = max(0, $defaultLifetime); $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s").', $this->maxIdLength - 24, \strlen($namespace), $namespace)); @@ -61,7 +61,7 @@ public function get($key, $default = null) return $value; } } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch key "{key}"', ['key' => $key, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); } return $default; @@ -69,6 +69,8 @@ public function get($key, $default = null) /** * {@inheritdoc} + * + * @return bool */ public function set($key, $value, $ttl = null) { @@ -79,6 +81,8 @@ public function set($key, $value, $ttl = null) /** * {@inheritdoc} + * + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -95,7 +99,7 @@ public function getMultiple($keys, $default = null) try { $values = $this->doFetch($ids); } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => $keys, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]); $values = []; } $ids = array_combine($ids, $keys); @@ -105,6 +109,8 @@ public function getMultiple($keys, $default = null) /** * {@inheritdoc} + * + * @return bool */ public function setMultiple($values, $ttl = null) { @@ -134,13 +140,16 @@ public function setMultiple($values, $ttl = null) foreach (\is_array($e) ? $e : array_keys($valuesById) as $id) { $keys[] = substr($id, \strlen($this->namespace)); } - CacheItem::log($this->logger, 'Failed to save values', ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]); + $message = 'Failed to save values'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['keys' => $keys, 'exception' => $e instanceof \Exception ? $e : null]); return false; } /** * {@inheritdoc} + * + * @return bool */ public function deleteMultiple($keys) { @@ -168,19 +177,19 @@ private function normalizeTtl($ttl) throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given.', \is_object($ttl) ? \get_class($ttl) : \gettype($ttl))); } - private function generateValues($values, &$keys, $default) + private function generateValues(iterable $values, array &$keys, $default): iterable { try { foreach ($values as $id => $value) { if (!isset($keys[$id])) { - $id = key($keys); + throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys))); } $key = $keys[$id]; unset($keys[$id]); yield $key => $value; } } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to fetch requested values', ['keys' => array_values($keys), 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to fetch values: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]); } foreach ($keys as $key) { diff --git a/vendor/symfony/cache/Simple/ApcuCache.php b/vendor/symfony/cache/Simple/ApcuCache.php index e583b443..bef89e27 100644 --- a/vendor/symfony/cache/Simple/ApcuCache.php +++ b/vendor/symfony/cache/Simple/ApcuCache.php @@ -11,18 +11,20 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\ApcuAdapter; use Symfony\Component\Cache\Traits\ApcuTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ApcuCache::class, ApcuAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use ApcuAdapter and type-hint for CacheInterface instead. + */ class ApcuCache extends AbstractCache { use ApcuTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $version - */ - public function __construct($namespace = '', $defaultLifetime = 0, $version = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null) { $this->init($namespace, $defaultLifetime, $version); } diff --git a/vendor/symfony/cache/Simple/ArrayCache.php b/vendor/symfony/cache/Simple/ArrayCache.php index 6013f0ad..469edf1c 100644 --- a/vendor/symfony/cache/Simple/ArrayCache.php +++ b/vendor/symfony/cache/Simple/ArrayCache.php @@ -12,16 +12,20 @@ namespace Symfony\Component\Cache\Simple; use Psr\Log\LoggerAwareInterface; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\ArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ArrayCache::class, ArrayAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); /** - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use ArrayAdapter and type-hint for CacheInterface instead. */ -class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInterface +class ArrayCache implements Psr16CacheInterface, LoggerAwareInterface, ResettableInterface { use ArrayTrait { ArrayTrait::deleteItem as delete; @@ -31,12 +35,11 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte private $defaultLifetime; /** - * @param int $defaultLifetime * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise */ - public function __construct($defaultLifetime = 0, $storeSerialized = true) + public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true) { - $this->defaultLifetime = (int) $defaultLifetime; + $this->defaultLifetime = $defaultLifetime; $this->storeSerialized = $storeSerialized; } @@ -45,13 +48,26 @@ public function __construct($defaultLifetime = 0, $storeSerialized = true) */ public function get($key, $default = null) { - foreach ($this->getMultiple([$key], $default) as $v) { - return $v; + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } + if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > microtime(true) || !$this->delete($key))) { + $this->values[$key] = null; + + return $default; } + if (!$this->storeSerialized) { + return $this->values[$key]; + } + $value = $this->unfreeze($key, $isHit); + + return $isHit ? $value : $default; } /** * {@inheritdoc} + * + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -61,14 +77,18 @@ public function getMultiple($keys, $default = null) throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys))); } foreach ($keys as $key) { - CacheItem::validateKey($key); + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } } - return $this->generateItems($keys, time(), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; }); + return $this->generateItems($keys, microtime(true), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; }); } /** * {@inheritdoc} + * + * @return bool */ public function deleteMultiple($keys) { @@ -84,16 +104,22 @@ public function deleteMultiple($keys) /** * {@inheritdoc} + * + * @return bool */ public function set($key, $value, $ttl = null) { - CacheItem::validateKey($key); + if (!\is_string($key)) { + CacheItem::validateKey($key); + } return $this->setMultiple([$key => $value], $ttl); } /** * {@inheritdoc} + * + * @return bool */ public function setMultiple($values, $ttl = null) { @@ -103,27 +129,20 @@ public function setMultiple($values, $ttl = null) $valuesArray = []; foreach ($values as $key => $value) { - \is_int($key) || CacheItem::validateKey($key); + if (!\is_int($key) && !(\is_string($key) && isset($this->expiries[$key]))) { + CacheItem::validateKey($key); + } $valuesArray[$key] = $value; } if (false === $ttl = $this->normalizeTtl($ttl)) { return $this->deleteMultiple(array_keys($valuesArray)); } - if ($this->storeSerialized) { - foreach ($valuesArray as $key => $value) { - try { - $valuesArray[$key] = serialize($value); - } catch (\Exception $e) { - $type = \is_object($value) ? \get_class($value) : \gettype($value); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', ['key' => $key, 'type' => $type, 'exception' => $e]); - - return false; - } - } - } - $expiry = 0 < $ttl ? time() + $ttl : \PHP_INT_MAX; + $expiry = 0 < $ttl ? microtime(true) + $ttl : \PHP_INT_MAX; foreach ($valuesArray as $key => $value) { + if ($this->storeSerialized && null === $value = $this->freeze($value, $key)) { + return false; + } $this->values[$key] = $value; $this->expiries[$key] = $expiry; } diff --git a/vendor/symfony/cache/Simple/ChainCache.php b/vendor/symfony/cache/Simple/ChainCache.php index 2e6c7277..bae95072 100644 --- a/vendor/symfony/cache/Simple/ChainCache.php +++ b/vendor/symfony/cache/Simple/ChainCache.php @@ -11,10 +11,15 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\ChainAdapter; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', ChainCache::class, ChainAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); /** * Chains several caches together. @@ -22,9 +27,9 @@ * Cached items are fetched from the first cache having them in its data store. * They are saved and deleted in all caches at once. * - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use ChainAdapter and type-hint for CacheInterface instead. */ -class ChainCache implements CacheInterface, PruneableInterface, ResettableInterface +class ChainCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface { private $miss; private $caches = []; @@ -32,25 +37,25 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf private $cacheCount; /** - * @param CacheInterface[] $caches The ordered list of caches used to fetch cached items - * @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones + * @param Psr16CacheInterface[] $caches The ordered list of caches used to fetch cached items + * @param int $defaultLifetime The lifetime of items propagated from lower caches to upper ones */ - public function __construct(array $caches, $defaultLifetime = 0) + public function __construct(array $caches, int $defaultLifetime = 0) { if (!$caches) { throw new InvalidArgumentException('At least one cache must be specified.'); } foreach ($caches as $cache) { - if (!$cache instanceof CacheInterface) { - throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), CacheInterface::class)); + if (!$cache instanceof Psr16CacheInterface) { + throw new InvalidArgumentException(sprintf('The class "%s" does not implement the "%s" interface.', \get_class($cache), Psr16CacheInterface::class)); } } $this->miss = new \stdClass(); $this->caches = array_values($caches); $this->cacheCount = \count($this->caches); - $this->defaultLifetime = 0 < $defaultLifetime ? (int) $defaultLifetime : null; + $this->defaultLifetime = 0 < $defaultLifetime ? $defaultLifetime : null; } /** @@ -77,6 +82,8 @@ public function get($key, $default = null) /** * {@inheritdoc} + * + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -85,11 +92,11 @@ public function getMultiple($keys, $default = null) return $this->generateItems($this->caches[0]->getMultiple($keys, $miss), 0, $miss, $default); } - private function generateItems($values, $cacheIndex, $miss, $default) + private function generateItems(iterable $values, int $cacheIndex, $miss, $default): iterable { $missing = []; $nextCacheIndex = $cacheIndex + 1; - $nextCache = isset($this->caches[$nextCacheIndex]) ? $this->caches[$nextCacheIndex] : null; + $nextCache = $this->caches[$nextCacheIndex] ?? null; foreach ($values as $k => $value) { if ($miss !== $value) { @@ -118,6 +125,8 @@ private function generateItems($values, $cacheIndex, $miss, $default) /** * {@inheritdoc} + * + * @return bool */ public function has($key) { @@ -132,6 +141,8 @@ public function has($key) /** * {@inheritdoc} + * + * @return bool */ public function clear() { @@ -147,6 +158,8 @@ public function clear() /** * {@inheritdoc} + * + * @return bool */ public function delete($key) { @@ -162,6 +175,8 @@ public function delete($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteMultiple($keys) { @@ -180,6 +195,8 @@ public function deleteMultiple($keys) /** * {@inheritdoc} + * + * @return bool */ public function set($key, $value, $ttl = null) { @@ -195,6 +212,8 @@ public function set($key, $value, $ttl = null) /** * {@inheritdoc} + * + * @return bool */ public function setMultiple($values, $ttl = null) { @@ -244,7 +263,7 @@ public function prune() public function reset() { foreach ($this->caches as $cache) { - if ($cache instanceof ResettableInterface) { + if ($cache instanceof ResetInterface) { $cache->reset(); } } diff --git a/vendor/symfony/cache/Simple/DoctrineCache.php b/vendor/symfony/cache/Simple/DoctrineCache.php index ea1a4eda..d7feb4d3 100644 --- a/vendor/symfony/cache/Simple/DoctrineCache.php +++ b/vendor/symfony/cache/Simple/DoctrineCache.php @@ -12,17 +12,20 @@ namespace Symfony\Component\Cache\Simple; use Doctrine\Common\Cache\CacheProvider; +use Symfony\Component\Cache\Adapter\DoctrineAdapter; use Symfony\Component\Cache\Traits\DoctrineTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', DoctrineCache::class, DoctrineAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use DoctrineAdapter and type-hint for CacheInterface instead. + */ class DoctrineCache extends AbstractCache { use DoctrineTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0) { parent::__construct('', $defaultLifetime); $this->provider = $provider; diff --git a/vendor/symfony/cache/Simple/FilesystemCache.php b/vendor/symfony/cache/Simple/FilesystemCache.php index ccd57953..fcc8a170 100644 --- a/vendor/symfony/cache/Simple/FilesystemCache.php +++ b/vendor/symfony/cache/Simple/FilesystemCache.php @@ -11,20 +11,25 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\FilesystemTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', FilesystemCache::class, FilesystemAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use FilesystemAdapter and type-hint for CacheInterface instead. + */ class FilesystemCache extends AbstractCache implements PruneableInterface { use FilesystemTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory - */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); } diff --git a/vendor/symfony/cache/Simple/MemcachedCache.php b/vendor/symfony/cache/Simple/MemcachedCache.php index 94a9f297..1f636486 100644 --- a/vendor/symfony/cache/Simple/MemcachedCache.php +++ b/vendor/symfony/cache/Simple/MemcachedCache.php @@ -11,20 +11,24 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\MemcachedAdapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\MemcachedTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', MemcachedCache::class, MemcachedAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use MemcachedAdapter and type-hint for CacheInterface instead. + */ class MemcachedCache extends AbstractCache { use MemcachedTrait; protected $maxIdLength = 250; - /** - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) + public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($client, $namespace, $defaultLifetime); + $this->init($client, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Simple/NullCache.php b/vendor/symfony/cache/Simple/NullCache.php index fa986aeb..fcbd39d5 100644 --- a/vendor/symfony/cache/Simple/NullCache.php +++ b/vendor/symfony/cache/Simple/NullCache.php @@ -11,12 +11,16 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\NullAdapter; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', NullCache::class, NullAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); /** - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use NullAdapter and type-hint for CacheInterface instead. */ -class NullCache implements CacheInterface +class NullCache implements Psr16CacheInterface { /** * {@inheritdoc} @@ -28,6 +32,8 @@ public function get($key, $default = null) /** * {@inheritdoc} + * + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -38,6 +44,8 @@ public function getMultiple($keys, $default = null) /** * {@inheritdoc} + * + * @return bool */ public function has($key) { @@ -46,6 +54,8 @@ public function has($key) /** * {@inheritdoc} + * + * @return bool */ public function clear() { @@ -54,6 +64,8 @@ public function clear() /** * {@inheritdoc} + * + * @return bool */ public function delete($key) { @@ -62,6 +74,8 @@ public function delete($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteMultiple($keys) { @@ -70,6 +84,8 @@ public function deleteMultiple($keys) /** * {@inheritdoc} + * + * @return bool */ public function set($key, $value, $ttl = null) { @@ -78,6 +94,8 @@ public function set($key, $value, $ttl = null) /** * {@inheritdoc} + * + * @return bool */ public function setMultiple($values, $ttl = null) { diff --git a/vendor/symfony/cache/Simple/PdoCache.php b/vendor/symfony/cache/Simple/PdoCache.php index c92e049a..7011ea07 100644 --- a/vendor/symfony/cache/Simple/PdoCache.php +++ b/vendor/symfony/cache/Simple/PdoCache.php @@ -11,9 +11,17 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\PdoAdapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PdoTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PdoCache::class, PdoAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use PdoAdapter and type-hint for CacheInterface instead. + */ class PdoCache extends AbstractCache implements PruneableInterface { use PdoTrait; @@ -25,6 +33,9 @@ class PdoCache extends AbstractCache implements PruneableInterface * a Doctrine DBAL Connection or a DSN string that will be used to * lazy-connect to the database when the cache is actually used. * + * When a Doctrine DBAL Connection is passed, the cache table is created + * automatically when possible. Otherwise, use the createTable() method. + * * List of available options: * * db_table: The name of the table [default: cache_items] * * db_id_col: The column where to store the cache id [default: item_id] @@ -35,17 +46,14 @@ class PdoCache extends AbstractCache implements PruneableInterface * * db_password: The password when lazy-connect [default: ''] * * db_connection_options: An array of driver-specific connection options [default: []] * - * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null - * @param string $namespace - * @param int $defaultLifetime - * @param array $options An associative array of options + * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null * * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION * @throws InvalidArgumentException When namespace contains invalid characters */ - public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = []) + public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], MarshallerInterface $marshaller = null) { - $this->init($connOrDsn, $namespace, $defaultLifetime, $options); + $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller); } } diff --git a/vendor/symfony/cache/Simple/PhpArrayCache.php b/vendor/symfony/cache/Simple/PhpArrayCache.php index 7bb25ff8..10c7340a 100644 --- a/vendor/symfony/cache/Simple/PhpArrayCache.php +++ b/vendor/symfony/cache/Simple/PhpArrayCache.php @@ -11,51 +11,44 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\PhpArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PhpArrayCache::class, PhpArrayAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); /** - * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0. - * Warmed up items are read-only and run-time discovered items are cached using a fallback adapter. - * - * @author Titouan Galopin - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use PhpArrayAdapter and type-hint for CacheInterface instead. */ -class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInterface +class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface { use PhpArrayTrait; /** - * @param string $file The PHP file were values are cached - * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit + * @param string $file The PHP file were values are cached + * @param Psr16CacheInterface $fallbackPool A pool to fallback on when an item is not hit */ - public function __construct($file, CacheInterface $fallbackPool) + public function __construct(string $file, Psr16CacheInterface $fallbackPool) { $this->file = $file; $this->pool = $fallbackPool; - $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN); } /** - * This adapter should only be used on PHP 7.0+ to take advantage of how PHP - * stores arrays in its latest versions. This factory method decorates the given - * fallback pool with this adapter only if the current PHP version is supported. + * This adapter takes advantage of how PHP stores arrays in its latest versions. * * @param string $file The PHP file were values are cached * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit * - * @return CacheInterface + * @return Psr16CacheInterface */ - public static function create($file, CacheInterface $fallbackPool) + public static function create($file, Psr16CacheInterface $fallbackPool) { - if (\PHP_VERSION_ID >= 70000) { - return new static($file, $fallbackPool); - } - - return $fallbackPool; + return new static($file, $fallbackPool); } /** @@ -69,22 +62,18 @@ public function get($key, $default = null) if (null === $this->values) { $this->initialize(); } - if (!isset($this->values[$key])) { + if (!isset($this->keys[$key])) { return $this->pool->get($key, $default); } - - $value = $this->values[$key]; + $value = $this->values[$this->keys[$key]]; if ('N;' === $value) { - $value = null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + return null; + } + if ($value instanceof \Closure) { try { - $e = null; - $value = unserialize($value); - } catch (\Error $e) { - } catch (\Exception $e) { - } - if (null !== $e) { + return $value(); + } catch (\Throwable $e) { return $default; } } @@ -94,6 +83,8 @@ public function get($key, $default = null) /** * {@inheritdoc} + * + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -116,6 +107,8 @@ public function getMultiple($keys, $default = null) /** * {@inheritdoc} + * + * @return bool */ public function has($key) { @@ -126,11 +119,13 @@ public function has($key) $this->initialize(); } - return isset($this->values[$key]) || $this->pool->has($key); + return isset($this->keys[$key]) || $this->pool->has($key); } /** * {@inheritdoc} + * + * @return bool */ public function delete($key) { @@ -141,11 +136,13 @@ public function delete($key) $this->initialize(); } - return !isset($this->values[$key]) && $this->pool->delete($key); + return !isset($this->keys[$key]) && $this->pool->delete($key); } /** * {@inheritdoc} + * + * @return bool */ public function deleteMultiple($keys) { @@ -161,7 +158,7 @@ public function deleteMultiple($keys) throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); } - if (isset($this->values[$key])) { + if (isset($this->keys[$key])) { $deleted = false; } else { $fallbackKeys[] = $key; @@ -180,6 +177,8 @@ public function deleteMultiple($keys) /** * {@inheritdoc} + * + * @return bool */ public function set($key, $value, $ttl = null) { @@ -190,11 +189,13 @@ public function set($key, $value, $ttl = null) $this->initialize(); } - return !isset($this->values[$key]) && $this->pool->set($key, $value, $ttl); + return !isset($this->keys[$key]) && $this->pool->set($key, $value, $ttl); } /** * {@inheritdoc} + * + * @return bool */ public function setMultiple($values, $ttl = null) { @@ -210,7 +211,7 @@ public function setMultiple($values, $ttl = null) throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); } - if (isset($this->values[$key])) { + if (isset($this->keys[$key])) { $saved = false; } else { $fallbackValues[$key] = $value; @@ -224,22 +225,20 @@ public function setMultiple($values, $ttl = null) return $saved; } - private function generateItems(array $keys, $default) + private function generateItems(array $keys, $default): iterable { $fallbackKeys = []; foreach ($keys as $key) { - if (isset($this->values[$key])) { - $value = $this->values[$key]; + if (isset($this->keys[$key])) { + $value = $this->values[$this->keys[$key]]; if ('N;' === $value) { yield $key => null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + } elseif ($value instanceof \Closure) { try { - yield $key => unserialize($value); - } catch (\Error $e) { - yield $key => $default; - } catch (\Exception $e) { + yield $key => $value(); + } catch (\Throwable $e) { yield $key => $default; } } else { @@ -251,9 +250,7 @@ private function generateItems(array $keys, $default) } if ($fallbackKeys) { - foreach ($this->pool->getMultiple($fallbackKeys, $default) as $key => $item) { - yield $key => $item; - } + yield from $this->pool->getMultiple($fallbackKeys, $default); } } } diff --git a/vendor/symfony/cache/Simple/PhpFilesCache.php b/vendor/symfony/cache/Simple/PhpFilesCache.php index 50c19034..9c79ae9a 100644 --- a/vendor/symfony/cache/Simple/PhpFilesCache.php +++ b/vendor/symfony/cache/Simple/PhpFilesCache.php @@ -11,31 +11,35 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\PhpFilesAdapter; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PhpFilesTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', PhpFilesCache::class, PhpFilesAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use PhpFilesAdapter and type-hint for CacheInterface instead. + */ class PhpFilesCache extends AbstractCache implements PruneableInterface { use PhpFilesTrait; /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory + * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire. + * Doing so is encouraged because it fits perfectly OPcache's memory model. * * @throws CacheException if OPcache is not enabled */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false) { - if (!static::isSupported()) { - throw new CacheException('OPcache is not enabled.'); - } + $this->appendOnly = $appendOnly; + self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); - - $e = new \Exception(); - $this->includeHandler = function () use ($e) { throw $e; }; - $this->zendDetectUnicode = filter_var(ini_get('zend.detect_unicode'), \FILTER_VALIDATE_BOOLEAN); + $this->includeHandler = static function ($type, $msg, $file, $line) { + throw new \ErrorException($msg, 0, $type, $file, $line); + }; } } diff --git a/vendor/symfony/cache/Simple/Psr6Cache.php b/vendor/symfony/cache/Simple/Psr6Cache.php index 6b3de205..366284b2 100644 --- a/vendor/symfony/cache/Simple/Psr6Cache.php +++ b/vendor/symfony/cache/Simple/Psr6Cache.php @@ -11,231 +11,13 @@ namespace Symfony\Component\Cache\Simple; -use Psr\Cache\CacheException as Psr6CacheException; -use Psr\Cache\CacheItemPoolInterface; -use Psr\SimpleCache\CacheException as SimpleCacheException; -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\Adapter\AdapterInterface; -use Symfony\Component\Cache\CacheItem; -use Symfony\Component\Cache\Exception\InvalidArgumentException; -use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\ResettableInterface; -use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Component\Cache\Psr16Cache; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Psr6Cache::class, Psr16Cache::class), \E_USER_DEPRECATED); /** - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use Psr16Cache instead. */ -class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterface +class Psr6Cache extends Psr16Cache { - use ProxyTrait; - - private $createCacheItem; - private $cacheItemPrototype; - - public function __construct(CacheItemPoolInterface $pool) - { - $this->pool = $pool; - - if (!$pool instanceof AdapterInterface) { - return; - } - $cacheItemPrototype = &$this->cacheItemPrototype; - $createCacheItem = \Closure::bind( - static function ($key, $value, $allowInt = false) use (&$cacheItemPrototype) { - $item = clone $cacheItemPrototype; - $item->key = $allowInt && \is_int($key) ? (string) $key : CacheItem::validateKey($key); - $item->value = $value; - $item->isHit = false; - - return $item; - }, - null, - CacheItem::class - ); - $this->createCacheItem = function ($key, $value, $allowInt = false) use ($createCacheItem) { - if (null === $this->cacheItemPrototype) { - $this->get($allowInt && \is_int($key) ? (string) $key : $key); - } - $this->createCacheItem = $createCacheItem; - - return $createCacheItem($key, $value, $allowInt); - }; - } - - /** - * {@inheritdoc} - */ - public function get($key, $default = null) - { - try { - $item = $this->pool->getItem($key); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - if (null === $this->cacheItemPrototype) { - $this->cacheItemPrototype = clone $item; - $this->cacheItemPrototype->set(null); - } - - return $item->isHit() ? $item->get() : $default; - } - - /** - * {@inheritdoc} - */ - public function set($key, $value, $ttl = null) - { - try { - if (null !== $f = $this->createCacheItem) { - $item = $f($key, $value); - } else { - $item = $this->pool->getItem($key)->set($value); - } - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - if (null !== $ttl) { - $item->expiresAfter($ttl); - } - - return $this->pool->save($item); - } - - /** - * {@inheritdoc} - */ - public function delete($key) - { - try { - return $this->pool->deleteItem($key); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function clear() - { - return $this->pool->clear(); - } - - /** - * {@inheritdoc} - */ - public function getMultiple($keys, $default = null) - { - if ($keys instanceof \Traversable) { - $keys = iterator_to_array($keys, false); - } elseif (!\is_array($keys)) { - throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys))); - } - - try { - $items = $this->pool->getItems($keys); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - $values = []; - - foreach ($items as $key => $item) { - $values[$key] = $item->isHit() ? $item->get() : $default; - } - - return $values; - } - - /** - * {@inheritdoc} - */ - public function setMultiple($values, $ttl = null) - { - $valuesIsArray = \is_array($values); - if (!$valuesIsArray && !$values instanceof \Traversable) { - throw new InvalidArgumentException(sprintf('Cache values must be array or Traversable, "%s" given.', \is_object($values) ? \get_class($values) : \gettype($values))); - } - $items = []; - - try { - if (null !== $f = $this->createCacheItem) { - $valuesIsArray = false; - foreach ($values as $key => $value) { - $items[$key] = $f($key, $value, true); - } - } elseif ($valuesIsArray) { - $items = []; - foreach ($values as $key => $value) { - $items[] = (string) $key; - } - $items = $this->pool->getItems($items); - } else { - foreach ($values as $key => $value) { - if (\is_int($key)) { - $key = (string) $key; - } - $items[$key] = $this->pool->getItem($key)->set($value); - } - } - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - $ok = true; - - foreach ($items as $key => $item) { - if ($valuesIsArray) { - $item->set($values[$key]); - } - if (null !== $ttl) { - $item->expiresAfter($ttl); - } - $ok = $this->pool->saveDeferred($item) && $ok; - } - - return $this->pool->commit() && $ok; - } - - /** - * {@inheritdoc} - */ - public function deleteMultiple($keys) - { - if ($keys instanceof \Traversable) { - $keys = iterator_to_array($keys, false); - } elseif (!\is_array($keys)) { - throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given.', \is_object($keys) ? \get_class($keys) : \gettype($keys))); - } - - try { - return $this->pool->deleteItems($keys); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - } - - /** - * {@inheritdoc} - */ - public function has($key) - { - try { - return $this->pool->hasItem($key); - } catch (SimpleCacheException $e) { - throw $e; - } catch (Psr6CacheException $e) { - throw new InvalidArgumentException($e->getMessage(), $e->getCode(), $e); - } - } } diff --git a/vendor/symfony/cache/Simple/RedisCache.php b/vendor/symfony/cache/Simple/RedisCache.php index e82c0627..e0a76fd6 100644 --- a/vendor/symfony/cache/Simple/RedisCache.php +++ b/vendor/symfony/cache/Simple/RedisCache.php @@ -11,19 +11,27 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\RedisAdapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Traits\RedisClusterProxy; +use Symfony\Component\Cache\Traits\RedisProxy; use Symfony\Component\Cache\Traits\RedisTrait; +use Symfony\Contracts\Cache\CacheInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', RedisCache::class, RedisAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); + +/** + * @deprecated since Symfony 4.3, use RedisAdapter and type-hint for CacheInterface instead. + */ class RedisCache extends AbstractCache { use RedisTrait; /** - * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient - * @param string $namespace - * @param int $defaultLifetime + * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis */ - public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) + public function __construct($redis, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($redisClient, $namespace, $defaultLifetime); + $this->init($redis, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Simple/TraceableCache.php b/vendor/symfony/cache/Simple/TraceableCache.php index 61b22963..0dae813e 100644 --- a/vendor/symfony/cache/Simple/TraceableCache.php +++ b/vendor/symfony/cache/Simple/TraceableCache.php @@ -11,22 +11,25 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; +use Symfony\Component\Cache\Adapter\TraceableAdapter; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" and type-hint for "%s" instead.', TraceableCache::class, TraceableAdapter::class, CacheInterface::class), \E_USER_DEPRECATED); /** - * An adapter that collects data about all cache calls. - * - * @author Nicolas Grekas + * @deprecated since Symfony 4.3, use TraceableAdapter and type-hint for CacheInterface instead. */ -class TraceableCache implements CacheInterface, PruneableInterface, ResettableInterface +class TraceableCache implements Psr16CacheInterface, PruneableInterface, ResettableInterface { private $pool; private $miss; private $calls = []; - public function __construct(CacheInterface $pool) + public function __construct(Psr16CacheInterface $pool) { $this->pool = $pool; $this->miss = new \stdClass(); @@ -56,6 +59,8 @@ public function get($key, $default = null) /** * {@inheritdoc} + * + * @return bool */ public function has($key) { @@ -69,6 +74,8 @@ public function has($key) /** * {@inheritdoc} + * + * @return bool */ public function delete($key) { @@ -82,6 +89,8 @@ public function delete($key) /** * {@inheritdoc} + * + * @return bool */ public function set($key, $value, $ttl = null) { @@ -95,6 +104,8 @@ public function set($key, $value, $ttl = null) /** * {@inheritdoc} + * + * @return bool */ public function setMultiple($values, $ttl = null) { @@ -122,6 +133,8 @@ public function setMultiple($values, $ttl = null) /** * {@inheritdoc} + * + * @return iterable */ public function getMultiple($keys, $default = null) { @@ -150,6 +163,8 @@ public function getMultiple($keys, $default = null) /** * {@inheritdoc} + * + * @return bool */ public function clear() { @@ -163,6 +178,8 @@ public function clear() /** * {@inheritdoc} + * + * @return bool */ public function deleteMultiple($keys) { @@ -200,7 +217,7 @@ public function prune() */ public function reset() { - if (!$this->pool instanceof ResettableInterface) { + if (!$this->pool instanceof ResetInterface) { return; } $event = $this->start(__FUNCTION__); @@ -220,7 +237,7 @@ public function getCalls() } } - private function start($name) + private function start(string $name): TraceableCacheEvent { $this->calls[] = $event = new TraceableCacheEvent(); $event->name = $name; diff --git a/vendor/symfony/cache/Tests/Adapter/AbstractRedisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/AbstractRedisAdapterTest.php deleted file mode 100644 index 0e8ed001..00000000 --- a/vendor/symfony/cache/Tests/Adapter/AbstractRedisAdapterTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\RedisAdapter; - -abstract class AbstractRedisAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testExpiration' => 'Testing expiration slows down the test suite', - 'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite', - 'testDefaultLifeTime' => 'Testing expiration slows down the test suite', - ]; - - protected static $redis; - - public function createCachePool($defaultLifetime = 0) - { - return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); - } - - public static function setUpBeforeClass() - { - if (!\extension_loaded('redis')) { - self::markTestSkipped('Extension redis required.'); - } - try { - (new \Redis())->connect(getenv('REDIS_HOST')); - } catch (\Exception $e) { - self::markTestSkipped($e->getMessage()); - } - } - - public static function tearDownAfterClass() - { - self::$redis = null; - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php deleted file mode 100644 index 5758a286..00000000 --- a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php +++ /dev/null @@ -1,175 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Cache\IntegrationTests\CachePoolTest; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\PruneableInterface; - -abstract class AdapterTestCase extends CachePoolTest -{ - protected function setUp() - { - parent::setUp(); - - if (!\array_key_exists('testDeferredSaveWithoutCommit', $this->skippedTests) && \defined('HHVM_VERSION')) { - $this->skippedTests['testDeferredSaveWithoutCommit'] = 'Destructors are called late on HHVM.'; - } - - if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) { - $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; - } - } - - public function testDefaultLifeTime() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = $this->createCachePool(2); - - $item = $cache->getItem('key.dlt'); - $item->set('value'); - $cache->save($item); - sleep(1); - - $item = $cache->getItem('key.dlt'); - $this->assertTrue($item->isHit()); - - sleep(2); - $item = $cache->getItem('key.dlt'); - $this->assertFalse($item->isHit()); - } - - public function testExpiration() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = $this->createCachePool(); - $cache->save($cache->getItem('k1')->set('v1')->expiresAfter(2)); - $cache->save($cache->getItem('k2')->set('v2')->expiresAfter(366 * 86400)); - - sleep(3); - $item = $cache->getItem('k1'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get(), "Item's value must be null when isHit() is false."); - - $item = $cache->getItem('k2'); - $this->assertTrue($item->isHit()); - $this->assertSame('v2', $item->get()); - } - - public function testNotUnserializable() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = $this->createCachePool(); - - $item = $cache->getItem('foo'); - $cache->save($item->set(new NotUnserializable())); - - $item = $cache->getItem('foo'); - $this->assertFalse($item->isHit()); - - foreach ($cache->getItems(['foo']) as $item) { - } - $cache->save($item->set(new NotUnserializable())); - - foreach ($cache->getItems(['foo']) as $item) { - } - $this->assertFalse($item->isHit()); - } - - public function testPrune() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - if (!method_exists($this, 'isPruned')) { - $this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.'); - } - - /** @var PruneableInterface|CacheItemPoolInterface $cache */ - $cache = $this->createCachePool(); - - $doSet = function ($name, $value, \DateInterval $expiresAfter = null) use ($cache) { - $item = $cache->getItem($name); - $item->set($value); - - if ($expiresAfter) { - $item->expiresAfter($expiresAfter); - } - - $cache->save($item); - }; - - $doSet('foo', 'foo-val', new \DateInterval('PT05S')); - $doSet('bar', 'bar-val', new \DateInterval('PT10S')); - $doSet('baz', 'baz-val', new \DateInterval('PT15S')); - $doSet('qux', 'qux-val', new \DateInterval('PT20S')); - - sleep(30); - $cache->prune(); - $this->assertTrue($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'bar')); - $this->assertTrue($this->isPruned($cache, 'baz')); - $this->assertTrue($this->isPruned($cache, 'qux')); - - $doSet('foo', 'foo-val'); - $doSet('bar', 'bar-val', new \DateInterval('PT20S')); - $doSet('baz', 'baz-val', new \DateInterval('PT40S')); - $doSet('qux', 'qux-val', new \DateInterval('PT80S')); - - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertFalse($this->isPruned($cache, 'bar')); - $this->assertFalse($this->isPruned($cache, 'baz')); - $this->assertFalse($this->isPruned($cache, 'qux')); - - sleep(30); - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'bar')); - $this->assertFalse($this->isPruned($cache, 'baz')); - $this->assertFalse($this->isPruned($cache, 'qux')); - - sleep(30); - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'baz')); - $this->assertFalse($this->isPruned($cache, 'qux')); - - sleep(30); - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'qux')); - } -} - -class NotUnserializable implements \Serializable -{ - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) - { - throw new \Exception(__CLASS__); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php deleted file mode 100644 index f55a1b9b..00000000 --- a/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php +++ /dev/null @@ -1,124 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Psr\Log\NullLogger; -use Symfony\Component\Cache\Adapter\ApcuAdapter; - -class ApcuAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testExpiration' => 'Testing expiration slows down the test suite', - 'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite', - 'testDefaultLifeTime' => 'Testing expiration slows down the test suite', - ]; - - public function createCachePool($defaultLifetime = 0) - { - if (!\function_exists('apcu_fetch') || !filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN)) { - $this->markTestSkipped('APCu extension is required.'); - } - if ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) { - if ('testWithCliSapi' !== $this->getName()) { - $this->markTestSkipped('apc.enable_cli=1 is required.'); - } - } - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Fails transiently on Windows.'); - } - - return new ApcuAdapter(str_replace('\\', '.', __CLASS__), $defaultLifetime); - } - - public function testUnserializable() - { - $pool = $this->createCachePool(); - - $item = $pool->getItem('foo'); - $item->set(function () {}); - - $this->assertFalse($pool->save($item)); - - $item = $pool->getItem('foo'); - $this->assertFalse($item->isHit()); - } - - public function testVersion() - { - $namespace = str_replace('\\', '.', static::class); - - $pool1 = new ApcuAdapter($namespace, 0, 'p1'); - - $item = $pool1->getItem('foo'); - $this->assertFalse($item->isHit()); - $this->assertTrue($pool1->save($item->set('bar'))); - - $item = $pool1->getItem('foo'); - $this->assertTrue($item->isHit()); - $this->assertSame('bar', $item->get()); - - $pool2 = new ApcuAdapter($namespace, 0, 'p2'); - - $item = $pool2->getItem('foo'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get()); - - $item = $pool1->getItem('foo'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get()); - } - - public function testNamespace() - { - $namespace = str_replace('\\', '.', static::class); - - $pool1 = new ApcuAdapter($namespace.'_1', 0, 'p1'); - - $item = $pool1->getItem('foo'); - $this->assertFalse($item->isHit()); - $this->assertTrue($pool1->save($item->set('bar'))); - - $item = $pool1->getItem('foo'); - $this->assertTrue($item->isHit()); - $this->assertSame('bar', $item->get()); - - $pool2 = new ApcuAdapter($namespace.'_2', 0, 'p1'); - - $item = $pool2->getItem('foo'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get()); - - $item = $pool1->getItem('foo'); - $this->assertTrue($item->isHit()); - $this->assertSame('bar', $item->get()); - } - - public function testWithCliSapi() - { - try { - // disable PHPUnit error handler to mimic a production environment - $isCalled = false; - set_error_handler(function () use (&$isCalled) { - $isCalled = true; - }); - $pool = new ApcuAdapter(str_replace('\\', '.', __CLASS__)); - $pool->setLogger(new NullLogger()); - - $item = $pool->getItem('foo'); - $item->isHit(); - $pool->save($item->set('bar')); - $this->assertFalse($isCalled); - } finally { - restore_error_handler(); - } - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php deleted file mode 100644 index e6adc9d0..00000000 --- a/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\ArrayAdapter; - -/** - * @group time-sensitive - */ -class ArrayAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.', - 'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.', - ]; - - public function createCachePool($defaultLifetime = 0) - { - return new ArrayAdapter($defaultLifetime); - } - - public function testGetValuesHitAndMiss() - { - /** @var ArrayAdapter $cache */ - $cache = $this->createCachePool(); - - // Hit - $item = $cache->getItem('foo'); - $item->set('4711'); - $cache->save($item); - - $fooItem = $cache->getItem('foo'); - $this->assertTrue($fooItem->isHit()); - $this->assertEquals('4711', $fooItem->get()); - - // Miss (should be present as NULL in $values) - $cache->getItem('bar'); - - $values = $cache->getValues(); - - $this->assertCount(2, $values); - $this->assertArrayHasKey('foo', $values); - $this->assertSame(serialize('4711'), $values['foo']); - $this->assertArrayHasKey('bar', $values); - $this->assertNull($values['bar']); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php deleted file mode 100644 index be811d6f..00000000 --- a/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php +++ /dev/null @@ -1,233 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use PHPUnit\Framework\MockObject\MockObject; -use Symfony\Component\Cache\Adapter\AdapterInterface; -use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Cache\Adapter\ChainAdapter; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; -use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter; - -/** - * @author Kévin Dunglas - * @group time-sensitive - */ -class ChainAdapterTest extends AdapterTestCase -{ - public function createCachePool($defaultLifetime = 0) - { - return new ChainAdapter([new ArrayAdapter($defaultLifetime), new ExternalAdapter($defaultLifetime), new FilesystemAdapter('', $defaultLifetime)], $defaultLifetime); - } - - public function testEmptyAdaptersException() - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('At least one adapter must be specified.'); - new ChainAdapter([]); - } - - public function testInvalidAdapterException() - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The class "stdClass" does not implement'); - new ChainAdapter([new \stdClass()]); - } - - public function testPrune() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = new ChainAdapter([ - $this->getPruneableMock(), - $this->getNonPruneableMock(), - $this->getPruneableMock(), - ]); - $this->assertTrue($cache->prune()); - - $cache = new ChainAdapter([ - $this->getPruneableMock(), - $this->getFailingPruneableMock(), - $this->getPruneableMock(), - ]); - $this->assertFalse($cache->prune()); - } - - public function testMultipleCachesExpirationWhenCommonTtlIsNotSet() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $adapter1 = new ArrayAdapter(4); - $adapter2 = new ArrayAdapter(2); - - $cache = new ChainAdapter([$adapter1, $adapter2]); - - $cache->save($cache->getItem('key')->set('value')); - - $item = $adapter1->getItem('key'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value', $item->get()); - - $item = $adapter2->getItem('key'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value', $item->get()); - - sleep(2); - - $item = $adapter1->getItem('key'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value', $item->get()); - - $item = $adapter2->getItem('key'); - $this->assertFalse($item->isHit()); - - sleep(2); - - $item = $adapter1->getItem('key'); - $this->assertFalse($item->isHit()); - - $adapter2->save($adapter2->getItem('key1')->set('value1')); - - $item = $cache->getItem('key1'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value1', $item->get()); - - sleep(2); - - $item = $adapter1->getItem('key1'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value1', $item->get()); - - $item = $adapter2->getItem('key1'); - $this->assertFalse($item->isHit()); - - sleep(2); - - $item = $adapter1->getItem('key1'); - $this->assertFalse($item->isHit()); - } - - public function testMultipleCachesExpirationWhenCommonTtlIsSet() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $adapter1 = new ArrayAdapter(4); - $adapter2 = new ArrayAdapter(2); - - $cache = new ChainAdapter([$adapter1, $adapter2], 6); - - $cache->save($cache->getItem('key')->set('value')); - - $item = $adapter1->getItem('key'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value', $item->get()); - - $item = $adapter2->getItem('key'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value', $item->get()); - - sleep(2); - - $item = $adapter1->getItem('key'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value', $item->get()); - - $item = $adapter2->getItem('key'); - $this->assertFalse($item->isHit()); - - sleep(2); - - $item = $adapter1->getItem('key'); - $this->assertFalse($item->isHit()); - - $adapter2->save($adapter2->getItem('key1')->set('value1')); - - $item = $cache->getItem('key1'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value1', $item->get()); - - sleep(2); - - $item = $adapter1->getItem('key1'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value1', $item->get()); - - $item = $adapter2->getItem('key1'); - $this->assertFalse($item->isHit()); - - sleep(2); - - $item = $adapter1->getItem('key1'); - $this->assertTrue($item->isHit()); - $this->assertEquals('value1', $item->get()); - - sleep(2); - - $item = $adapter1->getItem('key1'); - $this->assertFalse($item->isHit()); - } - - /** - * @return MockObject|PruneableCacheInterface - */ - private function getPruneableMock() - { - $pruneable = $this - ->getMockBuilder(PruneableCacheInterface::class) - ->getMock(); - - $pruneable - ->expects($this->atLeastOnce()) - ->method('prune') - ->willReturn(true); - - return $pruneable; - } - - /** - * @return MockObject|PruneableCacheInterface - */ - private function getFailingPruneableMock() - { - $pruneable = $this - ->getMockBuilder(PruneableCacheInterface::class) - ->getMock(); - - $pruneable - ->expects($this->atLeastOnce()) - ->method('prune') - ->willReturn(false); - - return $pruneable; - } - - /** - * @return MockObject|AdapterInterface - */ - private function getNonPruneableMock() - { - return $this - ->getMockBuilder(AdapterInterface::class) - ->getMock(); - } -} - -interface PruneableCacheInterface extends PruneableInterface, AdapterInterface -{ -} diff --git a/vendor/symfony/cache/Tests/Adapter/DoctrineAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/DoctrineAdapterTest.php deleted file mode 100644 index 8f520cb5..00000000 --- a/vendor/symfony/cache/Tests/Adapter/DoctrineAdapterTest.php +++ /dev/null @@ -1,32 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\DoctrineAdapter; -use Symfony\Component\Cache\Tests\Fixtures\ArrayCache; - -/** - * @group time-sensitive - */ -class DoctrineAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayCache is not.', - 'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayCache is not.', - 'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize', - ]; - - public function createCachePool($defaultLifetime = 0) - { - return new DoctrineAdapter(new ArrayCache($defaultLifetime), '', $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/FilesystemAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/FilesystemAdapterTest.php deleted file mode 100644 index fa830682..00000000 --- a/vendor/symfony/cache/Tests/Adapter/FilesystemAdapterTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; - -/** - * @group time-sensitive - */ -class FilesystemAdapterTest extends AdapterTestCase -{ - public function createCachePool($defaultLifetime = 0) - { - return new FilesystemAdapter('', $defaultLifetime); - } - - public static function tearDownAfterClass() - { - self::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - - public static function rmdir($dir) - { - if (!file_exists($dir)) { - return; - } - if (!$dir || 0 !== strpos(\dirname($dir), sys_get_temp_dir())) { - throw new \Exception(__METHOD__."() operates only on subdirs of system's temp dir"); - } - $children = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS), - \RecursiveIteratorIterator::CHILD_FIRST - ); - foreach ($children as $child) { - if ($child->isDir()) { - rmdir($child); - } else { - unlink($child); - } - } - rmdir($dir); - } - - protected function isPruned(CacheItemPoolInterface $cache, $name) - { - $getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile'); - $getFileMethod->setAccessible(true); - - return !file_exists($getFileMethod->invoke($cache, $name)); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php deleted file mode 100644 index 536e2c2d..00000000 --- a/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php +++ /dev/null @@ -1,87 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Cache\Adapter\AbstractAdapter; - -class MaxIdLengthAdapterTest extends TestCase -{ - public function testLongKey() - { - $cache = $this->getMockBuilder(MaxIdLengthAdapter::class) - ->setConstructorArgs([str_repeat('-', 10)]) - ->setMethods(['doHave', 'doFetch', 'doDelete', 'doSave', 'doClear']) - ->getMock(); - - $cache->expects($this->exactly(2)) - ->method('doHave') - ->withConsecutive( - [$this->equalTo('----------:0GTYWa9n4ed8vqNlOT2iEr:')], - [$this->equalTo('----------:---------------------------------------')] - ); - - $cache->hasItem(str_repeat('-', 40)); - $cache->hasItem(str_repeat('-', 39)); - } - - public function testLongKeyVersioning() - { - $cache = $this->getMockBuilder(MaxIdLengthAdapter::class) - ->setConstructorArgs([str_repeat('-', 26)]) - ->getMock(); - - $cache - ->method('doFetch') - ->willReturn(['2:']); - - $reflectionClass = new \ReflectionClass(AbstractAdapter::class); - - $reflectionMethod = $reflectionClass->getMethod('getId'); - $reflectionMethod->setAccessible(true); - - // No versioning enabled - $this->assertEquals('--------------------------:------------', $reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)])); - $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)]))); - $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 23)]))); - $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 40)]))); - - $reflectionProperty = $reflectionClass->getProperty('versioningIsEnabled'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($cache, true); - - // Versioning enabled - $this->assertEquals('--------------------------:2:------------', $reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)])); - $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 12)]))); - $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 23)]))); - $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, [str_repeat('-', 40)]))); - } - - public function testTooLongNamespace() - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Namespace must be 26 chars max, 40 given ("----------------------------------------")'); - $this->getMockBuilder(MaxIdLengthAdapter::class) - ->setConstructorArgs([str_repeat('-', 40)]) - ->getMock(); - } -} - -abstract class MaxIdLengthAdapter extends AbstractAdapter -{ - protected $maxIdLength = 50; - - public function __construct($ns) - { - parent::__construct($ns); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php deleted file mode 100644 index a9a397dd..00000000 --- a/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php +++ /dev/null @@ -1,204 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\AbstractAdapter; -use Symfony\Component\Cache\Adapter\MemcachedAdapter; - -class MemcachedAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testHasItemReturnsFalseWhenDeferredItemIsExpired' => 'Testing expiration slows down the test suite', - 'testDefaultLifeTime' => 'Testing expiration slows down the test suite', - ]; - - protected static $client; - - public static function setUpBeforeClass() - { - if (!MemcachedAdapter::isSupported()) { - self::markTestSkipped('Extension memcached >=2.2.0 required.'); - } - self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]); - self::$client->get('foo'); - $code = self::$client->getResultCode(); - - if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) { - self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage())); - } - } - - public function createCachePool($defaultLifetime = 0) - { - $client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')) : self::$client; - - return new MemcachedAdapter($client, str_replace('\\', '.', __CLASS__), $defaultLifetime); - } - - public function testOptions() - { - $client = MemcachedAdapter::createConnection([], [ - 'libketama_compatible' => false, - 'distribution' => 'modula', - 'compression' => true, - 'serializer' => 'php', - 'hash' => 'md5', - ]); - - $this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER)); - $this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH)); - $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION)); - $this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE)); - $this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION)); - } - - /** - * @dataProvider provideBadOptions - */ - public function testBadOptions($name, $value) - { - if (\PHP_VERSION_ID < 80000) { - $this->expectException('ErrorException'); - $this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::'); - } else { - $this->expectException('Error'); - $this->expectExceptionMessage('Undefined constant Memcached::'); - } - - MemcachedAdapter::createConnection([], [$name => $value]); - } - - public function provideBadOptions() - { - return [ - ['foo', 'bar'], - ['hash', 'zyx'], - ['serializer', 'zyx'], - ['distribution', 'zyx'], - ]; - } - - public function testDefaultOptions() - { - $this->assertTrue(MemcachedAdapter::isSupported()); - - $client = MemcachedAdapter::createConnection([]); - - $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION)); - $this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL)); - $this->assertSame(1, $client->getOption(\Memcached::OPT_TCP_NODELAY)); - $this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE)); - } - - public function testOptionSerializer() - { - $this->expectException('Symfony\Component\Cache\Exception\CacheException'); - $this->expectExceptionMessage('MemcachedAdapter: "serializer" option must be "php" or "igbinary".'); - if (!\Memcached::HAVE_JSON) { - $this->markTestSkipped('Memcached::HAVE_JSON required'); - } - - new MemcachedAdapter(MemcachedAdapter::createConnection([], ['serializer' => 'json'])); - } - - /** - * @dataProvider provideServersSetting - */ - public function testServersSetting($dsn, $host, $port) - { - $client1 = MemcachedAdapter::createConnection($dsn); - $client2 = MemcachedAdapter::createConnection([$dsn]); - $client3 = MemcachedAdapter::createConnection([[$host, $port]]); - $expect = [ - 'host' => $host, - 'port' => $port, - ]; - - $f = function ($s) { return ['host' => $s['host'], 'port' => $s['port']]; }; - $this->assertSame([$expect], array_map($f, $client1->getServerList())); - $this->assertSame([$expect], array_map($f, $client2->getServerList())); - $this->assertSame([$expect], array_map($f, $client3->getServerList())); - } - - public function provideServersSetting() - { - yield [ - 'memcached://127.0.0.1/50', - '127.0.0.1', - 11211, - ]; - yield [ - 'memcached://localhost:11222?weight=25', - 'localhost', - 11222, - ]; - if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) { - yield [ - 'memcached://user:password@127.0.0.1?weight=50', - '127.0.0.1', - 11211, - ]; - } - yield [ - 'memcached:///var/run/memcached.sock?weight=25', - '/var/run/memcached.sock', - 0, - ]; - yield [ - 'memcached:///var/local/run/memcached.socket?weight=25', - '/var/local/run/memcached.socket', - 0, - ]; - if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) { - yield [ - 'memcached://user:password@/var/local/run/memcached.socket?weight=25', - '/var/local/run/memcached.socket', - 0, - ]; - } - } - - /** - * @dataProvider provideDsnWithOptions - */ - public function testDsnWithOptions($dsn, array $options, array $expectedOptions) - { - $client = MemcachedAdapter::createConnection($dsn, $options); - - foreach ($expectedOptions as $option => $expect) { - $this->assertSame($expect, $client->getOption($option)); - } - } - - public function provideDsnWithOptions() - { - if (!class_exists('\Memcached')) { - self::markTestSkipped('Extension memcached required.'); - } - - yield [ - 'memcached://localhost:11222?retry_timeout=10', - [\Memcached::OPT_RETRY_TIMEOUT => 8], - [\Memcached::OPT_RETRY_TIMEOUT => 10], - ]; - yield [ - 'memcached://localhost:11222?socket_recv_size=1&socket_send_size=2', - [\Memcached::OPT_RETRY_TIMEOUT => 8], - [\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8], - ]; - } - - public function testClear() - { - $this->assertTrue($this->createCachePool()->clear()); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php deleted file mode 100644 index c2714033..00000000 --- a/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Cache\Adapter\ProxyAdapter; - -/** - * @group time-sensitive - */ -class NamespacedProxyAdapterTest extends ProxyAdapterTest -{ - public function createCachePool($defaultLifetime = 0) - { - return new ProxyAdapter(new ArrayAdapter($defaultLifetime), 'foo', $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/NullAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/NullAdapterTest.php deleted file mode 100644 index b771fa0e..00000000 --- a/vendor/symfony/cache/Tests/Adapter/NullAdapterTest.php +++ /dev/null @@ -1,128 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use PHPUnit\Framework\TestCase; -use Psr\Cache\CacheItemInterface; -use Symfony\Component\Cache\Adapter\NullAdapter; - -/** - * @group time-sensitive - */ -class NullAdapterTest extends TestCase -{ - public function createCachePool() - { - return new NullAdapter(); - } - - public function testGetItem() - { - $adapter = $this->createCachePool(); - - $item = $adapter->getItem('key'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - } - - public function testHasItem() - { - $this->assertFalse($this->createCachePool()->hasItem('key')); - } - - public function testGetItems() - { - $adapter = $this->createCachePool(); - - $keys = ['foo', 'bar', 'baz', 'biz']; - - /** @var CacheItemInterface[] $items */ - $items = $adapter->getItems($keys); - $count = 0; - - foreach ($items as $key => $item) { - $itemKey = $item->getKey(); - - $this->assertEquals($itemKey, $key, 'Keys must be preserved when fetching multiple items'); - $this->assertContains($key, $keys, 'Cache key can not change.'); - $this->assertFalse($item->isHit()); - - // Remove $key for $keys - foreach ($keys as $k => $v) { - if ($v === $key) { - unset($keys[$k]); - } - } - - ++$count; - } - - $this->assertSame(4, $count); - } - - public function testIsHit() - { - $adapter = $this->createCachePool(); - - $item = $adapter->getItem('key'); - $this->assertFalse($item->isHit()); - } - - public function testClear() - { - $this->assertTrue($this->createCachePool()->clear()); - } - - public function testDeleteItem() - { - $this->assertTrue($this->createCachePool()->deleteItem('key')); - } - - public function testDeleteItems() - { - $this->assertTrue($this->createCachePool()->deleteItems(['key', 'foo', 'bar'])); - } - - public function testSave() - { - $adapter = $this->createCachePool(); - - $item = $adapter->getItem('key'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - - $this->assertFalse($adapter->save($item)); - } - - public function testDeferredSave() - { - $adapter = $this->createCachePool(); - - $item = $adapter->getItem('key'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - - $this->assertFalse($adapter->saveDeferred($item)); - } - - public function testCommit() - { - $adapter = $this->createCachePool(); - - $item = $adapter->getItem('key'); - $this->assertFalse($item->isHit()); - $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - - $this->assertFalse($adapter->saveDeferred($item)); - $this->assertFalse($this->createCachePool()->commit()); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PdoAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PdoAdapterTest.php deleted file mode 100644 index dd2a9118..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PdoAdapterTest.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\PdoAdapter; -use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; - -/** - * @group time-sensitive - */ -class PdoAdapterTest extends AdapterTestCase -{ - use PdoPruneableTrait; - - protected static $dbFile; - - public static function setUpBeforeClass() - { - if (!\extension_loaded('pdo_sqlite')) { - self::markTestSkipped('Extension pdo_sqlite required.'); - } - - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); - - $pool = new PdoAdapter('sqlite:'.self::$dbFile); - $pool->createTable(); - } - - public static function tearDownAfterClass() - { - @unlink(self::$dbFile); - } - - public function createCachePool($defaultLifetime = 0) - { - return new PdoAdapter('sqlite:'.self::$dbFile, 'ns', $defaultLifetime); - } - - public function testCleanupExpiredItems() - { - $pdo = new \PDO('sqlite:'.self::$dbFile); - - $getCacheItemCount = function () use ($pdo) { - return (int) $pdo->query('SELECT COUNT(*) FROM cache_items')->fetch(\PDO::FETCH_COLUMN); - }; - - $this->assertSame(0, $getCacheItemCount()); - - $cache = $this->createCachePool(); - - $item = $cache->getItem('some_nice_key'); - $item->expiresAfter(1); - $item->set(1); - - $cache->save($item); - $this->assertSame(1, $getCacheItemCount()); - - sleep(2); - - $newItem = $cache->getItem($item->getKey()); - $this->assertFalse($newItem->isHit()); - $this->assertSame(0, $getCacheItemCount(), 'PDOAdapter must clean up expired items'); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php deleted file mode 100644 index aa53958c..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Doctrine\DBAL\DriverManager; -use Symfony\Component\Cache\Adapter\PdoAdapter; -use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; - -/** - * @group time-sensitive - */ -class PdoDbalAdapterTest extends AdapterTestCase -{ - use PdoPruneableTrait; - - protected static $dbFile; - - public static function setUpBeforeClass() - { - if (!\extension_loaded('pdo_sqlite')) { - self::markTestSkipped('Extension pdo_sqlite required.'); - } - - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); - - $pool = new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile])); - $pool->createTable(); - } - - public static function tearDownAfterClass() - { - @unlink(self::$dbFile); - } - - public function createCachePool($defaultLifetime = 0) - { - return new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php deleted file mode 100644 index f88a7187..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Psr\Cache\CacheItemInterface; -use Symfony\Component\Cache\Adapter\NullAdapter; -use Symfony\Component\Cache\Adapter\PhpArrayAdapter; - -/** - * @group time-sensitive - */ -class PhpArrayAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testBasicUsage' => 'PhpArrayAdapter is read-only.', - 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', - 'testClear' => 'PhpArrayAdapter is read-only.', - 'testClearWithDeferredItems' => 'PhpArrayAdapter is read-only.', - 'testDeleteItem' => 'PhpArrayAdapter is read-only.', - 'testSaveExpired' => 'PhpArrayAdapter is read-only.', - 'testSaveWithoutExpire' => 'PhpArrayAdapter is read-only.', - 'testDeferredSave' => 'PhpArrayAdapter is read-only.', - 'testDeferredSaveWithoutCommit' => 'PhpArrayAdapter is read-only.', - 'testDeleteItems' => 'PhpArrayAdapter is read-only.', - 'testDeleteDeferredItem' => 'PhpArrayAdapter is read-only.', - 'testCommit' => 'PhpArrayAdapter is read-only.', - 'testSaveDeferredWhenChangingValues' => 'PhpArrayAdapter is read-only.', - 'testSaveDeferredOverwrite' => 'PhpArrayAdapter is read-only.', - 'testIsHitDeferred' => 'PhpArrayAdapter is read-only.', - - 'testExpiresAt' => 'PhpArrayAdapter does not support expiration.', - 'testExpiresAtWithNull' => 'PhpArrayAdapter does not support expiration.', - 'testExpiresAfterWithNull' => 'PhpArrayAdapter does not support expiration.', - 'testDeferredExpired' => 'PhpArrayAdapter does not support expiration.', - 'testExpiration' => 'PhpArrayAdapter does not support expiration.', - - 'testGetItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testGetItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - - 'testDefaultLifeTime' => 'PhpArrayAdapter does not allow configuring a default lifetime.', - 'testPrune' => 'PhpArrayAdapter just proxies', - ]; - - protected static $file; - - public static function setUpBeforeClass() - { - self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php'; - } - - protected function tearDown() - { - $this->createCachePool()->clear(); - - if (file_exists(sys_get_temp_dir().'/symfony-cache')) { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - } - - public function createCachePool() - { - return new PhpArrayAdapterWrapper(self::$file, new NullAdapter()); - } - - public function testStore() - { - $arrayWithRefs = []; - $arrayWithRefs[0] = 123; - $arrayWithRefs[1] = &$arrayWithRefs[0]; - - $object = (object) [ - 'foo' => 'bar', - 'foo2' => 'bar2', - ]; - - $expected = [ - 'null' => null, - 'serializedString' => serialize($object), - 'arrayWithRefs' => $arrayWithRefs, - 'object' => $object, - 'arrayWithObject' => ['bar' => $object], - ]; - - $adapter = $this->createCachePool(); - $adapter->warmUp($expected); - - foreach ($expected as $key => $value) { - $this->assertSame(serialize($value), serialize($adapter->getItem($key)->get()), 'Warm up should create a PHP file that OPCache can load in memory'); - } - } - - public function testStoredFile() - { - $expected = [ - 'integer' => 42, - 'float' => 42.42, - 'boolean' => true, - 'array_simple' => ['foo', 'bar'], - 'array_associative' => ['foo' => 'bar', 'foo2' => 'bar2'], - ]; - - $adapter = $this->createCachePool(); - $adapter->warmUp($expected); - - $values = eval(substr(file_get_contents(self::$file), 6)); - - $this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory'); - } -} - -class PhpArrayAdapterWrapper extends PhpArrayAdapter -{ - public function save(CacheItemInterface $item) - { - \call_user_func(\Closure::bind(function () use ($item) { - $this->values[$item->getKey()] = $item->get(); - $this->warmUp($this->values); - $this->values = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayAdapter::class)); - - return true; - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php deleted file mode 100644 index 0bfd5c39..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\FilesystemAdapter; -use Symfony\Component\Cache\Adapter\PhpArrayAdapter; - -/** - * @group time-sensitive - */ -class PhpArrayAdapterWithFallbackTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testGetItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testGetItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testHasItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testDeleteItemInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testDeleteItemsInvalidKeys' => 'PhpArrayAdapter does not throw exceptions on invalid key.', - 'testPrune' => 'PhpArrayAdapter just proxies', - ]; - - protected static $file; - - public static function setUpBeforeClass() - { - self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php'; - } - - protected function tearDown() - { - $this->createCachePool()->clear(); - - if (file_exists(sys_get_temp_dir().'/symfony-cache')) { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - } - - public function createCachePool($defaultLifetime = 0) - { - return new PhpArrayAdapter(self::$file, new FilesystemAdapter('php-array-fallback', $defaultLifetime)); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php deleted file mode 100644 index 247160d5..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\Adapter\PhpFilesAdapter; - -/** - * @group time-sensitive - */ -class PhpFilesAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testDefaultLifeTime' => 'PhpFilesAdapter does not allow configuring a default lifetime.', - ]; - - public function createCachePool() - { - if (!PhpFilesAdapter::isSupported()) { - $this->markTestSkipped('OPcache extension is not enabled.'); - } - - return new PhpFilesAdapter('sf-cache'); - } - - public static function tearDownAfterClass() - { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - - protected function isPruned(CacheItemPoolInterface $cache, $name) - { - $getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile'); - $getFileMethod->setAccessible(true); - - return !file_exists($getFileMethod->invoke($cache, $name)); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php deleted file mode 100644 index 6aadbf26..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Predis\Connection\StreamConnection; -use Symfony\Component\Cache\Adapter\RedisAdapter; - -class PredisAdapterTest extends AbstractRedisAdapterTest -{ - public static function setUpBeforeClass() - { - parent::setUpBeforeClass(); - self::$redis = new \Predis\Client(['host' => getenv('REDIS_HOST')]); - } - - public function testCreateConnection() - { - $redisHost = getenv('REDIS_HOST'); - - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'/1', ['class' => \Predis\Client::class, 'timeout' => 3]); - $this->assertInstanceOf(\Predis\Client::class, $redis); - - $connection = $redis->getConnection(); - $this->assertInstanceOf(StreamConnection::class, $connection); - - $params = [ - 'scheme' => 'tcp', - 'host' => $redisHost, - 'path' => '', - 'dbindex' => '1', - 'port' => 6379, - 'class' => 'Predis\Client', - 'timeout' => 3, - 'persistent' => 0, - 'persistent_id' => null, - 'read_timeout' => 0, - 'retry_interval' => 0, - 'lazy' => false, - 'database' => '1', - 'password' => null, - ]; - $this->assertSame($params, $connection->getParameters()->toArray()); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisClusterAdapterTest.php deleted file mode 100644 index 1afabaf1..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PredisClusterAdapterTest.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -class PredisClusterAdapterTest extends AbstractRedisAdapterTest -{ - public static function setUpBeforeClass() - { - parent::setUpBeforeClass(); - self::$redis = new \Predis\Client([['host' => getenv('REDIS_HOST')]]); - } - - public static function tearDownAfterClass() - { - self::$redis = null; - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisRedisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisRedisClusterAdapterTest.php deleted file mode 100644 index 5b09919e..00000000 --- a/vendor/symfony/cache/Tests/Adapter/PredisRedisClusterAdapterTest.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -class PredisRedisClusterAdapterTest extends AbstractRedisAdapterTest -{ - public static function setUpBeforeClass() - { - if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { - self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); - } - self::$redis = new \Predis\Client(explode(' ', $hosts), ['cluster' => 'redis']); - } - - public static function tearDownAfterClass() - { - self::$redis = null; - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php deleted file mode 100644 index 810cb31a..00000000 --- a/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Psr\Cache\CacheItemInterface; -use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Cache\Adapter\ProxyAdapter; -use Symfony\Component\Cache\CacheItem; - -/** - * @group time-sensitive - */ -class ProxyAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.', - 'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.', - 'testPrune' => 'ProxyAdapter just proxies', - ]; - - public function createCachePool($defaultLifetime = 0) - { - return new ProxyAdapter(new ArrayAdapter(), '', $defaultLifetime); - } - - public function testProxyfiedItem() - { - $this->expectException('Exception'); - $this->expectExceptionMessage('OK bar'); - $item = new CacheItem(); - $pool = new ProxyAdapter(new TestingArrayAdapter($item)); - - $proxyItem = $pool->getItem('foo'); - - $this->assertNotSame($item, $proxyItem); - $pool->save($proxyItem->set('bar')); - } -} - -class TestingArrayAdapter extends ArrayAdapter -{ - private $item; - - public function __construct(CacheItemInterface $item) - { - $this->item = $item; - } - - public function getItem($key) - { - return $this->item; - } - - public function save(CacheItemInterface $item) - { - if ($item === $this->item) { - throw new \Exception('OK '.$item->get()); - } - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php deleted file mode 100644 index 6ec6321a..00000000 --- a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php +++ /dev/null @@ -1,92 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\AbstractAdapter; -use Symfony\Component\Cache\Adapter\RedisAdapter; -use Symfony\Component\Cache\Traits\RedisProxy; - -class RedisAdapterTest extends AbstractRedisAdapterTest -{ - public static function setUpBeforeClass() - { - parent::setUpBeforeClass(); - self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), ['lazy' => true]); - } - - public function createCachePool($defaultLifetime = 0) - { - $adapter = parent::createCachePool($defaultLifetime); - $this->assertInstanceOf(RedisProxy::class, self::$redis); - - return $adapter; - } - - public function testCreateConnection() - { - $redisHost = getenv('REDIS_HOST'); - - $redis = RedisAdapter::createConnection('redis://'.$redisHost); - $this->assertInstanceOf(\Redis::class, $redis); - $this->assertTrue($redis->isConnected()); - $this->assertSame(0, $redis->getDbNum()); - - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'/2'); - $this->assertSame(2, $redis->getDbNum()); - - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['timeout' => 3]); - $this->assertEquals(3, $redis->getTimeout()); - - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'?timeout=4'); - $this->assertEquals(4, $redis->getTimeout()); - - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['read_timeout' => 5]); - $this->assertEquals(5, $redis->getReadTimeout()); - } - - /** - * @dataProvider provideFailedCreateConnection - */ - public function testFailedCreateConnection($dsn) - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Redis connection '); - RedisAdapter::createConnection($dsn); - } - - public function provideFailedCreateConnection() - { - return [ - ['redis://localhost:1234'], - ['redis://foo@localhost'], - ['redis://localhost/123'], - ]; - } - - /** - * @dataProvider provideInvalidCreateConnection - */ - public function testInvalidCreateConnection($dsn) - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid Redis DSN'); - RedisAdapter::createConnection($dsn); - } - - public function provideInvalidCreateConnection() - { - return [ - ['foo://localhost'], - ['redis://'], - ]; - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisArrayAdapterTest.php deleted file mode 100644 index bd9def32..00000000 --- a/vendor/symfony/cache/Tests/Adapter/RedisArrayAdapterTest.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -class RedisArrayAdapterTest extends AbstractRedisAdapterTest -{ - public static function setUpBeforeClass() - { - parent::setupBeforeClass(); - if (!class_exists('RedisArray')) { - self::markTestSkipped('The RedisArray class is required.'); - } - self::$redis = new \RedisArray([getenv('REDIS_HOST')], ['lazy_connect' => true]); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php deleted file mode 100644 index 9c339d2d..00000000 --- a/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -class RedisClusterAdapterTest extends AbstractRedisAdapterTest -{ - public static function setUpBeforeClass() - { - if (!class_exists('RedisCluster')) { - self::markTestSkipped('The RedisCluster class is required.'); - } - if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { - self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); - } - - self::$redis = new \RedisCluster(null, explode(' ', $hosts)); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php deleted file mode 100644 index d8470a2e..00000000 --- a/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php +++ /dev/null @@ -1,41 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\SimpleCacheAdapter; -use Symfony\Component\Cache\Simple\ArrayCache; -use Symfony\Component\Cache\Simple\FilesystemCache; - -/** - * @group time-sensitive - */ -class SimpleCacheAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testPrune' => 'SimpleCache just proxies', - ]; - - public function createCachePool($defaultLifetime = 0) - { - return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime); - } - - public function testValidCacheKeyWithNamespace() - { - $cache = new SimpleCacheAdapter(new ArrayCache(), 'some_namespace', 0); - $item = $cache->getItem('my_key'); - $item->set('someValue'); - $cache->save($item); - - $this->assertTrue($cache->getItem('my_key')->isHit(), 'Stored item is successfully retrieved.'); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php deleted file mode 100644 index 11907a03..00000000 --- a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php +++ /dev/null @@ -1,338 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Cache\CacheItemInterface; -use Symfony\Component\Cache\Adapter\AdapterInterface; -use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; -use Symfony\Component\Cache\Adapter\TagAwareAdapter; - -/** - * @group time-sensitive - */ -class TagAwareAdapterTest extends AdapterTestCase -{ - public function createCachePool($defaultLifetime = 0) - { - return new TagAwareAdapter(new FilesystemAdapter('', $defaultLifetime)); - } - - public static function tearDownAfterClass() - { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - - public function testInvalidTag() - { - $this->expectException('Psr\Cache\InvalidArgumentException'); - $pool = $this->createCachePool(); - $item = $pool->getItem('foo'); - $item->tag(':'); - } - - public function testInvalidateTags() - { - $pool = $this->createCachePool(); - - $i0 = $pool->getItem('i0'); - $i1 = $pool->getItem('i1'); - $i2 = $pool->getItem('i2'); - $i3 = $pool->getItem('i3'); - $foo = $pool->getItem('foo'); - - $pool->save($i0->tag('bar')); - $pool->save($i1->tag('foo')); - $pool->save($i2->tag('foo')->tag('bar')); - $pool->save($i3->tag('foo')->tag('baz')); - $pool->save($foo); - - $pool->invalidateTags(['bar']); - - $this->assertFalse($pool->getItem('i0')->isHit()); - $this->assertTrue($pool->getItem('i1')->isHit()); - $this->assertFalse($pool->getItem('i2')->isHit()); - $this->assertTrue($pool->getItem('i3')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - $pool->invalidateTags(['foo']); - - $this->assertFalse($pool->getItem('i1')->isHit()); - $this->assertFalse($pool->getItem('i3')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - $anotherPoolInstance = $this->createCachePool(); - - $this->assertFalse($anotherPoolInstance->getItem('i1')->isHit()); - $this->assertFalse($anotherPoolInstance->getItem('i3')->isHit()); - $this->assertTrue($anotherPoolInstance->getItem('foo')->isHit()); - } - - public function testInvalidateCommits() - { - $pool1 = $this->createCachePool(); - - $foo = $pool1->getItem('foo'); - $foo->tag('tag'); - - $pool1->saveDeferred($foo->set('foo')); - $pool1->invalidateTags(['tag']); - - $pool2 = $this->createCachePool(); - $foo = $pool2->getItem('foo'); - - $this->assertTrue($foo->isHit()); - } - - public function testTagsAreCleanedOnSave() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $pool->save($i->tag('bar')); - - $pool->invalidateTags(['foo']); - $this->assertTrue($pool->getItem('k')->isHit()); - } - - public function testTagsAreCleanedOnDelete() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - $pool->deleteItem('k'); - - $pool->save($pool->getItem('k')); - $pool->invalidateTags(['foo']); - - $this->assertTrue($pool->getItem('k')->isHit()); - } - - public function testTagItemExpiry() - { - $pool = $this->createCachePool(10); - - $item = $pool->getItem('foo'); - $item->tag(['baz']); - $item->expiresAfter(100); - - $pool->save($item); - $pool->invalidateTags(['baz']); - $this->assertFalse($pool->getItem('foo')->isHit()); - - sleep(20); - - $this->assertFalse($pool->getItem('foo')->isHit()); - } - - public function testGetPreviousTags() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $this->assertSame(['foo' => 'foo'], $i->getPreviousTags()); - } - - public function testPrune() - { - $cache = new TagAwareAdapter($this->getPruneableMock()); - $this->assertTrue($cache->prune()); - - $cache = new TagAwareAdapter($this->getNonPruneableMock()); - $this->assertFalse($cache->prune()); - - $cache = new TagAwareAdapter($this->getFailingPruneableMock()); - $this->assertFalse($cache->prune()); - } - - public function testKnownTagVersionsTtl() - { - $itemsPool = new FilesystemAdapter('', 10); - $tagsPool = $this - ->getMockBuilder(AdapterInterface::class) - ->getMock(); - - $pool = new TagAwareAdapter($itemsPool, $tagsPool, 10); - - $item = $pool->getItem('foo'); - $item->tag(['baz']); - $item->expiresAfter(100); - - $tag = $this->getMockBuilder(CacheItemInterface::class)->getMock(); - $tag->expects(self::exactly(2))->method('get')->willReturn(10); - - $tagsPool->expects(self::exactly(2))->method('getItems')->willReturn([ - 'baz'.TagAwareAdapter::TAGS_PREFIX => $tag, - ]); - - $pool->save($item); - $this->assertTrue($pool->getItem('foo')->isHit()); - $this->assertTrue($pool->getItem('foo')->isHit()); - - sleep(20); - - $this->assertTrue($pool->getItem('foo')->isHit()); - - sleep(5); - - $this->assertTrue($pool->getItem('foo')->isHit()); - } - - public function testTagEntryIsCreatedForItemWithoutTags() - { - $pool = $this->createCachePool(); - - $itemKey = 'foo'; - $item = $pool->getItem($itemKey); - $pool->save($item); - - $adapter = new FilesystemAdapter(); - $this->assertTrue($adapter->hasItem(TagAwareAdapter::TAGS_PREFIX.$itemKey)); - } - - public function testHasItemReturnsFalseWhenPoolDoesNotHaveItemTags() - { - $pool = $this->createCachePool(); - - $itemKey = 'foo'; - $item = $pool->getItem($itemKey); - $pool->save($item); - - $anotherPool = $this->createCachePool(); - - $adapter = new FilesystemAdapter(); - $adapter->deleteItem(TagAwareAdapter::TAGS_PREFIX.$itemKey); //simulate item losing tags pair - - $this->assertFalse($anotherPool->hasItem($itemKey)); - } - - public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemTags() - { - $pool = $this->createCachePool(); - - $itemKey = 'foo'; - $item = $pool->getItem($itemKey); - $pool->save($item); - - $anotherPool = $this->createCachePool(); - - $adapter = new FilesystemAdapter(); - $adapter->deleteItem(TagAwareAdapter::TAGS_PREFIX.$itemKey); //simulate item losing tags pair - - $item = $anotherPool->getItem($itemKey); - $this->assertFalse($item->isHit()); - } - - public function testHasItemReturnsFalseWhenPoolDoesNotHaveItemAndOnlyHasTags() - { - $pool = $this->createCachePool(); - - $itemKey = 'foo'; - $item = $pool->getItem($itemKey); - $pool->save($item); - - $anotherPool = $this->createCachePool(); - - $adapter = new FilesystemAdapter(); - $adapter->deleteItem($itemKey); //simulate losing item but keeping tags - - $this->assertFalse($anotherPool->hasItem($itemKey)); - } - - public function testInvalidateTagsWithArrayAdapter() - { - $adapter = new TagAwareAdapter(new ArrayAdapter()); - - $item = $adapter->getItem('foo'); - - $this->assertFalse($item->isHit()); - - $item->tag('bar'); - $item->expiresAfter(100); - $adapter->save($item); - - $this->assertTrue($adapter->getItem('foo')->isHit()); - - $adapter->invalidateTags(['bar']); - - $this->assertFalse($adapter->getItem('foo')->isHit()); - } - - public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags() - { - $pool = $this->createCachePool(); - - $itemKey = 'foo'; - $item = $pool->getItem($itemKey); - $pool->save($item); - - $anotherPool = $this->createCachePool(); - - $adapter = new FilesystemAdapter(); - $adapter->deleteItem($itemKey); //simulate losing item but keeping tags - - $item = $anotherPool->getItem($itemKey); - $this->assertFalse($item->isHit()); - } - - /** - * @return MockObject|PruneableCacheInterface - */ - private function getPruneableMock() - { - $pruneable = $this - ->getMockBuilder(PruneableCacheInterface::class) - ->getMock(); - - $pruneable - ->expects($this->atLeastOnce()) - ->method('prune') - ->willReturn(true); - - return $pruneable; - } - - /** - * @return MockObject|PruneableCacheInterface - */ - private function getFailingPruneableMock() - { - $pruneable = $this - ->getMockBuilder(PruneableCacheInterface::class) - ->getMock(); - - $pruneable - ->expects($this->atLeastOnce()) - ->method('prune') - ->willReturn(false); - - return $pruneable; - } - - /** - * @return MockObject|AdapterInterface - */ - private function getNonPruneableMock() - { - return $this - ->getMockBuilder(AdapterInterface::class) - ->getMock(); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php b/vendor/symfony/cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php deleted file mode 100644 index b11c1f28..00000000 --- a/vendor/symfony/cache/Tests/Adapter/TagAwareAndProxyAdapterIntegrationTest.php +++ /dev/null @@ -1,38 +0,0 @@ -getItem('foo'); - $item->tag(['tag1', 'tag2']); - $item->set('bar'); - $cache->save($item); - - $this->assertSame('bar', $cache->getItem('foo')->get()); - } - - public function dataProvider() - { - return [ - [new ArrayAdapter()], - // also testing with a non-AdapterInterface implementation - // because the ProxyAdapter behaves slightly different for those - [new ExternalAdapter()], - ]; - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/TraceableAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/TraceableAdapterTest.php deleted file mode 100644 index 35eba7d7..00000000 --- a/vendor/symfony/cache/Tests/Adapter/TraceableAdapterTest.php +++ /dev/null @@ -1,191 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\FilesystemAdapter; -use Symfony\Component\Cache\Adapter\TraceableAdapter; - -/** - * @group time-sensitive - */ -class TraceableAdapterTest extends AdapterTestCase -{ - protected $skippedTests = [ - 'testPrune' => 'TraceableAdapter just proxies', - ]; - - public function createCachePool($defaultLifetime = 0) - { - return new TraceableAdapter(new FilesystemAdapter('', $defaultLifetime)); - } - - public function testGetItemMissTrace() - { - $pool = $this->createCachePool(); - $pool->getItem('k'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('getItem', $call->name); - $this->assertSame(['k' => false], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(1, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testGetItemHitTrace() - { - $pool = $this->createCachePool(); - $item = $pool->getItem('k')->set('foo'); - $pool->save($item); - $pool->getItem('k'); - $calls = $pool->getCalls(); - $this->assertCount(3, $calls); - - $call = $calls[2]; - $this->assertSame(1, $call->hits); - $this->assertSame(0, $call->misses); - } - - public function testGetItemsMissTrace() - { - $pool = $this->createCachePool(); - $arg = ['k0', 'k1']; - $items = $pool->getItems($arg); - foreach ($items as $item) { - } - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('getItems', $call->name); - $this->assertSame(['k0' => false, 'k1' => false], $call->result); - $this->assertSame(2, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testHasItemMissTrace() - { - $pool = $this->createCachePool(); - $pool->hasItem('k'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('hasItem', $call->name); - $this->assertSame(['k' => false], $call->result); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testHasItemHitTrace() - { - $pool = $this->createCachePool(); - $item = $pool->getItem('k')->set('foo'); - $pool->save($item); - $pool->hasItem('k'); - $calls = $pool->getCalls(); - $this->assertCount(3, $calls); - - $call = $calls[2]; - $this->assertSame('hasItem', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testDeleteItemTrace() - { - $pool = $this->createCachePool(); - $pool->deleteItem('k'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('deleteItem', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testDeleteItemsTrace() - { - $pool = $this->createCachePool(); - $arg = ['k0', 'k1']; - $pool->deleteItems($arg); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('deleteItems', $call->name); - $this->assertSame(['keys' => $arg, 'result' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testSaveTrace() - { - $pool = $this->createCachePool(); - $item = $pool->getItem('k')->set('foo'); - $pool->save($item); - $calls = $pool->getCalls(); - $this->assertCount(2, $calls); - - $call = $calls[1]; - $this->assertSame('save', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testSaveDeferredTrace() - { - $pool = $this->createCachePool(); - $item = $pool->getItem('k')->set('foo'); - $pool->saveDeferred($item); - $calls = $pool->getCalls(); - $this->assertCount(2, $calls); - - $call = $calls[1]; - $this->assertSame('saveDeferred', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testCommitTrace() - { - $pool = $this->createCachePool(); - $pool->commit(); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('commit', $call->name); - $this->assertTrue($call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } -} diff --git a/vendor/symfony/cache/Tests/Adapter/TraceableTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/TraceableTagAwareAdapterTest.php deleted file mode 100644 index 5cd4185c..00000000 --- a/vendor/symfony/cache/Tests/Adapter/TraceableTagAwareAdapterTest.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Adapter; - -use Symfony\Component\Cache\Adapter\FilesystemAdapter; -use Symfony\Component\Cache\Adapter\TagAwareAdapter; -use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter; - -/** - * @group time-sensitive - */ -class TraceableTagAwareAdapterTest extends TraceableAdapterTest -{ - public function testInvalidateTags() - { - $pool = new TraceableTagAwareAdapter(new TagAwareAdapter(new FilesystemAdapter())); - $pool->invalidateTags(['foo']); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('invalidateTags', $call->name); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } -} diff --git a/vendor/symfony/cache/Tests/CacheItemTest.php b/vendor/symfony/cache/Tests/CacheItemTest.php deleted file mode 100644 index 28c681d1..00000000 --- a/vendor/symfony/cache/Tests/CacheItemTest.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Cache\CacheItem; - -class CacheItemTest extends TestCase -{ - public function testValidKey() - { - $this->assertSame('foo', CacheItem::validateKey('foo')); - } - - /** - * @dataProvider provideInvalidKey - */ - public function testInvalidKey($key) - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Cache key'); - CacheItem::validateKey($key); - } - - public function provideInvalidKey() - { - return [ - [''], - ['{'], - ['}'], - ['('], - [')'], - ['/'], - ['\\'], - ['@'], - [':'], - [true], - [null], - [1], - [1.1], - [[[]]], - [new \Exception('foo')], - ]; - } - - public function testTag() - { - $item = new CacheItem(); - - $this->assertSame($item, $item->tag('foo')); - $this->assertSame($item, $item->tag(['bar', 'baz'])); - - \call_user_func(\Closure::bind(function () use ($item) { - $this->assertSame(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'], $item->tags); - }, $this, CacheItem::class)); - } - - /** - * @dataProvider provideInvalidKey - */ - public function testInvalidTag($tag) - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Cache tag'); - $item = new CacheItem(); - $item->tag($tag); - } -} diff --git a/vendor/symfony/cache/Tests/DoctrineProviderTest.php b/vendor/symfony/cache/Tests/DoctrineProviderTest.php deleted file mode 100644 index 91a5516a..00000000 --- a/vendor/symfony/cache/Tests/DoctrineProviderTest.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests; - -use Doctrine\Common\Cache\CacheProvider; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\Cache\DoctrineProvider; - -class DoctrineProviderTest extends TestCase -{ - public function testProvider() - { - $pool = new ArrayAdapter(); - $cache = new DoctrineProvider($pool); - - $this->assertInstanceOf(CacheProvider::class, $cache); - - $key = '{}()/\@:'; - - $this->assertTrue($cache->delete($key)); - $this->assertFalse($cache->contains($key)); - - $this->assertTrue($cache->save($key, 'bar')); - $this->assertTrue($cache->contains($key)); - $this->assertSame('bar', $cache->fetch($key)); - - $this->assertTrue($cache->delete($key)); - $this->assertFalse($cache->fetch($key)); - $this->assertTrue($cache->save($key, 'bar')); - - $cache->flushAll(); - $this->assertFalse($cache->fetch($key)); - $this->assertFalse($cache->contains($key)); - } -} diff --git a/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php b/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php deleted file mode 100644 index 13b4f330..00000000 --- a/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php +++ /dev/null @@ -1,52 +0,0 @@ -doContains($id) ? $this->data[$id][0] : false; - } - - protected function doContains($id) - { - if (!isset($this->data[$id])) { - return false; - } - - $expiry = $this->data[$id][1]; - - return !$expiry || time() < $expiry || !$this->doDelete($id); - } - - protected function doSave($id, $data, $lifeTime = 0) - { - $this->data[$id] = [$data, $lifeTime ? time() + $lifeTime : false]; - - return true; - } - - protected function doDelete($id) - { - unset($this->data[$id]); - - return true; - } - - protected function doFlush() - { - $this->data = []; - - return true; - } - - protected function doGetStats() - { - return null; - } -} diff --git a/vendor/symfony/cache/Tests/Fixtures/ExternalAdapter.php b/vendor/symfony/cache/Tests/Fixtures/ExternalAdapter.php deleted file mode 100644 index be1f9901..00000000 --- a/vendor/symfony/cache/Tests/Fixtures/ExternalAdapter.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Fixtures; - -use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\Adapter\ArrayAdapter; - -/** - * Adapter not implementing the {@see \Symfony\Component\Cache\Adapter\AdapterInterface}. - * - * @author Kévin Dunglas - */ -class ExternalAdapter implements CacheItemPoolInterface -{ - private $cache; - - public function __construct($defaultLifetime = 0) - { - $this->cache = new ArrayAdapter($defaultLifetime); - } - - public function getItem($key) - { - return $this->cache->getItem($key); - } - - public function getItems(array $keys = []) - { - return $this->cache->getItems($keys); - } - - public function hasItem($key) - { - return $this->cache->hasItem($key); - } - - public function clear() - { - return $this->cache->clear(); - } - - public function deleteItem($key) - { - return $this->cache->deleteItem($key); - } - - public function deleteItems(array $keys) - { - return $this->cache->deleteItems($keys); - } - - public function save(CacheItemInterface $item) - { - return $this->cache->save($item); - } - - public function saveDeferred(CacheItemInterface $item) - { - return $this->cache->saveDeferred($item); - } - - public function commit() - { - return $this->cache->commit(); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php b/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php deleted file mode 100644 index 7a6cabe8..00000000 --- a/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\RedisCache; - -abstract class AbstractRedisCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testSetTtl' => 'Testing expiration slows down the test suite', - 'testSetMultipleTtl' => 'Testing expiration slows down the test suite', - 'testDefaultLifeTime' => 'Testing expiration slows down the test suite', - ]; - - protected static $redis; - - public function createSimpleCache($defaultLifetime = 0) - { - return new RedisCache(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); - } - - public static function setUpBeforeClass() - { - if (!\extension_loaded('redis')) { - self::markTestSkipped('Extension redis required.'); - } - try { - (new \Redis())->connect(getenv('REDIS_HOST')); - } catch (\Exception $e) { - self::markTestSkipped($e->getMessage()); - } - } - - public static function tearDownAfterClass() - { - self::$redis = null; - } -} diff --git a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php deleted file mode 100644 index fad0c043..00000000 --- a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\ApcuCache; - -class ApcuCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testSetTtl' => 'Testing expiration slows down the test suite', - 'testSetMultipleTtl' => 'Testing expiration slows down the test suite', - 'testDefaultLifeTime' => 'Testing expiration slows down the test suite', - ]; - - public function createSimpleCache($defaultLifetime = 0) - { - if (!\function_exists('apcu_fetch') || !filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) || ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN))) { - $this->markTestSkipped('APCu extension is required.'); - } - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Fails transiently on Windows.'); - } - - return new ApcuCache(str_replace('\\', '.', __CLASS__), $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php deleted file mode 100644 index 26c3e14d..00000000 --- a/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\ArrayCache; - -/** - * @group time-sensitive - */ -class ArrayCacheTest extends CacheTestCase -{ - public function createSimpleCache($defaultLifetime = 0) - { - return new ArrayCache($defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php deleted file mode 100644 index ff9944a3..00000000 --- a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php +++ /dev/null @@ -1,150 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Cache\IntegrationTests\SimpleCacheTest; -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\PruneableInterface; - -abstract class CacheTestCase extends SimpleCacheTest -{ - protected function setUp() - { - parent::setUp(); - - if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createSimpleCache() instanceof PruneableInterface) { - $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; - } - } - - public static function validKeys() - { - if (\defined('HHVM_VERSION')) { - return parent::validKeys(); - } - - return array_merge(parent::validKeys(), [["a\0b"]]); - } - - public function testDefaultLifeTime() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = $this->createSimpleCache(2); - $cache->clear(); - - $cache->set('key.dlt', 'value'); - sleep(1); - - $this->assertSame('value', $cache->get('key.dlt')); - - sleep(2); - $this->assertNull($cache->get('key.dlt')); - - $cache->clear(); - } - - public function testNotUnserializable() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = $this->createSimpleCache(); - $cache->clear(); - - $cache->set('foo', new NotUnserializable()); - - $this->assertNull($cache->get('foo')); - - $cache->setMultiple(['foo' => new NotUnserializable()]); - - foreach ($cache->getMultiple(['foo']) as $value) { - } - $this->assertNull($value); - - $cache->clear(); - } - - public function testPrune() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - if (!method_exists($this, 'isPruned')) { - $this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.'); - } - - /** @var PruneableInterface|CacheInterface $cache */ - $cache = $this->createSimpleCache(); - $cache->clear(); - - $cache->set('foo', 'foo-val', new \DateInterval('PT05S')); - $cache->set('bar', 'bar-val', new \DateInterval('PT10S')); - $cache->set('baz', 'baz-val', new \DateInterval('PT15S')); - $cache->set('qux', 'qux-val', new \DateInterval('PT20S')); - - sleep(30); - $cache->prune(); - $this->assertTrue($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'bar')); - $this->assertTrue($this->isPruned($cache, 'baz')); - $this->assertTrue($this->isPruned($cache, 'qux')); - - $cache->set('foo', 'foo-val'); - $cache->set('bar', 'bar-val', new \DateInterval('PT20S')); - $cache->set('baz', 'baz-val', new \DateInterval('PT40S')); - $cache->set('qux', 'qux-val', new \DateInterval('PT80S')); - - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertFalse($this->isPruned($cache, 'bar')); - $this->assertFalse($this->isPruned($cache, 'baz')); - $this->assertFalse($this->isPruned($cache, 'qux')); - - sleep(30); - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'bar')); - $this->assertFalse($this->isPruned($cache, 'baz')); - $this->assertFalse($this->isPruned($cache, 'qux')); - - sleep(30); - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'baz')); - $this->assertFalse($this->isPruned($cache, 'qux')); - - sleep(30); - $cache->prune(); - $this->assertFalse($this->isPruned($cache, 'foo')); - $this->assertTrue($this->isPruned($cache, 'qux')); - - $cache->clear(); - } -} - -class NotUnserializable implements \Serializable -{ - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) - { - throw new \Exception(__CLASS__); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php b/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php deleted file mode 100644 index f216bc1f..00000000 --- a/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use PHPUnit\Framework\MockObject\MockObject; -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\Simple\ArrayCache; -use Symfony\Component\Cache\Simple\ChainCache; -use Symfony\Component\Cache\Simple\FilesystemCache; - -/** - * @group time-sensitive - */ -class ChainCacheTest extends CacheTestCase -{ - public function createSimpleCache($defaultLifetime = 0) - { - return new ChainCache([new ArrayCache($defaultLifetime), new FilesystemCache('', $defaultLifetime)], $defaultLifetime); - } - - public function testEmptyCachesException() - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('At least one cache must be specified.'); - new ChainCache([]); - } - - public function testInvalidCacheException() - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The class "stdClass" does not implement'); - new ChainCache([new \stdClass()]); - } - - public function testPrune() - { - if (isset($this->skippedTests[__FUNCTION__])) { - $this->markTestSkipped($this->skippedTests[__FUNCTION__]); - } - - $cache = new ChainCache([ - $this->getPruneableMock(), - $this->getNonPruneableMock(), - $this->getPruneableMock(), - ]); - $this->assertTrue($cache->prune()); - - $cache = new ChainCache([ - $this->getPruneableMock(), - $this->getFailingPruneableMock(), - $this->getPruneableMock(), - ]); - $this->assertFalse($cache->prune()); - } - - /** - * @return MockObject|PruneableCacheInterface - */ - private function getPruneableMock() - { - $pruneable = $this - ->getMockBuilder(PruneableCacheInterface::class) - ->getMock(); - - $pruneable - ->expects($this->atLeastOnce()) - ->method('prune') - ->willReturn(true); - - return $pruneable; - } - - /** - * @return MockObject|PruneableCacheInterface - */ - private function getFailingPruneableMock() - { - $pruneable = $this - ->getMockBuilder(PruneableCacheInterface::class) - ->getMock(); - - $pruneable - ->expects($this->atLeastOnce()) - ->method('prune') - ->willReturn(false); - - return $pruneable; - } - - /** - * @return MockObject|CacheInterface - */ - private function getNonPruneableMock() - { - return $this - ->getMockBuilder(CacheInterface::class) - ->getMock(); - } -} - -interface PruneableCacheInterface extends PruneableInterface, CacheInterface -{ -} diff --git a/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php b/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php deleted file mode 100644 index af4331d6..00000000 --- a/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\DoctrineCache; -use Symfony\Component\Cache\Tests\Fixtures\ArrayCache; - -/** - * @group time-sensitive - */ -class DoctrineCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testObjectDoesNotChangeInCache' => 'ArrayCache does not use serialize/unserialize', - 'testNotUnserializable' => 'ArrayCache does not use serialize/unserialize', - ]; - - public function createSimpleCache($defaultLifetime = 0) - { - return new DoctrineCache(new ArrayCache($defaultLifetime), '', $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php b/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php deleted file mode 100644 index 620305a5..00000000 --- a/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\Simple\FilesystemCache; - -/** - * @group time-sensitive - */ -class FilesystemCacheTest extends CacheTestCase -{ - public function createSimpleCache($defaultLifetime = 0) - { - return new FilesystemCache('', $defaultLifetime); - } - - protected function isPruned(CacheInterface $cache, $name) - { - $getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile'); - $getFileMethod->setAccessible(true); - - return !file_exists($getFileMethod->invoke($cache, $name)); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php deleted file mode 100644 index 6df682e9..00000000 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php +++ /dev/null @@ -1,178 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Adapter\AbstractAdapter; -use Symfony\Component\Cache\Simple\MemcachedCache; - -class MemcachedCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testSetTtl' => 'Testing expiration slows down the test suite', - 'testSetMultipleTtl' => 'Testing expiration slows down the test suite', - 'testDefaultLifeTime' => 'Testing expiration slows down the test suite', - ]; - - protected static $client; - - public static function setUpBeforeClass() - { - if (!MemcachedCache::isSupported()) { - self::markTestSkipped('Extension memcached >=2.2.0 required.'); - } - self::$client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST')); - self::$client->get('foo'); - $code = self::$client->getResultCode(); - - if (\Memcached::RES_SUCCESS !== $code && \Memcached::RES_NOTFOUND !== $code) { - self::markTestSkipped('Memcached error: '.strtolower(self::$client->getResultMessage())); - } - } - - public function createSimpleCache($defaultLifetime = 0) - { - $client = $defaultLifetime ? AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]) : self::$client; - - return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime); - } - - public function testCreatePersistentConnectionShouldNotDupServerList() - { - $instance = MemcachedCache::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['persistent_id' => 'persistent']); - $this->assertCount(1, $instance->getServerList()); - - $instance = MemcachedCache::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['persistent_id' => 'persistent']); - $this->assertCount(1, $instance->getServerList()); - } - - public function testOptions() - { - $client = MemcachedCache::createConnection([], [ - 'libketama_compatible' => false, - 'distribution' => 'modula', - 'compression' => true, - 'serializer' => 'php', - 'hash' => 'md5', - ]); - - $this->assertSame(\Memcached::SERIALIZER_PHP, $client->getOption(\Memcached::OPT_SERIALIZER)); - $this->assertSame(\Memcached::HASH_MD5, $client->getOption(\Memcached::OPT_HASH)); - $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION)); - $this->assertSame(0, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE)); - $this->assertSame(\Memcached::DISTRIBUTION_MODULA, $client->getOption(\Memcached::OPT_DISTRIBUTION)); - } - - /** - * @dataProvider provideBadOptions - */ - public function testBadOptions($name, $value) - { - if (\PHP_VERSION_ID < 80000) { - $this->expectException('ErrorException'); - $this->expectExceptionMessage('constant(): Couldn\'t find constant Memcached::'); - } else { - $this->expectException('Error'); - $this->expectExceptionMessage('Undefined constant Memcached::'); - } - - MemcachedCache::createConnection([], [$name => $value]); - } - - public function provideBadOptions() - { - return [ - ['foo', 'bar'], - ['hash', 'zyx'], - ['serializer', 'zyx'], - ['distribution', 'zyx'], - ]; - } - - public function testDefaultOptions() - { - $this->assertTrue(MemcachedCache::isSupported()); - - $client = MemcachedCache::createConnection([]); - - $this->assertTrue($client->getOption(\Memcached::OPT_COMPRESSION)); - $this->assertSame(1, $client->getOption(\Memcached::OPT_BINARY_PROTOCOL)); - $this->assertSame(1, $client->getOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE)); - } - - public function testOptionSerializer() - { - $this->expectException('Symfony\Component\Cache\Exception\CacheException'); - $this->expectExceptionMessage('MemcachedAdapter: "serializer" option must be "php" or "igbinary".'); - if (!\Memcached::HAVE_JSON) { - $this->markTestSkipped('Memcached::HAVE_JSON required'); - } - - new MemcachedCache(MemcachedCache::createConnection([], ['serializer' => 'json'])); - } - - /** - * @dataProvider provideServersSetting - */ - public function testServersSetting($dsn, $host, $port) - { - $client1 = MemcachedCache::createConnection($dsn); - $client2 = MemcachedCache::createConnection([$dsn]); - $client3 = MemcachedCache::createConnection([[$host, $port]]); - $expect = [ - 'host' => $host, - 'port' => $port, - ]; - - $f = function ($s) { return ['host' => $s['host'], 'port' => $s['port']]; }; - $this->assertSame([$expect], array_map($f, $client1->getServerList())); - $this->assertSame([$expect], array_map($f, $client2->getServerList())); - $this->assertSame([$expect], array_map($f, $client3->getServerList())); - } - - public function provideServersSetting() - { - yield [ - 'memcached://127.0.0.1/50', - '127.0.0.1', - 11211, - ]; - yield [ - 'memcached://localhost:11222?weight=25', - 'localhost', - 11222, - ]; - if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) { - yield [ - 'memcached://user:password@127.0.0.1?weight=50', - '127.0.0.1', - 11211, - ]; - } - yield [ - 'memcached:///var/run/memcached.sock?weight=25', - '/var/run/memcached.sock', - 0, - ]; - yield [ - 'memcached:///var/local/run/memcached.socket?weight=25', - '/var/local/run/memcached.socket', - 0, - ]; - if (filter_var(ini_get('memcached.use_sasl'), \FILTER_VALIDATE_BOOLEAN)) { - yield [ - 'memcached://user:password@/var/local/run/memcached.socket?weight=25', - '/var/local/run/memcached.socket', - 0, - ]; - } - } -} diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php deleted file mode 100644 index 13865a60..00000000 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Adapter\AbstractAdapter; -use Symfony\Component\Cache\Simple\MemcachedCache; - -class MemcachedCacheTextModeTest extends MemcachedCacheTest -{ - public function createSimpleCache($defaultLifetime = 0) - { - $client = AbstractAdapter::createConnection('memcached://'.getenv('MEMCACHED_HOST'), ['binary_protocol' => false]); - - return new MemcachedCache($client, str_replace('\\', '.', __CLASS__), $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/NullCacheTest.php b/vendor/symfony/cache/Tests/Simple/NullCacheTest.php deleted file mode 100644 index 31f42c32..00000000 --- a/vendor/symfony/cache/Tests/Simple/NullCacheTest.php +++ /dev/null @@ -1,96 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Cache\Simple\NullCache; - -/** - * @group time-sensitive - */ -class NullCacheTest extends TestCase -{ - public function createCachePool() - { - return new NullCache(); - } - - public function testGetItem() - { - $cache = $this->createCachePool(); - - $this->assertNull($cache->get('key')); - } - - public function testHas() - { - $this->assertFalse($this->createCachePool()->has('key')); - } - - public function testGetMultiple() - { - $cache = $this->createCachePool(); - - $keys = ['foo', 'bar', 'baz', 'biz']; - - $default = new \stdClass(); - $items = $cache->getMultiple($keys, $default); - $count = 0; - - foreach ($items as $key => $item) { - $this->assertContains($key, $keys, 'Cache key can not change.'); - $this->assertSame($default, $item); - - // Remove $key for $keys - foreach ($keys as $k => $v) { - if ($v === $key) { - unset($keys[$k]); - } - } - - ++$count; - } - - $this->assertSame(4, $count); - } - - public function testClear() - { - $this->assertTrue($this->createCachePool()->clear()); - } - - public function testDelete() - { - $this->assertTrue($this->createCachePool()->delete('key')); - } - - public function testDeleteMultiple() - { - $this->assertTrue($this->createCachePool()->deleteMultiple(['key', 'foo', 'bar'])); - } - - public function testSet() - { - $cache = $this->createCachePool(); - - $this->assertFalse($cache->set('key', 'val')); - $this->assertNull($cache->get('key')); - } - - public function testSetMultiple() - { - $cache = $this->createCachePool(); - - $this->assertFalse($cache->setMultiple(['key' => 'val'])); - $this->assertNull($cache->get('key')); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php b/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php deleted file mode 100644 index f5a26341..00000000 --- a/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\PdoCache; -use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; - -/** - * @group time-sensitive - */ -class PdoCacheTest extends CacheTestCase -{ - use PdoPruneableTrait; - - protected static $dbFile; - - public static function setUpBeforeClass() - { - if (!\extension_loaded('pdo_sqlite')) { - self::markTestSkipped('Extension pdo_sqlite required.'); - } - - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); - - $pool = new PdoCache('sqlite:'.self::$dbFile); - $pool->createTable(); - } - - public static function tearDownAfterClass() - { - @unlink(self::$dbFile); - } - - public function createSimpleCache($defaultLifetime = 0) - { - return new PdoCache('sqlite:'.self::$dbFile, 'ns', $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php b/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php deleted file mode 100644 index 4da2b603..00000000 --- a/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Doctrine\DBAL\DriverManager; -use Symfony\Component\Cache\Simple\PdoCache; -use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; - -/** - * @group time-sensitive - */ -class PdoDbalCacheTest extends CacheTestCase -{ - use PdoPruneableTrait; - - protected static $dbFile; - - public static function setUpBeforeClass() - { - if (!\extension_loaded('pdo_sqlite')) { - self::markTestSkipped('Extension pdo_sqlite required.'); - } - - self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); - - $pool = new PdoCache(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile])); - $pool->createTable(); - } - - public static function tearDownAfterClass() - { - @unlink(self::$dbFile); - } - - public function createSimpleCache($defaultLifetime = 0) - { - return new PdoCache(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]), '', $defaultLifetime); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php deleted file mode 100644 index bcd7dea5..00000000 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php +++ /dev/null @@ -1,145 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\NullCache; -use Symfony\Component\Cache\Simple\PhpArrayCache; -use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest; - -/** - * @group time-sensitive - */ -class PhpArrayCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testBasicUsageWithLongKey' => 'PhpArrayCache does no writes', - - 'testDelete' => 'PhpArrayCache does no writes', - 'testDeleteMultiple' => 'PhpArrayCache does no writes', - 'testDeleteMultipleGenerator' => 'PhpArrayCache does no writes', - - 'testSetTtl' => 'PhpArrayCache does no expiration', - 'testSetMultipleTtl' => 'PhpArrayCache does no expiration', - 'testSetExpiredTtl' => 'PhpArrayCache does no expiration', - 'testSetMultipleExpiredTtl' => 'PhpArrayCache does no expiration', - - 'testGetInvalidKeys' => 'PhpArrayCache does no validation', - 'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation', - 'testSetInvalidKeys' => 'PhpArrayCache does no validation', - 'testDeleteInvalidKeys' => 'PhpArrayCache does no validation', - 'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation', - 'testSetInvalidTtl' => 'PhpArrayCache does no validation', - 'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation', - 'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation', - 'testHasInvalidKeys' => 'PhpArrayCache does no validation', - 'testSetValidData' => 'PhpArrayCache does no validation', - - 'testDefaultLifeTime' => 'PhpArrayCache does not allow configuring a default lifetime.', - 'testPrune' => 'PhpArrayCache just proxies', - ]; - - protected static $file; - - public static function setUpBeforeClass() - { - self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php'; - } - - protected function tearDown() - { - $this->createSimpleCache()->clear(); - - if (file_exists(sys_get_temp_dir().'/symfony-cache')) { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - } - - public function createSimpleCache() - { - return new PhpArrayCacheWrapper(self::$file, new NullCache()); - } - - public function testStore() - { - $arrayWithRefs = []; - $arrayWithRefs[0] = 123; - $arrayWithRefs[1] = &$arrayWithRefs[0]; - - $object = (object) [ - 'foo' => 'bar', - 'foo2' => 'bar2', - ]; - - $expected = [ - 'null' => null, - 'serializedString' => serialize($object), - 'arrayWithRefs' => $arrayWithRefs, - 'object' => $object, - 'arrayWithObject' => ['bar' => $object], - ]; - - $cache = new PhpArrayCache(self::$file, new NullCache()); - $cache->warmUp($expected); - - foreach ($expected as $key => $value) { - $this->assertSame(serialize($value), serialize($cache->get($key)), 'Warm up should create a PHP file that OPCache can load in memory'); - } - } - - public function testStoredFile() - { - $expected = [ - 'integer' => 42, - 'float' => 42.42, - 'boolean' => true, - 'array_simple' => ['foo', 'bar'], - 'array_associative' => ['foo' => 'bar', 'foo2' => 'bar2'], - ]; - - $cache = new PhpArrayCache(self::$file, new NullCache()); - $cache->warmUp($expected); - - $values = eval(substr(file_get_contents(self::$file), 6)); - - $this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory'); - } -} - -class PhpArrayCacheWrapper extends PhpArrayCache -{ - public function set($key, $value, $ttl = null) - { - \call_user_func(\Closure::bind(function () use ($key, $value) { - $this->values[$key] = $value; - $this->warmUp($this->values); - $this->values = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayCache::class)); - - return true; - } - - public function setMultiple($values, $ttl = null) - { - if (!\is_array($values) && !$values instanceof \Traversable) { - return parent::setMultiple($values, $ttl); - } - \call_user_func(\Closure::bind(function () use ($values) { - foreach ($values as $key => $value) { - $this->values[$key] = $value; - } - $this->warmUp($this->values); - $this->values = eval(substr(file_get_contents($this->file), 6)); - }, $this, PhpArrayCache::class)); - - return true; - } -} diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php deleted file mode 100644 index b08c1604..00000000 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\FilesystemCache; -use Symfony\Component\Cache\Simple\PhpArrayCache; -use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest; - -/** - * @group time-sensitive - */ -class PhpArrayCacheWithFallbackTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testGetInvalidKeys' => 'PhpArrayCache does no validation', - 'testGetMultipleInvalidKeys' => 'PhpArrayCache does no validation', - 'testDeleteInvalidKeys' => 'PhpArrayCache does no validation', - 'testDeleteMultipleInvalidKeys' => 'PhpArrayCache does no validation', - //'testSetValidData' => 'PhpArrayCache does no validation', - 'testSetInvalidKeys' => 'PhpArrayCache does no validation', - 'testSetInvalidTtl' => 'PhpArrayCache does no validation', - 'testSetMultipleInvalidKeys' => 'PhpArrayCache does no validation', - 'testSetMultipleInvalidTtl' => 'PhpArrayCache does no validation', - 'testHasInvalidKeys' => 'PhpArrayCache does no validation', - 'testPrune' => 'PhpArrayCache just proxies', - ]; - - protected static $file; - - public static function setUpBeforeClass() - { - self::$file = sys_get_temp_dir().'/symfony-cache/php-array-adapter-test.php'; - } - - protected function tearDown() - { - $this->createSimpleCache()->clear(); - - if (file_exists(sys_get_temp_dir().'/symfony-cache')) { - FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); - } - } - - public function createSimpleCache($defaultLifetime = 0) - { - return new PhpArrayCache(self::$file, new FilesystemCache('php-array-fallback', $defaultLifetime)); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php deleted file mode 100644 index 936f29a4..00000000 --- a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\Simple\PhpFilesCache; - -/** - * @group time-sensitive - */ -class PhpFilesCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testDefaultLifeTime' => 'PhpFilesCache does not allow configuring a default lifetime.', - ]; - - public function createSimpleCache() - { - if (!PhpFilesCache::isSupported()) { - $this->markTestSkipped('OPcache extension is not enabled.'); - } - - return new PhpFilesCache('sf-cache'); - } - - protected function isPruned(CacheInterface $cache, $name) - { - $getFileMethod = (new \ReflectionObject($cache))->getMethod('getFile'); - $getFileMethod->setAccessible(true); - - return !file_exists($getFileMethod->invoke($cache, $name)); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php deleted file mode 100644 index 1bc75c90..00000000 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php +++ /dev/null @@ -1,30 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Adapter\FilesystemAdapter; -use Symfony\Component\Cache\Simple\Psr6Cache; - -/** - * @group time-sensitive - */ -class Psr6CacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testPrune' => 'Psr6Cache just proxies', - ]; - - public function createSimpleCache($defaultLifetime = 0) - { - return new Psr6Cache(new FilesystemAdapter('', $defaultLifetime)); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php deleted file mode 100644 index ec5e4c06..00000000 --- a/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -class RedisArrayCacheTest extends AbstractRedisCacheTest -{ - public static function setUpBeforeClass() - { - parent::setupBeforeClass(); - if (!class_exists('RedisArray')) { - self::markTestSkipped('The RedisArray class is required.'); - } - self::$redis = new \RedisArray([getenv('REDIS_HOST')], ['lazy_connect' => true]); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php deleted file mode 100644 index 8e3f6088..00000000 --- a/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php +++ /dev/null @@ -1,82 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\RedisCache; - -class RedisCacheTest extends AbstractRedisCacheTest -{ - public static function setUpBeforeClass() - { - parent::setupBeforeClass(); - self::$redis = RedisCache::createConnection('redis://'.getenv('REDIS_HOST')); - } - - public function testCreateConnection() - { - $redisHost = getenv('REDIS_HOST'); - - $redis = RedisCache::createConnection('redis://'.$redisHost); - $this->assertInstanceOf(\Redis::class, $redis); - $this->assertTrue($redis->isConnected()); - $this->assertSame(0, $redis->getDbNum()); - - $redis = RedisCache::createConnection('redis://'.$redisHost.'/2'); - $this->assertSame(2, $redis->getDbNum()); - - $redis = RedisCache::createConnection('redis://'.$redisHost, ['timeout' => 3]); - $this->assertEquals(3, $redis->getTimeout()); - - $redis = RedisCache::createConnection('redis://'.$redisHost.'?timeout=4'); - $this->assertEquals(4, $redis->getTimeout()); - - $redis = RedisCache::createConnection('redis://'.$redisHost, ['read_timeout' => 5]); - $this->assertEquals(5, $redis->getReadTimeout()); - } - - /** - * @dataProvider provideFailedCreateConnection - */ - public function testFailedCreateConnection($dsn) - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Redis connection '); - RedisCache::createConnection($dsn); - } - - public function provideFailedCreateConnection() - { - return [ - ['redis://localhost:1234'], - ['redis://foo@localhost'], - ['redis://localhost/123'], - ]; - } - - /** - * @dataProvider provideInvalidCreateConnection - */ - public function testInvalidCreateConnection($dsn) - { - $this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid Redis DSN'); - RedisCache::createConnection($dsn); - } - - public function provideInvalidCreateConnection() - { - return [ - ['foo://localhost'], - ['redis://'], - ]; - } -} diff --git a/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php deleted file mode 100644 index 6b7f8039..00000000 --- a/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -class RedisClusterCacheTest extends AbstractRedisCacheTest -{ - public static function setUpBeforeClass() - { - if (!class_exists('RedisCluster')) { - self::markTestSkipped('The RedisCluster class is required.'); - } - if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { - self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); - } - - self::$redis = new \RedisCluster(null, explode(' ', $hosts)); - } -} diff --git a/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php b/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php deleted file mode 100644 index e684caf3..00000000 --- a/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php +++ /dev/null @@ -1,171 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Simple; - -use Symfony\Component\Cache\Simple\FilesystemCache; -use Symfony\Component\Cache\Simple\TraceableCache; - -/** - * @group time-sensitive - */ -class TraceableCacheTest extends CacheTestCase -{ - protected $skippedTests = [ - 'testPrune' => 'TraceableCache just proxies', - ]; - - public function createSimpleCache($defaultLifetime = 0) - { - return new TraceableCache(new FilesystemCache('', $defaultLifetime)); - } - - public function testGetMissTrace() - { - $pool = $this->createSimpleCache(); - $pool->get('k'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('get', $call->name); - $this->assertSame(['k' => false], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(1, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testGetHitTrace() - { - $pool = $this->createSimpleCache(); - $pool->set('k', 'foo'); - $pool->get('k'); - $calls = $pool->getCalls(); - $this->assertCount(2, $calls); - - $call = $calls[1]; - $this->assertSame(1, $call->hits); - $this->assertSame(0, $call->misses); - } - - public function testGetMultipleMissTrace() - { - $pool = $this->createSimpleCache(); - $pool->set('k1', 123); - $values = $pool->getMultiple(['k0', 'k1']); - foreach ($values as $value) { - } - $calls = $pool->getCalls(); - $this->assertCount(2, $calls); - - $call = $calls[1]; - $this->assertSame('getMultiple', $call->name); - $this->assertSame(['k1' => true, 'k0' => false], $call->result); - $this->assertSame(1, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testHasMissTrace() - { - $pool = $this->createSimpleCache(); - $pool->has('k'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('has', $call->name); - $this->assertSame(['k' => false], $call->result); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testHasHitTrace() - { - $pool = $this->createSimpleCache(); - $pool->set('k', 'foo'); - $pool->has('k'); - $calls = $pool->getCalls(); - $this->assertCount(2, $calls); - - $call = $calls[1]; - $this->assertSame('has', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testDeleteTrace() - { - $pool = $this->createSimpleCache(); - $pool->delete('k'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('delete', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testDeleteMultipleTrace() - { - $pool = $this->createSimpleCache(); - $arg = ['k0', 'k1']; - $pool->deleteMultiple($arg); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('deleteMultiple', $call->name); - $this->assertSame(['keys' => $arg, 'result' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testTraceSetTrace() - { - $pool = $this->createSimpleCache(); - $pool->set('k', 'foo'); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('set', $call->name); - $this->assertSame(['k' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } - - public function testSetMultipleTrace() - { - $pool = $this->createSimpleCache(); - $pool->setMultiple(['k' => 'foo']); - $calls = $pool->getCalls(); - $this->assertCount(1, $calls); - - $call = $calls[0]; - $this->assertSame('setMultiple', $call->name); - $this->assertSame(['keys' => ['k'], 'result' => true], $call->result); - $this->assertSame(0, $call->hits); - $this->assertSame(0, $call->misses); - $this->assertNotEmpty($call->start); - $this->assertNotEmpty($call->end); - } -} diff --git a/vendor/symfony/cache/Tests/Traits/PdoPruneableTrait.php b/vendor/symfony/cache/Tests/Traits/PdoPruneableTrait.php deleted file mode 100644 index c405de70..00000000 --- a/vendor/symfony/cache/Tests/Traits/PdoPruneableTrait.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Traits; - -trait PdoPruneableTrait -{ - protected function isPruned($cache, $name) - { - $o = new \ReflectionObject($cache); - - if (!$o->hasMethod('getConnection')) { - self::fail('Cache does not have "getConnection()" method.'); - } - - $getPdoConn = $o->getMethod('getConnection'); - $getPdoConn->setAccessible(true); - - /** @var \Doctrine\DBAL\Statement|\PDOStatement $select */ - $select = $getPdoConn->invoke($cache)->prepare('SELECT 1 FROM cache_items WHERE item_id LIKE :id'); - $select->bindValue(':id', sprintf('%%%s', $name)); - $result = $select->execute(); - - return 1 !== (int) (\is_object($result) ? $result->fetchOne() : $select->fetch(\PDO::FETCH_COLUMN)); - } -} diff --git a/vendor/symfony/cache/Traits/AbstractAdapterTrait.php b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php new file mode 100644 index 00000000..388c1df3 --- /dev/null +++ b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php @@ -0,0 +1,164 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait AbstractAdapterTrait +{ + use AbstractTrait; + + /** + * @var \Closure needs to be set by class, signature is function(string , mixed , bool ) + */ + private $createCacheItem; + + /** + * @var \Closure needs to be set by class, signature is function(array , string , array <&expiredIds>) + */ + private $mergeByLifetime; + + /** + * {@inheritdoc} + */ + public function getItem($key) + { + $id = $this->getId($key); + + if (isset($this->deferred[$key])) { + $this->commit(); + } + + $f = $this->createCacheItem; + $isHit = false; + $value = null; + + try { + foreach ($this->doFetch([$id]) as $value) { + $isHit = true; + } + + return $f($key, $value, $isHit); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); + } + + return $f($key, null, false); + } + + /** + * {@inheritdoc} + */ + public function getItems(array $keys = []) + { + $ids = []; + $commit = false; + + foreach ($keys as $key) { + $ids[] = $this->getId($key); + $commit = $commit || isset($this->deferred[$key]); + } + + if ($commit) { + $this->commit(); + } + + try { + $items = $this->doFetch($ids); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => $keys, 'exception' => $e]); + $items = []; + } + $ids = array_combine($ids, $keys); + + return $this->generateItems($items, $ids); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function save(CacheItemInterface $item) + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return $this->commit(); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function saveDeferred(CacheItemInterface $item) + { + if (!$item instanceof CacheItem) { + return false; + } + $this->deferred[$item->getKey()] = $item; + + return true; + } + + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + if ($this->deferred) { + $this->commit(); + } + } + + private function generateItems(iterable $items, array &$keys): iterable + { + $f = $this->createCacheItem; + + try { + foreach ($items as $id => $value) { + if (!isset($keys[$id])) { + throw new InvalidArgumentException(sprintf('Could not match value id "%s" to keys "%s".', $id, implode('", "', $keys))); + } + $key = $keys[$id]; + unset($keys[$id]); + yield $key => $f($key, $value, true); + } + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to fetch items: '.$e->getMessage(), ['keys' => array_values($keys), 'exception' => $e]); + } + + foreach ($keys as $key) { + yield $key => $f($key, null, false); + } + } +} diff --git a/vendor/symfony/cache/Traits/AbstractTrait.php b/vendor/symfony/cache/Traits/AbstractTrait.php index dc291e10..b0478806 100644 --- a/vendor/symfony/cache/Traits/AbstractTrait.php +++ b/vendor/symfony/cache/Traits/AbstractTrait.php @@ -27,6 +27,7 @@ trait AbstractTrait private $namespaceVersion = ''; private $versioningIsEnabled = false; private $deferred = []; + private $ids = []; /** * @var int|null The maximum length to enforce for identifiers or null when no limit applies @@ -77,10 +78,12 @@ abstract protected function doDelete(array $ids); * * @return array|bool The identifiers that failed to be cached or a boolean stating if caching succeeded or not */ - abstract protected function doSave(array $values, $lifetime); + abstract protected function doSave(array $values, int $lifetime); /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { @@ -93,7 +96,7 @@ public function hasItem($key) try { return $this->doHave($id); } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached', ['key' => $key, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to check if key "{key}" is cached: '.$e->getMessage(), ['key' => $key, 'exception' => $e]); return false; } @@ -101,26 +104,43 @@ public function hasItem($key) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { $this->deferred = []; if ($cleared = $this->versioningIsEnabled) { - $namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), static::NS_SEPARATOR, 5); + if ('' === $namespaceVersionToClear = $this->namespaceVersion) { + foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) { + $namespaceVersionToClear = $v; + } + } + $namespaceToClear = $this->namespace.$namespaceVersionToClear; + $namespaceVersion = self::formatNamespaceVersion(mt_rand()); try { - $cleared = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0); + $e = $this->doSave([static::NS_SEPARATOR.$this->namespace => $namespaceVersion], 0); } catch (\Exception $e) { - $cleared = false; } - if ($cleared = true === $cleared || [] === $cleared) { + if (true !== $e && [] !== $e) { + $cleared = false; + $message = 'Failed to save the new namespace'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['exception' => $e instanceof \Exception ? $e : null]); + } else { $this->namespaceVersion = $namespaceVersion; + $this->ids = []; } + } else { + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; + $namespaceToClear = $this->namespace.$prefix; } try { - return $this->doClear($this->namespace) || $cleared; + return $this->doClear($namespaceToClear) || $cleared; } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to clear the cache', ['exception' => $e]); + CacheItem::log($this->logger, 'Failed to clear the cache: '.$e->getMessage(), ['exception' => $e]); return false; } @@ -128,6 +148,8 @@ public function clear() /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { @@ -136,6 +158,8 @@ public function deleteItem($key) /** * {@inheritdoc} + * + * @return bool */ public function deleteItems(array $keys) { @@ -164,7 +188,8 @@ public function deleteItems(array $keys) } } catch (\Exception $e) { } - CacheItem::log($this->logger, 'Failed to delete key "{key}"', ['key' => $key, 'exception' => $e]); + $message = 'Failed to delete key "{key}"'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]); $ok = false; } @@ -188,6 +213,7 @@ public function enableVersioning($enable = true) $wasEnabled = $this->versioningIsEnabled; $this->versioningIsEnabled = (bool) $enable; $this->namespaceVersion = ''; + $this->ids = []; return $wasEnabled; } @@ -201,6 +227,7 @@ public function reset() $this->commit(); } $this->namespaceVersion = ''; + $this->ids = []; } /** @@ -211,9 +238,13 @@ public function reset() * @return mixed * * @throws \Exception + * + * @deprecated since Symfony 4.2, use DefaultMarshaller instead. */ protected static function unserialize($value) { + @trigger_error(sprintf('The "%s::unserialize()" method is deprecated since Symfony 4.2, use DefaultMarshaller instead.', __CLASS__), \E_USER_DEPRECATED); + if ('b:0;' === $value) { return false; } @@ -230,29 +261,45 @@ protected static function unserialize($value) } } - private function getId($key) + private function getId($key): string { - CacheItem::validateKey($key); - if ($this->versioningIsEnabled && '' === $this->namespaceVersion) { + $this->ids = []; $this->namespaceVersion = '1'.static::NS_SEPARATOR; try { foreach ($this->doFetch([static::NS_SEPARATOR.$this->namespace]) as $v) { $this->namespaceVersion = $v; } + $e = true; if ('1'.static::NS_SEPARATOR === $this->namespaceVersion) { - $this->namespaceVersion = substr_replace(base64_encode(pack('V', time())), static::NS_SEPARATOR, 5); - $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0); + $this->namespaceVersion = self::formatNamespaceVersion(time()); + $e = $this->doSave([static::NS_SEPARATOR.$this->namespace => $this->namespaceVersion], 0); } } catch (\Exception $e) { } + if (true !== $e && [] !== $e) { + $message = 'Failed to save the new namespace'.($e instanceof \Exception ? ': '.$e->getMessage() : '.'); + CacheItem::log($this->logger, $message, ['exception' => $e instanceof \Exception ? $e : null]); + } + } + + if (\is_string($key) && isset($this->ids[$key])) { + return $this->namespace.$this->namespaceVersion.$this->ids[$key]; + } + CacheItem::validateKey($key); + $this->ids[$key] = $key; + + if (\count($this->ids) > 1000) { + $this->ids = \array_slice($this->ids, 500, null, true); // stop memory leak if there are many keys } if (null === $this->maxIdLength) { return $this->namespace.$this->namespaceVersion.$key; } if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) { - $id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 22)); + // Use MD5 to favor speed over security, which is not an issue here + $this->ids[$key] = $id = substr_replace(base64_encode(hash('md5', $key, true)), static::NS_SEPARATOR, -(\strlen($this->namespaceVersion) + 2)); + $id = $this->namespace.$this->namespaceVersion.$id; } return $id; @@ -265,4 +312,9 @@ public static function handleUnserializeCallback($class) { throw new \DomainException('Class not found: '.$class); } + + private static function formatNamespaceVersion(int $value): string + { + return strtr(substr_replace(base64_encode(pack('V', $value)), static::NS_SEPARATOR, 5), '/', '_'); + } } diff --git a/vendor/symfony/cache/Traits/ApcuTrait.php b/vendor/symfony/cache/Traits/ApcuTrait.php index 2f47f8e6..46bd20fe 100644 --- a/vendor/symfony/cache/Traits/ApcuTrait.php +++ b/vendor/symfony/cache/Traits/ApcuTrait.php @@ -23,10 +23,10 @@ trait ApcuTrait { public static function isSupported() { - return \function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN); + return \function_exists('apcu_fetch') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN); } - private function init($namespace, $defaultLifetime, $version) + private function init(string $namespace, int $defaultLifetime, ?string $version) { if (!static::isSupported()) { throw new CacheException('APCu is not enabled.'); @@ -51,14 +51,27 @@ private function init($namespace, $defaultLifetime, $version) */ protected function doFetch(array $ids) { + $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); try { - foreach (apcu_fetch($ids, $ok) ?: [] as $k => $v) { + $values = []; + $ids = array_flip($ids); + foreach (apcu_fetch(array_keys($ids), $ok) ?: [] as $k => $v) { + if (!isset($ids[$k])) { + // work around https://github.com/krakjoe/apcu/issues/247 + $k = key($ids); + } + unset($ids[$k]); + if (null !== $v || $ok) { - yield $k => $v; + $values[$k] = $v; } } + + return $values; } catch (\Error $e) { throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine()); + } finally { + ini_set('unserialize_callback_func', $unserializeCallbackHandler); } } @@ -75,8 +88,8 @@ protected function doHave($id) */ protected function doClear($namespace) { - return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli' !== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) - ? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY)) + return isset($namespace[0]) && class_exists(\APCUIterator::class, false) && ('cli' !== \PHP_SAPI || filter_var(\ini_get('apc.enable_cli'), \FILTER_VALIDATE_BOOLEAN)) + ? apcu_delete(new \APCUIterator(sprintf('/^%s/', preg_quote($namespace, '/')), \APC_ITER_KEY)) : apcu_clear_cache(); } @@ -95,7 +108,7 @@ protected function doDelete(array $ids) /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { try { if (false === $failures = apcu_store($values, null, $lifetime)) { @@ -103,15 +116,13 @@ protected function doSave(array $values, $lifetime) } return array_keys($failures); - } catch (\Error $e) { - } catch (\Exception $e) { - } + } catch (\Throwable $e) { + if (1 === \count($values)) { + // Workaround https://github.com/krakjoe/apcu/issues/170 + apcu_delete(array_key_first($values)); + } - if (1 === \count($values)) { - // Workaround https://github.com/krakjoe/apcu/issues/170 - apcu_delete(key($values)); + throw $e; } - - throw $e; } } diff --git a/vendor/symfony/cache/Traits/ArrayTrait.php b/vendor/symfony/cache/Traits/ArrayTrait.php index 0a60968e..e41daebc 100644 --- a/vendor/symfony/cache/Traits/ArrayTrait.php +++ b/vendor/symfony/cache/Traits/ArrayTrait.php @@ -34,36 +34,72 @@ trait ArrayTrait */ public function getValues() { - return $this->values; + if (!$this->storeSerialized) { + return $this->values; + } + + $values = $this->values; + foreach ($values as $k => $v) { + if (null === $v || 'N;' === $v) { + continue; + } + if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) { + $values[$k] = serialize($v); + } + } + + return $values; } /** * {@inheritdoc} + * + * @return bool */ public function hasItem($key) { + if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) { + return true; + } CacheItem::validateKey($key); - return isset($this->expiries[$key]) && ($this->expiries[$key] > time() || !$this->deleteItem($key)); + return isset($this->expiries[$key]) && !$this->deleteItem($key); } /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { - $this->values = $this->expiries = []; + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; + + if ('' !== $prefix) { + foreach ($this->values as $key => $value) { + if (str_starts_with($key, $prefix)) { + unset($this->values[$key], $this->expiries[$key]); + } + } + } else { + $this->values = $this->expiries = []; + } return true; } /** * {@inheritdoc} + * + * @return bool */ public function deleteItem($key) { - CacheItem::validateKey($key); - + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } unset($this->values[$key], $this->expiries[$key]); return true; @@ -77,24 +113,13 @@ public function reset() $this->clear(); } - private function generateItems(array $keys, $now, $f) + private function generateItems(array $keys, float $now, callable $f): iterable { foreach ($keys as $i => $key) { - try { - if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) { - $this->values[$key] = $value = null; - } elseif (!$this->storeSerialized) { - $value = $this->values[$key]; - } elseif ('b:0;' === $value = $this->values[$key]) { - $value = false; - } elseif (false === $value = unserialize($value)) { - $this->values[$key] = $value = null; - $isHit = false; - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]); + if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) { $this->values[$key] = $value = null; - $isHit = false; + } else { + $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key]; } unset($keys[$i]); @@ -105,4 +130,55 @@ private function generateItems(array $keys, $now, $f) yield $key => $f($key, null, false); } } + + private function freeze($value, $key) + { + if (null === $value) { + return 'N;'; + } + if (\is_string($value)) { + // Serialize strings if they could be confused with serialized objects or arrays + if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { + return serialize($value); + } + } elseif (!\is_scalar($value)) { + try { + $serialized = serialize($value); + } catch (\Exception $e) { + unset($this->values[$key]); + $type = \is_object($value) ? \get_class($value) : \gettype($value); + $message = sprintf('Failed to save key "{key}" of type %s: ', $type).$e->getMessage(); + CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e]); + + return null; + } + // Keep value serialized if it contains any objects or any internal references + if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) { + return $serialized; + } + } + + return $value; + } + + private function unfreeze(string $key, bool &$isHit) + { + if ('N;' === $value = $this->values[$key]) { + return null; + } + if (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + try { + $value = unserialize($value); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); + $value = false; + } + if (false === $value) { + $this->values[$key] = $value = null; + $isHit = false; + } + } + + return $value; + } } diff --git a/vendor/symfony/cache/Traits/ContractsTrait.php b/vendor/symfony/cache/Traits/ContractsTrait.php new file mode 100644 index 00000000..49a96eed --- /dev/null +++ b/vendor/symfony/cache/Traits/ContractsTrait.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\LockRegistry; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\CacheTrait; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * @author Nicolas Grekas + * + * @internal + */ +trait ContractsTrait +{ + use CacheTrait { + doGet as private contractsGet; + } + + private $callbackWrapper; + private $computing = []; + + /** + * Wraps the callback passed to ->get() in a callable. + * + * @return callable the previous callback wrapper + */ + public function setCallbackWrapper(?callable $callbackWrapper): callable + { + if (!isset($this->callbackWrapper)) { + $this->callbackWrapper = \Closure::fromCallable([LockRegistry::class, 'compute']); + + if (\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { + $this->setCallbackWrapper(null); + } + } + + $previousWrapper = $this->callbackWrapper; + $this->callbackWrapper = $callbackWrapper ?? static function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) { + return $callback($item, $save); + }; + + return $previousWrapper; + } + + private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null) + { + if (0 > $beta = $beta ?? 1.0) { + throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', static::class, $beta)); + } + + static $setMetadata; + + $setMetadata = $setMetadata ?? \Closure::bind( + static function (CacheItem $item, float $startTime, ?array &$metadata) { + if ($item->expiry > $endTime = microtime(true)) { + $item->newMetadata[CacheItem::METADATA_EXPIRY] = $metadata[CacheItem::METADATA_EXPIRY] = $item->expiry; + $item->newMetadata[CacheItem::METADATA_CTIME] = $metadata[CacheItem::METADATA_CTIME] = (int) ceil(1000 * ($endTime - $startTime)); + } else { + unset($metadata[CacheItem::METADATA_EXPIRY], $metadata[CacheItem::METADATA_CTIME]); + } + }, + null, + CacheItem::class + ); + + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { + // don't wrap nor save recursive calls + if (isset($this->computing[$key])) { + $value = $callback($item, $save); + $save = false; + + return $value; + } + + $this->computing[$key] = $key; + $startTime = microtime(true); + + if (!isset($this->callbackWrapper)) { + $this->setCallbackWrapper($this->setCallbackWrapper(null)); + } + + try { + $value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { + $setMetadata($item, $startTime, $metadata); + }, $this->logger ?? null); + $setMetadata($item, $startTime, $metadata); + + return $value; + } finally { + unset($this->computing[$key]); + } + }, $beta, $metadata, $this->logger ?? null); + } +} diff --git a/vendor/symfony/cache/Traits/DoctrineTrait.php b/vendor/symfony/cache/Traits/DoctrineTrait.php index 48623e67..ae14db01 100644 --- a/vendor/symfony/cache/Traits/DoctrineTrait.php +++ b/vendor/symfony/cache/Traits/DoctrineTrait.php @@ -91,7 +91,7 @@ protected function doDelete(array $ids) /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { return $this->provider->saveMultiple($values, $lifetime); } diff --git a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php index 8071a382..4e06495d 100644 --- a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php +++ b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php @@ -23,10 +23,10 @@ trait FilesystemCommonTrait private $directory; private $tmp; - private function init($namespace, $directory) + private function init(string $namespace, ?string $directory) { if (!isset($directory[0])) { - $directory = sys_get_temp_dir().'/symfony-cache'; + $directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfony-cache'; } else { $directory = realpath($directory) ?: $directory; } @@ -35,6 +35,8 @@ private function init($namespace, $directory) throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } $directory .= \DIRECTORY_SEPARATOR.$namespace; + } else { + $directory .= \DIRECTORY_SEPARATOR.'@'; } if (!file_exists($directory)) { @mkdir($directory, 0777, true); @@ -55,8 +57,12 @@ protected function doClear($namespace) { $ok = true; - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) { - $ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok; + foreach ($this->scanHashDir($this->directory) as $file) { + if ('' !== $namespace && !str_starts_with($this->getFileKey($file), $namespace)) { + continue; + } + + $ok = ($this->doUnlink($file) || !file_exists($file)) && $ok; } return $ok; @@ -71,23 +77,39 @@ protected function doDelete(array $ids) foreach ($ids as $id) { $file = $this->getFile($id); - $ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok; + $ok = (!file_exists($file) || $this->doUnlink($file) || !file_exists($file)) && $ok; } return $ok; } - private function write($file, $data, $expiresAt = null) + protected function doUnlink($file) + { + return @unlink($file); + } + + private function write(string $file, string $data, int $expiresAt = null) { set_error_handler(__CLASS__.'::throwError'); try { if (null === $this->tmp) { - $this->tmp = $this->directory.uniqid('', true); + $this->tmp = $this->directory.bin2hex(random_bytes(6)); } - file_put_contents($this->tmp, $data); + try { + $h = fopen($this->tmp, 'x'); + } catch (\ErrorException $e) { + if (!str_contains($e->getMessage(), 'File exists')) { + throw $e; + } + + $this->tmp = $this->directory.bin2hex(random_bytes(6)); + $h = fopen($this->tmp, 'x'); + } + fwrite($h, $data); + fclose($h); if (null !== $expiresAt) { - touch($this->tmp, $expiresAt); + touch($this->tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds } return rename($this->tmp, $file); @@ -96,10 +118,11 @@ private function write($file, $data, $expiresAt = null) } } - private function getFile($id, $mkdir = false) + private function getFile(string $id, bool $mkdir = false, string $directory = null) { - $hash = str_replace('/', '-', base64_encode(hash('sha256', static::class.$id, true))); - $dir = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); + // Use MD5 to favor speed over security, which is not an issue here + $hash = str_replace('/', '-', base64_encode(hash('md5', static::class.$id, true))); + $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); if ($mkdir && !file_exists($dir)) { @mkdir($dir, 0777, true); @@ -108,6 +131,38 @@ private function getFile($id, $mkdir = false) return $dir.substr($hash, 2, 20); } + private function getFileKey(string $file): string + { + return ''; + } + + private function scanHashDir(string $directory): \Generator + { + if (!file_exists($directory)) { + return; + } + + $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; + + for ($i = 0; $i < 38; ++$i) { + if (!file_exists($directory.$chars[$i])) { + continue; + } + + for ($j = 0; $j < 38; ++$j) { + if (!file_exists($dir = $directory.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j])) { + continue; + } + + foreach (@scandir($dir, \SCANDIR_SORT_NONE) ?: [] as $file) { + if ('.' !== $file && '..' !== $file) { + yield $dir.\DIRECTORY_SEPARATOR.$file; + } + } + } + } + } + /** * @internal */ @@ -116,6 +171,9 @@ public static function throwError($type, $message, $file, $line) throw new \ErrorException($message, 0, $type, $file, $line); } + /** + * @return array + */ public function __sleep() { throw new \BadMethodCallException('Cannot serialize '.__CLASS__); diff --git a/vendor/symfony/cache/Traits/FilesystemTrait.php b/vendor/symfony/cache/Traits/FilesystemTrait.php index 9d7f5578..72118eaa 100644 --- a/vendor/symfony/cache/Traits/FilesystemTrait.php +++ b/vendor/symfony/cache/Traits/FilesystemTrait.php @@ -23,6 +23,8 @@ trait FilesystemTrait { use FilesystemCommonTrait; + private $marshaller; + /** * @return bool */ @@ -31,8 +33,8 @@ public function prune() $time = time(); $pruned = true; - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - if (!$h = @fopen($file, 'rb')) { + foreach ($this->scanHashDir($this->directory) as $file) { + if (!$h = @fopen($file, 'r')) { continue; } @@ -57,7 +59,7 @@ protected function doFetch(array $ids) foreach ($ids as $id) { $file = $this->getFile($id); - if (!file_exists($file) || !$h = @fopen($file, 'rb')) { + if (!file_exists($file) || !$h = @fopen($file, 'r')) { continue; } if (($expiresAt = (int) fgets($h)) && $now >= $expiresAt) { @@ -68,7 +70,7 @@ protected function doFetch(array $ids) $value = stream_get_contents($h); fclose($h); if ($i === $id) { - $values[$id] = parent::unserialize($value); + $values[$id] = $this->marshaller->unmarshall($value); } } } @@ -89,19 +91,34 @@ protected function doHave($id) /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { - $ok = true; $expiresAt = $lifetime ? (time() + $lifetime) : 0; + $values = $this->marshaller->marshall($values, $failed); foreach ($values as $id => $value) { - $ok = $this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".serialize($value), $expiresAt) && $ok; + if (!$this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".$value, $expiresAt)) { + $failed[] = $id; + } } - if (!$ok && !is_writable($this->directory)) { + if ($failed && !is_writable($this->directory)) { throw new CacheException(sprintf('Cache directory is not writable (%s).', $this->directory)); } - return $ok; + return $failed; + } + + private function getFileKey(string $file): string + { + if (!$h = @fopen($file, 'r')) { + return ''; + } + + fgets($h); // expiry + $encodedKey = fgets($h); + fclose($h); + + return rawurldecode(rtrim($encodedKey)); } } diff --git a/vendor/symfony/cache/Traits/MemcachedTrait.php b/vendor/symfony/cache/Traits/MemcachedTrait.php index 34d0208e..ebcb160c 100644 --- a/vendor/symfony/cache/Traits/MemcachedTrait.php +++ b/vendor/symfony/cache/Traits/MemcachedTrait.php @@ -13,6 +13,8 @@ use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @author Rob Frawley 2nd @@ -29,18 +31,27 @@ trait MemcachedTrait \Memcached::OPT_SERIALIZER => \Memcached::SERIALIZER_PHP, ]; + /** + * We are replacing characters that are illegal in Memcached keys with reserved characters from + * {@see \Symfony\Contracts\Cache\ItemInterface::RESERVED_CHARACTERS} that are legal in Memcached. + * Note: don’t use {@see \Symfony\Component\Cache\Adapter\AbstractAdapter::NS_SEPARATOR}. + */ + private static $RESERVED_MEMCACHED = " \n\r\t\v\f\0"; + private static $RESERVED_PSR6 = '@()\{}/'; + + private $marshaller; private $client; private $lazyClient; public static function isSupported() { - return \extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>='); + return \extension_loaded('memcached') && version_compare(phpversion('memcached'), \PHP_VERSION_ID >= 80100 ? '3.1.6' : '2.2.0', '>='); } - private function init(\Memcached $client, $namespace, $defaultLifetime) + private function init(\Memcached $client, string $namespace, int $defaultLifetime, ?MarshallerInterface $marshaller) { if (!static::isSupported()) { - throw new CacheException('Memcached >= 2.2.0 is required.'); + throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.'); } if ('Memcached' === \get_class($client)) { $opt = $client->getOption(\Memcached::OPT_SERIALIZER); @@ -55,6 +66,7 @@ private function init(\Memcached $client, $namespace, $defaultLifetime) parent::__construct($namespace, $defaultLifetime); $this->enableVersioning(); + $this->marshaller = $marshaller ?? new DefaultMarshaller(); } /** @@ -67,7 +79,6 @@ private function init(\Memcached $client, $namespace, $defaultLifetime) * - [['localhost', 11211, 33]] * * @param array[]|string|string[] $servers An array of servers, a DSN, or an array of DSNs - * @param array $options An array of options * * @return \Memcached * @@ -81,7 +92,7 @@ public static function createConnection($servers, array $options = []) throw new InvalidArgumentException(sprintf('MemcachedAdapter::createClient() expects array or string as first argument, "%s" given.', \gettype($servers))); } if (!static::isSupported()) { - throw new CacheException('Memcached >= 2.2.0 is required.'); + throw new CacheException('Memcached '.(\PHP_VERSION_ID >= 80100 ? '> 3.1.5' : '>= 2.2.0').' is required.'); } set_error_handler(function ($type, $msg, $file, $line) { throw new \ErrorException($msg, 0, $type, $file, $line); }); try { @@ -95,19 +106,43 @@ public static function createConnection($servers, array $options = []) if (\is_array($dsn)) { continue; } - if (0 !== strpos($dsn, 'memcached://')) { - throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s" does not start with "memcached://".', $dsn)); + if (!str_starts_with($dsn, 'memcached:')) { + throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s" does not start with "memcached:".', $dsn)); } - $params = preg_replace_callback('#^memcached://(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) { - if (!empty($m[1])) { - list($username, $password) = explode(':', $m[1], 2) + [1 => null]; + $params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) { + if (!empty($m[2])) { + [$username, $password] = explode(':', $m[2], 2) + [1 => null]; } - return 'file://'; + return 'file:'.($m[1] ?? ''); }, $dsn); if (false === $params = parse_url($params)) { throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn)); } + $query = $hosts = []; + if (isset($params['query'])) { + parse_str($params['query'], $query); + + if (isset($query['host'])) { + if (!\is_array($hosts = $query['host'])) { + throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn)); + } + foreach ($hosts as $host => $weight) { + if (false === $port = strrpos($host, ':')) { + $hosts[$host] = [$host, 11211, (int) $weight]; + } else { + $hosts[$host] = [substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight]; + } + } + $hosts = array_values($hosts); + unset($query['host']); + } + if ($hosts && !isset($params['host']) && !isset($params['path'])) { + unset($servers[$i]); + $servers = array_merge($servers, $hosts); + continue; + } + } if (!isset($params['host']) && !isset($params['path'])) { throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: "%s".', $dsn)); } @@ -116,17 +151,20 @@ public static function createConnection($servers, array $options = []) $params['path'] = substr($params['path'], 0, -\strlen($m[0])); } $params += [ - 'host' => isset($params['host']) ? $params['host'] : $params['path'], + 'host' => $params['host'] ?? $params['path'], 'port' => isset($params['host']) ? 11211 : null, 'weight' => 0, ]; - if (isset($params['query'])) { - parse_str($params['query'], $query); + if ($query) { $params += $query; $options = $query + $options; } $servers[$i] = [$params['host'], $params['port'], $params['weight']]; + + if ($hosts) { + $servers = array_merge($servers, $hosts); + } } // set client's options @@ -193,18 +231,22 @@ public static function createConnection($servers, array $options = []) /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + if ($lifetime && $lifetime > 30 * 86400) { $lifetime += time(); } $encodedValues = []; foreach ($values as $key => $value) { - $encodedValues[rawurlencode($key)] = $value; + $encodedValues[self::encodeKey($key)] = $value; } - return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)); + return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)) ? $failed : false; } /** @@ -212,22 +254,19 @@ protected function doSave(array $values, $lifetime) */ protected function doFetch(array $ids) { - $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); try { - $encodedIds = array_map('rawurlencode', $ids); + $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids); $encodedResult = $this->checkResultCode($this->getClient()->getMulti($encodedIds)); $result = []; foreach ($encodedResult as $key => $value) { - $result[rawurldecode($key)] = $value; + $result[self::decodeKey($key)] = $this->marshaller->unmarshall($value); } return $result; } catch (\Error $e) { throw new \ErrorException($e->getMessage(), $e->getCode(), \E_ERROR, $e->getFile(), $e->getLine()); - } finally { - ini_set('unserialize_callback_func', $unserializeCallbackHandler); } } @@ -236,7 +275,7 @@ protected function doFetch(array $ids) */ protected function doHave($id) { - return false !== $this->getClient()->get(rawurlencode($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode()); + return false !== $this->getClient()->get(self::encodeKey($id)) || $this->checkResultCode(\Memcached::RES_SUCCESS === $this->client->getResultCode()); } /** @@ -245,7 +284,7 @@ protected function doHave($id) protected function doDelete(array $ids) { $ok = true; - $encodedIds = array_map('rawurlencode', $ids); + $encodedIds = array_map([__CLASS__, 'encodeKey'], $ids); foreach ($this->checkResultCode($this->getClient()->deleteMulti($encodedIds)) as $result) { if (\Memcached::RES_SUCCESS !== $result && \Memcached::RES_NOTFOUND !== $result) { $ok = false; @@ -275,10 +314,7 @@ private function checkResultCode($result) throw new CacheException('MemcachedAdapter client error: '.strtolower($this->client->getResultMessage())); } - /** - * @return \Memcached - */ - private function getClient() + private function getClient(): \Memcached { if ($this->client) { return $this->client; @@ -294,4 +330,14 @@ private function getClient() return $this->client = $this->lazyClient; } + + private static function encodeKey(string $key): string + { + return strtr($key, self::$RESERVED_MEMCACHED, self::$RESERVED_PSR6); + } + + private static function decodeKey(string $key): string + { + return strtr($key, self::$RESERVED_PSR6, self::$RESERVED_MEMCACHED); + } } diff --git a/vendor/symfony/cache/Traits/PdoTrait.php b/vendor/symfony/cache/Traits/PdoTrait.php index 917e8dd1..4d5e1230 100644 --- a/vendor/symfony/cache/Traits/PdoTrait.php +++ b/vendor/symfony/cache/Traits/PdoTrait.php @@ -14,14 +14,22 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Exception; +use Doctrine\DBAL\Exception\TableNotFoundException; +use Doctrine\DBAL\ParameterType; use Doctrine\DBAL\Schema\Schema; +use Doctrine\DBAL\Statement; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @internal */ trait PdoTrait { + private $marshaller; private $conn; private $dsn; private $driver; @@ -36,7 +44,7 @@ trait PdoTrait private $connectionOptions = []; private $namespace; - private function init($connOrDsn, $namespace, $defaultLifetime, array $options) + private function init($connOrDsn, string $namespace, int $defaultLifetime, array $options, ?MarshallerInterface $marshaller) { if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); @@ -56,15 +64,16 @@ private function init($connOrDsn, $namespace, $defaultLifetime, array $options) throw new InvalidArgumentException(sprintf('"%s" requires PDO or Doctrine\DBAL\Connection instance or DSN string as first argument, "%s" given.', __CLASS__, \is_object($connOrDsn) ? \get_class($connOrDsn) : \gettype($connOrDsn))); } - $this->table = isset($options['db_table']) ? $options['db_table'] : $this->table; - $this->idCol = isset($options['db_id_col']) ? $options['db_id_col'] : $this->idCol; - $this->dataCol = isset($options['db_data_col']) ? $options['db_data_col'] : $this->dataCol; - $this->lifetimeCol = isset($options['db_lifetime_col']) ? $options['db_lifetime_col'] : $this->lifetimeCol; - $this->timeCol = isset($options['db_time_col']) ? $options['db_time_col'] : $this->timeCol; - $this->username = isset($options['db_username']) ? $options['db_username'] : $this->username; - $this->password = isset($options['db_password']) ? $options['db_password'] : $this->password; - $this->connectionOptions = isset($options['db_connection_options']) ? $options['db_connection_options'] : $this->connectionOptions; + $this->table = $options['db_table'] ?? $this->table; + $this->idCol = $options['db_id_col'] ?? $this->idCol; + $this->dataCol = $options['db_data_col'] ?? $this->dataCol; + $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol; + $this->timeCol = $options['db_time_col'] ?? $this->timeCol; + $this->username = $options['db_username'] ?? $this->username; + $this->password = $options['db_password'] ?? $this->password; + $this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions; $this->namespace = $namespace; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); parent::__construct($namespace, $defaultLifetime); } @@ -77,6 +86,7 @@ private function init($connOrDsn, $namespace, $defaultLifetime, array $options) * * @throws \PDOException When the table already exists * @throws DBALException When the table already exists + * @throws Exception When the table already exists * @throws \DomainException When an unsupported PDO driver is used */ public function createTable() @@ -140,7 +150,7 @@ public function createTable() throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver)); } - if (method_exists($conn, 'executeStatement')) { + if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) { $conn->executeStatement($sql); } else { $conn->exec($sql); @@ -158,14 +168,35 @@ public function prune() $deleteSql .= " AND $this->idCol LIKE :namespace"; } - $delete = $this->getConnection()->prepare($deleteSql); - $delete->bindValue(':time', time(), \PDO::PARAM_INT); + $connection = $this->getConnection(); + $useDbalConstants = $connection instanceof Connection; + + try { + $delete = $connection->prepare($deleteSql); + } catch (TableNotFoundException $e) { + return true; + } catch (\PDOException $e) { + return true; + } + $delete->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); if ('' !== $this->namespace) { - $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR); + $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), $useDbalConstants ? ParameterType::STRING : \PDO::PARAM_STR); } + try { + // Doctrine DBAL ^2.13 || >= 3.1 + if ($delete instanceof Statement && method_exists($delete, 'executeStatement')) { + $delete->executeStatement(); - return $delete->execute(); + return true; + } + + return $delete->execute(); + } catch (TableNotFoundException $e) { + return true; + } catch (\PDOException $e) { + return true; + } } /** @@ -173,13 +204,16 @@ public function prune() */ protected function doFetch(array $ids) { + $connection = $this->getConnection(); + $useDbalConstants = $connection instanceof Connection; + $now = time(); $expired = []; $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)"; - $stmt = $this->getConnection()->prepare($sql); - $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); + $stmt = $connection->prepare($sql); + $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); foreach ($ids as $id) { $stmt->bindValue(++$i, $id); } @@ -196,15 +230,15 @@ protected function doFetch(array $ids) if (null === $row[1]) { $expired[] = $row[0]; } else { - yield $row[0] => parent::unserialize(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); + yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); } } if ($expired) { $sql = str_pad('', (\count($expired) << 1) - 1, '?,'); $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)"; - $stmt = $this->getConnection()->prepare($sql); - $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); + $stmt = $connection->prepare($sql); + $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); foreach ($expired as $id) { $stmt->bindValue(++$i, $id); } @@ -217,11 +251,14 @@ protected function doFetch(array $ids) */ protected function doHave($id) { + $connection = $this->getConnection(); + $useDbalConstants = $connection instanceof Connection; + $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)"; - $stmt = $this->getConnection()->prepare($sql); + $stmt = $connection->prepare($sql); $stmt->bindValue(':id', $id); - $stmt->bindValue(':time', time(), \PDO::PARAM_INT); + $stmt->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); $result = $stmt->execute(); return (bool) (\is_object($result) ? $result->fetchOne() : $stmt->fetchColumn()); @@ -244,10 +281,14 @@ protected function doClear($namespace) $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'"; } - if (method_exists($conn, 'executeStatement')) { - $conn->executeStatement($sql); - } else { - $conn->exec($sql); + try { + if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) { + $conn->executeStatement($sql); + } else { + $conn->exec($sql); + } + } catch (TableNotFoundException $e) { + } catch (\PDOException $e) { } return true; @@ -260,8 +301,12 @@ protected function doDelete(array $ids) { $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); $sql = "DELETE FROM $this->table WHERE $this->idCol IN ($sql)"; - $stmt = $this->getConnection()->prepare($sql); - $stmt->execute(array_values($ids)); + try { + $stmt = $this->getConnection()->prepare($sql); + $stmt->execute(array_values($ids)); + } catch (TableNotFoundException $e) { + } catch (\PDOException $e) { + } return true; } @@ -269,24 +314,15 @@ protected function doDelete(array $ids) /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { - $serialized = []; - $failed = []; - - foreach ($values as $id => $value) { - try { - $serialized[$id] = serialize($value); - } catch (\Exception $e) { - $failed[] = $id; - } - } - - if (!$serialized) { + if (!$values = $this->marshaller->marshall($values, $failed)) { return $failed; } $conn = $this->getConnection(); + $useDbalConstants = $conn instanceof Connection; + $driver = $this->driver; $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; @@ -321,39 +357,62 @@ protected function doSave(array $values, $lifetime) $now = time(); $lifetime = $lifetime ?: null; - $stmt = $conn->prepare($sql); + try { + $stmt = $conn->prepare($sql); + } catch (TableNotFoundException $e) { + if (!$conn->isTransactionActive() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) { + $this->createTable(); + } + $stmt = $conn->prepare($sql); + } catch (\PDOException $e) { + if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) { + $this->createTable(); + } + $stmt = $conn->prepare($sql); + } if ('sqlsrv' === $driver || 'oci' === $driver) { $stmt->bindParam(1, $id); $stmt->bindParam(2, $id); - $stmt->bindParam(3, $data, \PDO::PARAM_LOB); - $stmt->bindValue(4, $lifetime, \PDO::PARAM_INT); - $stmt->bindValue(5, $now, \PDO::PARAM_INT); - $stmt->bindParam(6, $data, \PDO::PARAM_LOB); - $stmt->bindValue(7, $lifetime, \PDO::PARAM_INT); - $stmt->bindValue(8, $now, \PDO::PARAM_INT); + $stmt->bindParam(3, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $stmt->bindValue(4, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindValue(5, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindParam(6, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $stmt->bindValue(7, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindValue(8, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); } else { $stmt->bindParam(':id', $id); - $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); - $stmt->bindValue(':time', $now, \PDO::PARAM_INT); + $stmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $stmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $stmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); } if (null === $driver) { $insertStmt = $conn->prepare($insertSql); $insertStmt->bindParam(':id', $id); - $insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); - $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT); + $insertStmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB); + $insertStmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); + $insertStmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT); } - foreach ($serialized as $id => $data) { - $result = $stmt->execute(); - + foreach ($values as $id => $data) { + try { + $result = $stmt->execute(); + } catch (TableNotFoundException $e) { + if (!$conn->isTransactionActive() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) { + $this->createTable(); + } + $result = $stmt->execute(); + } catch (\PDOException $e) { + if (!$conn->inTransaction() || \in_array($this->driver, ['pgsql', 'sqlite', 'sqlsrv'], true)) { + $this->createTable(); + } + $result = $stmt->execute(); + } if (null === $driver && !(\is_object($result) ? $result->rowCount() : $stmt->rowCount())) { try { $insertStmt->execute(); - } catch (DBALException $e) { + } catch (DBALException|Exception $e) { } catch (\PDOException $e) { // A concurrent write won, let it be } @@ -369,8 +428,15 @@ protected function doSave(array $values, $lifetime) private function getConnection() { if (null === $this->conn) { - $this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions); - $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + if (strpos($this->dsn, '://')) { + if (!class_exists(DriverManager::class)) { + throw new InvalidArgumentException(sprintf('Failed to parse the DSN "%s". Try running "composer require doctrine/dbal".', $this->dsn)); + } + $this->conn = DriverManager::getConnection(['url' => $this->dsn]); + } else { + $this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions); + $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + } } if (null === $this->driver) { if ($this->conn instanceof \PDO) { @@ -379,11 +445,9 @@ private function getConnection() $driver = $this->conn->getDriver(); switch (true) { - case $driver instanceof \Doctrine\DBAL\Driver\AbstractMySQLDriver: - case $driver instanceof \Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver: case $driver instanceof \Doctrine\DBAL\Driver\Mysqli\Driver: - case $driver instanceof \Doctrine\DBAL\Driver\PDOMySql\Driver: - case $driver instanceof \Doctrine\DBAL\Driver\PDO\MySQL\Driver: + throw new \LogicException(sprintf('The adapter "%s" does not support the mysqli driver, use pdo_mysql instead.', static::class)); + case $driver instanceof \Doctrine\DBAL\Driver\AbstractMySQLDriver: $this->driver = 'mysql'; break; case $driver instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver: @@ -404,6 +468,15 @@ private function getConnection() case $driver instanceof \Doctrine\DBAL\Driver\PDO\SQLSrv\Driver: $this->driver = 'sqlsrv'; break; + case $driver instanceof \Doctrine\DBAL\Driver: + $this->driver = [ + 'mssql' => 'sqlsrv', + 'oracle' => 'oci', + 'postgresql' => 'pgsql', + 'sqlite' => 'sqlite', + 'mysql' => 'mysql', + ][$driver->getDatabasePlatform()->getName()] ?? \get_class($driver); + break; default: $this->driver = \get_class($driver); break; @@ -414,10 +487,7 @@ private function getConnection() return $this->conn; } - /** - * @return string - */ - private function getServerVersion() + private function getServerVersion(): string { if (null === $this->serverVersion) { $conn = $this->conn instanceof \PDO ? $this->conn : $this->conn->getWrappedConnection(); diff --git a/vendor/symfony/cache/Traits/PhpArrayTrait.php b/vendor/symfony/cache/Traits/PhpArrayTrait.php index 972c7512..230c7bd4 100644 --- a/vendor/symfony/cache/Traits/PhpArrayTrait.php +++ b/vendor/symfony/cache/Traits/PhpArrayTrait.php @@ -11,8 +11,10 @@ namespace Symfony\Component\Cache\Traits; +use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\VarExporter\VarExporter; /** * @author Titouan Galopin @@ -25,8 +27,8 @@ trait PhpArrayTrait use ProxyTrait; private $file; + private $keys; private $values; - private $zendDetectUnicode; private static $valuesCache = []; @@ -57,56 +59,63 @@ public function warmUp(array $values) } } + $dumpedValues = ''; + $dumpedMap = []; $dump = <<<'EOF' $value) { CacheItem::validateKey(\is_int($key) ? (string) $key : $key); + $isStaticValue = true; - if (null === $value || \is_object($value)) { + if (null === $value) { + $value = "'N;'"; + } elseif (\is_object($value) || \is_array($value)) { try { - $value = serialize($value); + $value = VarExporter::export($value, $isStaticValue); } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \get_class($value)), 0, $e); - } - } elseif (\is_array($value)) { - try { - $serialized = serialize($value); - $unserialized = unserialize($serialized); - } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e); - } - // Store arrays serialized if they contain any objects or references - if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) { - $value = $serialized; + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e); } } elseif (\is_string($value)) { - // Serialize strings if they could be confused with serialized objects or arrays - if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { - $value = serialize($value); + // Wrap "N;" in a closure to not confuse it with an encoded `null` + if ('N;' === $value) { + $isStaticValue = false; } - } elseif (!is_scalar($value)) { + $value = var_export($value, true); + } elseif (!\is_scalar($value)) { throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \gettype($value))); + } else { + $value = var_export($value, true); + } + + if (!$isStaticValue) { + $value = str_replace("\n", "\n ", $value); + $value = "static function () {\n return {$value};\n}"; + } + $hash = hash('md5', $value); + + if (null === $id = $dumpedMap[$hash] ?? null) { + $id = $dumpedMap[$hash] = \count($dumpedMap); + $dumpedValues .= "{$id} => {$value},\n"; } - $dump .= var_export($key, true).' => '.var_export($value, true).",\n"; + $dump .= var_export($key, true)." => {$id},\n"; } - $dump .= "\n];\n"; - $dump = str_replace("' . \"\\0\" . '", "\0", $dump); + $dump .= "\n], [\n\n{$dumpedValues}\n]];\n"; $tmpFile = uniqid($this->file, true); file_put_contents($tmpFile, $dump); @chmod($tmpFile, 0666 & ~umask()); - unset($serialized, $unserialized, $value, $dump); + unset($serialized, $value, $dump); @rename($tmpFile, $this->file); unset(self::$valuesCache[$this->file]); @@ -116,14 +125,23 @@ public function warmUp(array $values) /** * {@inheritdoc} + * + * @param string $prefix + * + * @return bool */ - public function clear() + public function clear(/* string $prefix = '' */) { - $this->values = []; + $prefix = 0 < \func_num_args() ? (string) func_get_arg(0) : ''; + $this->keys = $this->values = []; $cleared = @unlink($this->file) || !file_exists($this->file); unset(self::$valuesCache[$this->file]); + if ($this->pool instanceof AdapterInterface) { + return $this->pool->clear($prefix) && $cleared; + } + return $this->pool->clear() && $cleared; } @@ -133,20 +151,19 @@ public function clear() private function initialize() { if (isset(self::$valuesCache[$this->file])) { - $this->values = self::$valuesCache[$this->file]; + $values = self::$valuesCache[$this->file]; + } elseif (!file_exists($this->file)) { + $this->keys = $this->values = []; return; + } else { + $values = self::$valuesCache[$this->file] = (include $this->file) ?: [[], []]; } - if ($this->zendDetectUnicode) { - $zmb = ini_set('zend.detect_unicode', 0); - } - try { - $this->values = self::$valuesCache[$this->file] = file_exists($this->file) ? (include $this->file ?: []) : []; - } finally { - if ($this->zendDetectUnicode) { - ini_set('zend.detect_unicode', $zmb); - } + if (2 !== \count($values) || !isset($values[0], $values[1])) { + $this->keys = $this->values = []; + } else { + [$this->keys, $this->values] = $values; } } } diff --git a/vendor/symfony/cache/Traits/PhpFilesTrait.php b/vendor/symfony/cache/Traits/PhpFilesTrait.php index 2668b26c..c76e7fe3 100644 --- a/vendor/symfony/cache/Traits/PhpFilesTrait.php +++ b/vendor/symfony/cache/Traits/PhpFilesTrait.php @@ -13,6 +13,7 @@ use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\VarExporter\VarExporter; /** * @author Piotr Stankowski @@ -23,14 +24,24 @@ */ trait PhpFilesTrait { - use FilesystemCommonTrait; + use FilesystemCommonTrait { + doClear as private doCommonClear; + doDelete as private doCommonDelete; + } private $includeHandler; - private $zendDetectUnicode; + private $appendOnly; + private $values = []; + private $files = []; + + private static $startTime; + private static $valuesCache = []; public static function isSupported() { - return \function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN); + self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time(); + + return \function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) || filter_var(\ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN)); } /** @@ -40,19 +51,21 @@ public function prune() { $time = time(); $pruned = true; - $allowCompile = 'cli' !== \PHP_SAPI || filter_var(ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN); + $getExpiry = true; set_error_handler($this->includeHandler); try { - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - list($expiresAt) = include $file; + foreach ($this->scanHashDir($this->directory) as $file) { + try { + if (\is_array($expiresAt = include $file)) { + $expiresAt = $expiresAt[0]; + } + } catch (\ErrorException $e) { + $expiresAt = $time; + } if ($time >= $expiresAt) { - $pruned = @unlink($file) && !file_exists($file) && $pruned; - - if ($allowCompile) { - @opcache_invalidate($file, true); - } + $pruned = $this->doUnlink($file) && !file_exists($file) && $pruned; } } } finally { @@ -67,41 +80,75 @@ public function prune() */ protected function doFetch(array $ids) { + if ($this->appendOnly) { + $now = 0; + $missingIds = []; + } else { + $now = time(); + $missingIds = $ids; + $ids = []; + } $values = []; - $now = time(); - if ($this->zendDetectUnicode) { - $zmb = ini_set('zend.detect_unicode', 0); + begin: + $getExpiry = false; + + foreach ($ids as $id) { + if (null === $value = $this->values[$id] ?? null) { + $missingIds[] = $id; + } elseif ('N;' === $value) { + $values[$id] = null; + } elseif (!\is_object($value)) { + $values[$id] = $value; + } elseif (!$value instanceof LazyValue) { + $values[$id] = $value(); + } elseif (false === $values[$id] = include $value->file) { + unset($values[$id], $this->values[$id]); + $missingIds[] = $id; + } + if (!$this->appendOnly) { + unset($this->values[$id]); + } } + + if (!$missingIds) { + return $values; + } + set_error_handler($this->includeHandler); try { - foreach ($ids as $id) { + $getExpiry = true; + + foreach ($missingIds as $k => $id) { try { - $file = $this->getFile($id); - list($expiresAt, $values[$id]) = include $file; + $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id); + + if (isset(self::$valuesCache[$file])) { + [$expiresAt, $this->values[$id]] = self::$valuesCache[$file]; + } elseif (\is_array($expiresAt = include $file)) { + if ($this->appendOnly) { + self::$valuesCache[$file] = $expiresAt; + } + + [$expiresAt, $this->values[$id]] = $expiresAt; + } elseif ($now < $expiresAt) { + $this->values[$id] = new LazyValue($file); + } + if ($now >= $expiresAt) { - unset($values[$id]); + unset($this->values[$id], $missingIds[$k], self::$valuesCache[$file]); } - } catch (\Exception $e) { - continue; + } catch (\ErrorException $e) { + unset($missingIds[$k]); } } } finally { restore_error_handler(); - if ($this->zendDetectUnicode) { - ini_set('zend.detect_unicode', $zmb); - } - } - - foreach ($values as $id => $value) { - if ('N;' === $value) { - $values[$id] = null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { - $values[$id] = parent::unserialize($value); - } } - return $values; + $ids = $missingIds; + $missingIds = []; + goto begin; } /** @@ -109,44 +156,94 @@ protected function doFetch(array $ids) */ protected function doHave($id) { - return (bool) $this->doFetch([$id]); + if ($this->appendOnly && isset($this->values[$id])) { + return true; + } + + set_error_handler($this->includeHandler); + try { + $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id); + $getExpiry = true; + + if (isset(self::$valuesCache[$file])) { + [$expiresAt, $value] = self::$valuesCache[$file]; + } elseif (\is_array($expiresAt = include $file)) { + if ($this->appendOnly) { + self::$valuesCache[$file] = $expiresAt; + } + + [$expiresAt, $value] = $expiresAt; + } elseif ($this->appendOnly) { + $value = new LazyValue($file); + } + } catch (\ErrorException $e) { + return false; + } finally { + restore_error_handler(); + } + if ($this->appendOnly) { + $now = 0; + $this->values[$id] = $value; + } else { + $now = time(); + } + + return $now < $expiresAt; } /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { $ok = true; - $data = [$lifetime ? time() + $lifetime : \PHP_INT_MAX, '']; - $allowCompile = 'cli' !== \PHP_SAPI || filter_var(ini_get('opcache.enable_cli'), \FILTER_VALIDATE_BOOLEAN); + $expiry = $lifetime ? time() + $lifetime : 'PHP_INT_MAX'; + $allowCompile = self::isSupported(); foreach ($values as $key => $value) { - if (null === $value || \is_object($value)) { - $value = serialize($value); - } elseif (\is_array($value)) { - $serialized = serialize($value); - $unserialized = parent::unserialize($serialized); - // Store arrays serialized if they contain any objects or references - if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) { - $value = $serialized; + unset($this->values[$key]); + $isStaticValue = true; + if (null === $value) { + $value = "'N;'"; + } elseif (\is_object($value) || \is_array($value)) { + try { + $value = VarExporter::export($value, $isStaticValue); + } catch (\Exception $e) { + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e); } } elseif (\is_string($value)) { - // Serialize strings if they could be confused with serialized objects or arrays - if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { - $value = serialize($value); + // Wrap "N;" in a closure to not confuse it with an encoded `null` + if ('N;' === $value) { + $isStaticValue = false; } - } elseif (!is_scalar($value)) { + $value = var_export($value, true); + } elseif (!\is_scalar($value)) { throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable "%s" value.', $key, \gettype($value))); + } else { + $value = var_export($value, true); } - $data[1] = $value; - $file = $this->getFile($key, true); - $ok = $this->write($file, 'appendOnly) { + $value = "return [{$expiry}, static function () { return {$value}; }];"; + } else { + // We cannot use a closure here because of https://bugs.php.net/76982 + $value = str_replace('\Symfony\Component\VarExporter\Internal\\', '', $value); + $value = "namespace Symfony\Component\VarExporter\Internal;\n\nreturn \$getExpiry ? {$expiry} : {$value};"; + } + + $file = $this->files[$key] = $this->getFile($key, true); + // Since OPcache only compiles files older than the script execution start, set the file's mtime in the past + $ok = $this->write($file, "directory)) { @@ -155,4 +252,62 @@ protected function doSave(array $values, $lifetime) return $ok; } + + /** + * {@inheritdoc} + */ + protected function doClear($namespace) + { + $this->values = []; + + return $this->doCommonClear($namespace); + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids) + { + foreach ($ids as $id) { + unset($this->values[$id]); + } + + return $this->doCommonDelete($ids); + } + + protected function doUnlink($file) + { + unset(self::$valuesCache[$file]); + + if (self::isSupported()) { + @opcache_invalidate($file, true); + } + + return @unlink($file); + } + + private function getFileKey(string $file): string + { + if (!$h = @fopen($file, 'r')) { + return ''; + } + + $encodedKey = substr(fgets($h), 8); + fclose($h); + + return rawurldecode(rtrim($encodedKey)); + } +} + +/** + * @internal + */ +class LazyValue +{ + public $file; + + public function __construct(string $file) + { + $this->file = $file; + } } diff --git a/vendor/symfony/cache/Traits/ProxyTrait.php b/vendor/symfony/cache/Traits/ProxyTrait.php index d9e085b9..c86f360a 100644 --- a/vendor/symfony/cache/Traits/ProxyTrait.php +++ b/vendor/symfony/cache/Traits/ProxyTrait.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Cache\Traits; use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Service\ResetInterface; /** * @author Nicolas Grekas @@ -36,7 +36,7 @@ public function prune() */ public function reset() { - if ($this->pool instanceof ResettableInterface) { + if ($this->pool instanceof ResetInterface) { $this->pool->reset(); } } diff --git a/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php b/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php new file mode 100644 index 00000000..deba74f6 --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisClusterNodeProxy.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +/** + * This file acts as a wrapper to the \RedisCluster implementation so it can accept the same type of calls as + * individual \Redis objects. + * + * Calls are made to individual nodes via: RedisCluster->{method}($host, ...args)' + * according to https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands + * + * @author Jack Thomas + * + * @internal + */ +class RedisClusterNodeProxy +{ + private $host; + private $redis; + + /** + * @param \RedisCluster|RedisClusterProxy $redis + */ + public function __construct(array $host, $redis) + { + $this->host = $host; + $this->redis = $redis; + } + + public function __call(string $method, array $args) + { + return $this->redis->{$method}($this->host, ...$args); + } + + public function scan(&$iIterator, $strPattern = null, $iCount = null) + { + return $this->redis->scan($iIterator, $this->host, $strPattern, $iCount); + } + + public function getOption($name) + { + return $this->redis->getOption($name); + } +} diff --git a/vendor/symfony/cache/Traits/RedisClusterProxy.php b/vendor/symfony/cache/Traits/RedisClusterProxy.php new file mode 100644 index 00000000..b4cef59a --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisClusterProxy.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +/** + * @author Alessandro Chitolina + * + * @internal + */ +class RedisClusterProxy +{ + private $redis; + private $initializer; + + public function __construct(\Closure $initializer) + { + $this->initializer = $initializer; + } + + public function __call($method, array $args) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->{$method}(...$args); + } + + public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount); + } + + public function scan(&$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->scan($iIterator, $strPattern, $iCount); + } + + public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount); + } + + public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount); + } +} diff --git a/vendor/symfony/cache/Traits/RedisProxy.php b/vendor/symfony/cache/Traits/RedisProxy.php index 98ea3aba..2b0b8573 100644 --- a/vendor/symfony/cache/Traits/RedisProxy.php +++ b/vendor/symfony/cache/Traits/RedisProxy.php @@ -32,7 +32,7 @@ public function __call($method, array $args) { $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis); - return \call_user_func_array([$this->redis, $method], $args); + return $this->redis->{$method}(...$args); } public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null) diff --git a/vendor/symfony/cache/Traits/RedisTrait.php b/vendor/symfony/cache/Traits/RedisTrait.php index a30d6d3f..dabdde4e 100644 --- a/vendor/symfony/cache/Traits/RedisTrait.php +++ b/vendor/symfony/cache/Traits/RedisTrait.php @@ -13,10 +13,13 @@ use Predis\Connection\Aggregate\ClusterInterface; use Predis\Connection\Aggregate\RedisCluster; -use Predis\Connection\Factory; +use Predis\Connection\Aggregate\ReplicationInterface; +use Predis\Response\ErrorInterface; use Predis\Response\Status; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @author Aurimas Niekis @@ -33,24 +36,40 @@ trait RedisTrait 'timeout' => 30, 'read_timeout' => 0, 'retry_interval' => 0, - 'lazy' => false, + 'tcp_keepalive' => 0, + 'lazy' => null, + 'redis_cluster' => false, + 'redis_sentinel' => null, + 'dbindex' => 0, + 'failover' => 'none', + 'ssl' => null, // see https://php.net/context.ssl ]; private $redis; + private $marshaller; /** - * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient + * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis */ - private function init($redisClient, $namespace = '', $defaultLifetime = 0) + private function init($redis, string $namespace, int $defaultLifetime, ?MarshallerInterface $marshaller) { parent::__construct($namespace, $defaultLifetime); if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } - if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) { - throw new InvalidArgumentException(sprintf('"%s()" expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, "%s" given.', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient))); + + if (!$redis instanceof \Redis && !$redis instanceof \RedisArray && !$redis instanceof \RedisCluster && !$redis instanceof \Predis\ClientInterface && !$redis instanceof RedisProxy && !$redis instanceof RedisClusterProxy) { + throw new InvalidArgumentException(sprintf('"%s()" expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, "%s" given.', __METHOD__, \is_object($redis) ? \get_class($redis) : \gettype($redis))); + } + + if ($redis instanceof \Predis\ClientInterface && $redis->getOptions()->exceptions) { + $options = clone $redis->getOptions(); + \Closure::bind(function () { $this->options['exceptions'] = false; }, $options, $options)(); + $redis = new $redis($redis->getConnection(), $options); } - $this->redis = $redisClient; + + $this->redis = $redis; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); } /** @@ -68,57 +87,117 @@ private function init($redisClient, $namespace = '', $defaultLifetime = 0) * * @throws InvalidArgumentException when the DSN is invalid * - * @return \Redis|\Predis\Client According to the "class" option + * @return \Redis|\RedisCluster|RedisClusterProxy|RedisProxy|\Predis\ClientInterface According to the "class" option */ public static function createConnection($dsn, array $options = []) { - if (0 !== strpos($dsn, 'redis://')) { - throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s" does not start with "redis://".', $dsn)); + if (str_starts_with($dsn, 'redis:')) { + $scheme = 'redis'; + } elseif (str_starts_with($dsn, 'rediss:')) { + $scheme = 'rediss'; + } else { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s" does not start with "redis:" or "rediss".', $dsn)); + } + + if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { + throw new CacheException(sprintf('Cannot find the "redis" extension nor the "predis/predis" package: "%s".', $dsn)); } - $params = preg_replace_callback('#^redis://(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { - if (isset($m[1])) { - $auth = $m[1]; + + $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { + if (isset($m[2])) { + $auth = $m[2]; + + if ('' === $auth) { + $auth = null; + } } - return 'file://'; + return 'file:'.($m[1] ?? ''); }, $dsn); + if (false === $params = parse_url($params)) { throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn)); } - if (!isset($params['host']) && !isset($params['path'])) { - throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn)); + + $query = $hosts = []; + + $tls = 'rediss' === $scheme; + $tcpScheme = $tls ? 'tls' : 'tcp'; + + if (isset($params['query'])) { + parse_str($params['query'], $query); + + if (isset($query['host'])) { + if (!\is_array($hosts = $query['host'])) { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn)); + } + foreach ($hosts as $host => $parameters) { + if (\is_string($parameters)) { + parse_str($parameters, $parameters); + } + if (false === $i = strrpos($host, ':')) { + $hosts[$host] = ['scheme' => $tcpScheme, 'host' => $host, 'port' => 6379] + $parameters; + } elseif ($port = (int) substr($host, 1 + $i)) { + $hosts[$host] = ['scheme' => $tcpScheme, 'host' => substr($host, 0, $i), 'port' => $port] + $parameters; + } else { + $hosts[$host] = ['scheme' => 'unix', 'path' => substr($host, 0, $i)] + $parameters; + } + } + $hosts = array_values($hosts); + } } - if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) { - $params['dbindex'] = $m[1]; - $params['path'] = substr($params['path'], 0, -\strlen($m[0])); + + if (isset($params['host']) || isset($params['path'])) { + if (!isset($params['dbindex']) && isset($params['path'])) { + if (preg_match('#/(\d+)$#', $params['path'], $m)) { + $params['dbindex'] = $m[1]; + $params['path'] = substr($params['path'], 0, -\strlen($m[0])); + } elseif (isset($params['host'])) { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s", the "dbindex" parameter must be a number.', $dsn)); + } + } + + if (isset($params['host'])) { + array_unshift($hosts, ['scheme' => $tcpScheme, 'host' => $params['host'], 'port' => $params['port'] ?? 6379]); + } else { + array_unshift($hosts, ['scheme' => 'unix', 'path' => $params['path']]); + } } - if (isset($params['host'])) { - $scheme = 'tcp'; - } else { - $scheme = 'unix'; + + if (!$hosts) { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s".', $dsn)); } - $params += [ - 'host' => isset($params['host']) ? $params['host'] : $params['path'], - 'port' => isset($params['host']) ? 6379 : null, - 'dbindex' => 0, - ]; - if (isset($params['query'])) { - parse_str($params['query'], $query); - $params += $query; + + $params += $query + $options + self::$defaultConnectionOptions; + + if (isset($params['redis_sentinel']) && !class_exists(\Predis\Client::class)) { + throw new CacheException(sprintf('Redis Sentinel support requires the "predis/predis" package: "%s".', $dsn)); } - $params += $options + self::$defaultConnectionOptions; - if (null === $params['class'] && !\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { - throw new CacheException(sprintf('Cannot find the "redis" extension, and "predis/predis" is not installed: "%s".', $dsn)); + + if (null === $params['class'] && !isset($params['redis_sentinel']) && \extension_loaded('redis')) { + $class = $params['redis_cluster'] ? \RedisCluster::class : (1 < \count($hosts) ? \RedisArray::class : \Redis::class); + } else { + $class = $params['class'] ?? \Predis\Client::class; + + if (isset($params['redis_sentinel']) && !is_a($class, \Predis\Client::class, true)) { + throw new CacheException(sprintf('Cannot use Redis Sentinel: class "%s" does not extend "Predis\Client": "%s".', $class, $dsn)); + } } - $class = null === $params['class'] ? (\extension_loaded('redis') ? \Redis::class : \Predis\Client::class) : $params['class']; if (is_a($class, \Redis::class, true)) { $connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect'; $redis = new $class(); - $initializer = function ($redis) use ($connect, $params, $dsn, $auth) { + $initializer = static function ($redis) use ($connect, $params, $dsn, $auth, $hosts, $tls) { + $host = $hosts[0]['host'] ?? $hosts[0]['path']; + $port = $hosts[0]['port'] ?? 0; + + if (isset($hosts[0]['host']) && $tls) { + $host = 'tls://'.$host; + } + try { - @$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']); + @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') ? [['stream' => $params['ssl'] ?? null]] : []); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); $isConnected = $redis->isConnected(); @@ -130,11 +209,14 @@ public static function createConnection($dsn, array $options = []) if ((null !== $auth && !$redis->auth($auth)) || ($params['dbindex'] && !$redis->select($params['dbindex'])) - || ($params['read_timeout'] && !$redis->setOption(\Redis::OPT_READ_TIMEOUT, $params['read_timeout'])) ) { $e = preg_replace('/^ERR /', '', $redis->getLastError()); throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e.'.'); } + + if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) { + $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } } catch (\RedisException $e) { throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage()); } @@ -147,13 +229,92 @@ public static function createConnection($dsn, array $options = []) } else { $initializer($redis); } - } elseif (is_a($class, \Predis\Client::class, true)) { - $params['scheme'] = $scheme; - $params['database'] = $params['dbindex'] ?: null; - $params['password'] = $auth; - $redis = new $class((new Factory())->create($params)); + } elseif (is_a($class, \RedisArray::class, true)) { + foreach ($hosts as $i => $host) { + switch ($host['scheme']) { + case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break; + case 'tls': $hosts[$i] = 'tls://'.$host['host'].':'.$host['port']; break; + default: $hosts[$i] = $host['path']; + } + } + $params['lazy_connect'] = $params['lazy'] ?? true; + $params['connect_timeout'] = $params['timeout']; + + try { + $redis = new $class($hosts, $params); + } catch (\RedisClusterException $e) { + throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage()); + } + + if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) { + $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + } elseif (is_a($class, \RedisCluster::class, true)) { + $initializer = static function () use ($class, $params, $dsn, $hosts) { + foreach ($hosts as $i => $host) { + switch ($host['scheme']) { + case 'tcp': $hosts[$i] = $host['host'].':'.$host['port']; break; + case 'tls': $hosts[$i] = 'tls://'.$host['host'].':'.$host['port']; break; + default: $hosts[$i] = $host['path']; + } + } + + try { + $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', ...\defined('Redis::SCAN_PREFIX') ? [$params['ssl'] ?? null] : []); + } catch (\RedisClusterException $e) { + throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage()); + } + + if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) { + $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + switch ($params['failover']) { + case 'error': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_ERROR); break; + case 'distribute': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE); break; + case 'slaves': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES); break; + } + + return $redis; + }; + + $redis = $params['lazy'] ? new RedisClusterProxy($initializer) : $initializer(); + } elseif (is_a($class, \Predis\ClientInterface::class, true)) { + if ($params['redis_cluster']) { + $params['cluster'] = 'redis'; + if (isset($params['redis_sentinel'])) { + throw new InvalidArgumentException(sprintf('Cannot use both "redis_cluster" and "redis_sentinel" at the same time: "%s".', $dsn)); + } + } elseif (isset($params['redis_sentinel'])) { + $params['replication'] = 'sentinel'; + $params['service'] = $params['redis_sentinel']; + } + $params += ['parameters' => []]; + $params['parameters'] += [ + 'persistent' => $params['persistent'], + 'timeout' => $params['timeout'], + 'read_write_timeout' => $params['read_timeout'], + 'tcp_nodelay' => true, + ]; + if ($params['dbindex']) { + $params['parameters']['database'] = $params['dbindex']; + } + if (null !== $auth) { + $params['parameters']['password'] = $auth; + } + if (1 === \count($hosts) && !($params['redis_cluster'] || $params['redis_sentinel'])) { + $hosts = $hosts[0]; + } elseif (\in_array($params['failover'], ['slaves', 'distribute'], true) && !isset($params['replication'])) { + $params['replication'] = true; + $hosts[0] += ['alias' => 'master']; + } + $params['exceptions'] = false; + + $redis = new $class($hosts, array_diff_key($params, array_diff_key(self::$defaultConnectionOptions, ['ssl' => null]))); + if (isset($params['redis_sentinel'])) { + $redis->getConnection()->setSentinelTimeout($params['timeout']); + } } elseif (class_exists($class, false)) { - throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis" or "Predis\Client".', $class)); + throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster" nor "Predis\ClientInterface".', $class)); } else { throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); } @@ -172,7 +333,7 @@ protected function doFetch(array $ids) $result = []; - if ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface) { + if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) { $values = $this->pipeline(function () use ($ids) { foreach ($ids as $id) { yield 'get' => [$id]; @@ -190,7 +351,7 @@ protected function doFetch(array $ids) foreach ($values as $id => $v) { if ($v) { - $result[$id] = parent::unserialize($v); + $result[$id] = $this->marshaller->unmarshall($v); } } @@ -210,32 +371,19 @@ protected function doHave($id) */ protected function doClear($namespace) { - $cleared = true; - $hosts = [$this->redis]; - $evalArgs = [[$namespace], 0]; - - if ($this->redis instanceof \Predis\Client) { - $evalArgs = [0, $namespace]; + if ($this->redis instanceof \Predis\ClientInterface) { + $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : ''; + $prefixLen = \strlen($prefix ?? ''); + } - $connection = $this->redis->getConnection(); - if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { - $hosts = []; - foreach ($connection as $c) { - $hosts[] = new \Predis\Client($c); - } - } - } elseif ($this->redis instanceof \RedisArray) { - $hosts = []; - foreach ($this->redis->_hosts() as $host) { - $hosts[] = $this->redis->_instance($host); - } - } elseif ($this->redis instanceof \RedisCluster) { - $hosts = []; - foreach ($this->redis->_masters() as $host) { - $hosts[] = $h = new \Redis(); - $h->connect($host[0], $host[1]); - } + $cleared = true; + $hosts = $this->getHosts(); + $host = reset($hosts); + if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { + // Predis supports info command only on the master in replication environments + $hosts = [$host->getClientFor('master')]; } + foreach ($hosts as $host) { if (!isset($namespace[0])) { $cleared = $host->flushDb() && $cleared; @@ -243,24 +391,36 @@ protected function doClear($namespace) } $info = $host->info('Server'); - $info = isset($info['Server']) ? $info['Server'] : $info; + $info = !$info instanceof ErrorInterface ? $info['Server'] ?? $info : ['redis_version' => '2.0']; + + if (!$host instanceof \Predis\ClientInterface) { + $prefix = \defined('Redis::SCAN_PREFIX') && (\Redis::SCAN_PREFIX & $host->getOption(\Redis::OPT_SCAN)) ? '' : $host->getOption(\Redis::OPT_PREFIX); + $prefixLen = \strlen($host->getOption(\Redis::OPT_PREFIX) ?? ''); + } + $pattern = $prefix.$namespace.'*'; if (!version_compare($info['redis_version'], '2.8', '>=')) { // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS // can hang your server when it is executed against large databases (millions of items). // Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above. - $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]..'*') for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $evalArgs[0], $evalArgs[1]) && $cleared; + $args = $this->redis instanceof \Predis\ClientInterface ? [0, $pattern] : [[$pattern], 0]; + $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]) for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $args[0], $args[1]) && $cleared; continue; } $cursor = null; do { - $keys = $host instanceof \Predis\Client ? $host->scan($cursor, 'MATCH', $namespace.'*', 'COUNT', 1000) : $host->scan($cursor, $namespace.'*', 1000); + $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000); if (isset($keys[1]) && \is_array($keys[1])) { $cursor = $keys[0]; $keys = $keys[1]; } if ($keys) { + if ($prefixLen) { + foreach ($keys as $i => $key) { + $keys[$i] = substr($key, $prefixLen); + } + } $this->doDelete($keys); } } while ($cursor = (int) $cursor); @@ -278,7 +438,7 @@ protected function doDelete(array $ids) return true; } - if ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface) { + if ($this->redis instanceof \Predis\ClientInterface && $this->redis->getConnection() instanceof ClusterInterface) { $this->pipeline(function () use ($ids) { foreach ($ids as $id) { yield 'del' => [$id]; @@ -294,25 +454,14 @@ protected function doDelete(array $ids) /** * {@inheritdoc} */ - protected function doSave(array $values, $lifetime) + protected function doSave(array $values, int $lifetime) { - $serialized = []; - $failed = []; - - foreach ($values as $id => $value) { - try { - $serialized[$id] = serialize($value); - } catch (\Exception $e) { - $failed[] = $id; - } - } - - if (!$serialized) { + if (!$values = $this->marshaller->marshall($values, $failed)) { return $failed; } - $results = $this->pipeline(function () use ($serialized, $lifetime) { - foreach ($serialized as $id => $value) { + $results = $this->pipeline(function () use ($values, $lifetime) { + foreach ($values as $id => $value) { if (0 >= $lifetime) { yield 'set' => [$id, $value]; } else { @@ -320,8 +469,9 @@ protected function doSave(array $values, $lifetime) } } }); + foreach ($results as $id => $result) { - if (true !== $result && (!$result instanceof Status || $result !== Status::get('OK'))) { + if (true !== $result && (!$result instanceof Status || Status::get('OK') !== $result)) { $failed[] = $id; } } @@ -329,54 +479,87 @@ protected function doSave(array $values, $lifetime) return $failed; } - private function pipeline(\Closure $generator) + private function pipeline(\Closure $generator, $redis = null): \Generator { $ids = []; + $redis = $redis ?? $this->redis; - if ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof RedisCluster)) { + if ($redis instanceof RedisClusterProxy || $redis instanceof \RedisCluster || ($redis instanceof \Predis\ClientInterface && $redis->getConnection() instanceof RedisCluster)) { // phpredis & predis don't support pipelining with RedisCluster // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining // see https://github.com/nrk/predis/issues/267#issuecomment-123781423 $results = []; foreach ($generator() as $command => $args) { - $results[] = \call_user_func_array([$this->redis, $command], $args); - $ids[] = $args[0]; + $results[] = $redis->{$command}(...$args); + $ids[] = 'eval' === $command ? ($redis instanceof \Predis\ClientInterface ? $args[2] : $args[1][0]) : $args[0]; } - } elseif ($this->redis instanceof \Predis\Client) { - $results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) { + } elseif ($redis instanceof \Predis\ClientInterface) { + $results = $redis->pipeline(static function ($redis) use ($generator, &$ids) { foreach ($generator() as $command => $args) { - \call_user_func_array([$redis, $command], $args); - $ids[] = $args[0]; + $redis->{$command}(...$args); + $ids[] = 'eval' === $command ? $args[2] : $args[0]; } }); - } elseif ($this->redis instanceof \RedisArray) { + } elseif ($redis instanceof \RedisArray) { $connections = $results = $ids = []; foreach ($generator() as $command => $args) { - if (!isset($connections[$h = $this->redis->_target($args[0])])) { - $connections[$h] = [$this->redis->_instance($h), -1]; + $id = 'eval' === $command ? $args[1][0] : $args[0]; + if (!isset($connections[$h = $redis->_target($id)])) { + $connections[$h] = [$redis->_instance($h), -1]; $connections[$h][0]->multi(\Redis::PIPELINE); } - \call_user_func_array([$connections[$h][0], $command], $args); + $connections[$h][0]->{$command}(...$args); $results[] = [$h, ++$connections[$h][1]]; - $ids[] = $args[0]; + $ids[] = $id; } foreach ($connections as $h => $c) { $connections[$h] = $c[0]->exec(); } - foreach ($results as $k => list($h, $c)) { + foreach ($results as $k => [$h, $c]) { $results[$k] = $connections[$h][$c]; } } else { - $this->redis->multi(\Redis::PIPELINE); + $redis->multi(\Redis::PIPELINE); foreach ($generator() as $command => $args) { - \call_user_func_array([$this->redis, $command], $args); - $ids[] = $args[0]; + $redis->{$command}(...$args); + $ids[] = 'eval' === $command ? $args[1][0] : $args[0]; } - $results = $this->redis->exec(); + $results = $redis->exec(); + } + + if (!$redis instanceof \Predis\ClientInterface && 'eval' === $command && $redis->getLastError()) { + $e = new \RedisException($redis->getLastError()); + $results = array_map(function ($v) use ($e) { return false === $v ? $e : $v; }, $results); } foreach ($ids as $k => $id) { yield $id => $results[$k]; } } + + private function getHosts(): array + { + $hosts = [$this->redis]; + if ($this->redis instanceof \Predis\ClientInterface) { + $connection = $this->redis->getConnection(); + if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { + $hosts = []; + foreach ($connection as $c) { + $hosts[] = new \Predis\Client($c); + } + } + } elseif ($this->redis instanceof \RedisArray) { + $hosts = []; + foreach ($this->redis->_hosts() as $host) { + $hosts[] = $this->redis->_instance($host); + } + } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { + $hosts = []; + foreach ($this->redis->_masters() as $host) { + $hosts[] = new RedisClusterNodeProxy($host, $this->redis); + } + } + + return $hosts; + } } diff --git a/vendor/symfony/cache/composer.json b/vendor/symfony/cache/composer.json index f412e4f1..7a9e8df5 100644 --- a/vendor/symfony/cache/composer.json +++ b/vendor/symfony/cache/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/cache", "type": "library", - "description": "Symfony Cache component with PSR-6, PSR-16, and tags", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", "keywords": ["caching", "psr6"], "homepage": "https://symfony.com", "license": "MIT", @@ -16,24 +16,37 @@ } ], "provide": { - "psr/cache-implementation": "1.0", - "psr/simple-cache-implementation": "1.0" + "psr/cache-implementation": "1.0|2.0", + "psr/simple-cache-implementation": "1.0|2.0", + "symfony/cache-implementation": "1.0|2.0" }, "require": { - "php": "^5.5.9|>=7.0.8", - "psr/cache": "~1.0", - "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/polyfill-apcu": "~1.1" + "php": ">=7.1.3", + "psr/cache": "^1.0|^2.0", + "psr/log": "^1|^2|^3", + "symfony/cache-contracts": "^1.1.7|^2", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.2|^5.0" }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/cache": "^1.6", - "doctrine/dbal": "^2.4|^3.0", - "predis/predis": "^1.0" + "doctrine/cache": "^1.6|^2.0", + "doctrine/dbal": "^2.7|^3.0", + "predis/predis": "^1.1", + "psr/simple-cache": "^1.0|^2.0", + "symfony/config": "^4.2|^5.0", + "symfony/dependency-injection": "^3.4|^4.1|^5.0", + "symfony/filesystem": "^4.4|^5.0", + "symfony/http-kernel": "^4.4", + "symfony/var-dumper": "^4.4|^5.0" }, "conflict": { - "symfony/var-dumper": "<3.3" + "doctrine/dbal": "<2.7", + "symfony/dependency-injection": "<3.4", + "symfony/http-kernel": "<4.4|>=5.0", + "symfony/var-dumper": "<4.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Cache\\": "" }, diff --git a/vendor/symfony/cache/phpunit.xml.dist b/vendor/symfony/cache/phpunit.xml.dist deleted file mode 100644 index c35458ca..00000000 --- a/vendor/symfony/cache/phpunit.xml.dist +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Tests - ./vendor - - - - - - - - - - - Cache\IntegrationTests - Doctrine\Common\Cache - Symfony\Component\Cache - Symfony\Component\Cache\Tests\Fixtures - Symfony\Component\Cache\Traits - - - - - - - diff --git a/vendor/symfony/config/CHANGELOG.md b/vendor/symfony/config/CHANGELOG.md index 6cb610c4..a650e10a 100644 --- a/vendor/symfony/config/CHANGELOG.md +++ b/vendor/symfony/config/CHANGELOG.md @@ -1,6 +1,36 @@ CHANGELOG ========= +4.4.0 +----- + + * added a way to exclude patterns of resources from being imported by the `import()` method + +4.3.0 +----- + + * deprecated using environment variables with `cannotBeEmpty()` if the value is validated with `validate()` + * made `Resource\*` classes final and not implement `Serializable` anymore + * deprecated the `root()` method in `TreeBuilder`, pass the root node information to the constructor instead + +4.2.0 +----- + + * deprecated constructing a `TreeBuilder` without passing root node information + * renamed `FileLoaderLoadException` to `LoaderLoadException` + +4.1.0 +----- + + * added `setPathSeparator` method to `NodeBuilder` class + * added third `$pathSeparator` constructor argument to `BaseNode` + * the `Processor` class has been made final + +4.0.0 +----- + + * removed `ConfigCachePass` + 3.4.0 ----- diff --git a/vendor/symfony/config/ConfigCache.php b/vendor/symfony/config/ConfigCache.php index b2a39076..053059b8 100644 --- a/vendor/symfony/config/ConfigCache.php +++ b/vendor/symfony/config/ConfigCache.php @@ -31,9 +31,9 @@ class ConfigCache extends ResourceCheckerConfigCache * @param string $file The absolute cache path * @param bool $debug Whether debugging is enabled or not */ - public function __construct($file, $debug) + public function __construct(string $file, bool $debug) { - $this->debug = (bool) $debug; + $this->debug = $debug; $checkers = []; if (true === $this->debug) { diff --git a/vendor/symfony/config/ConfigCacheFactory.php b/vendor/symfony/config/ConfigCacheFactory.php index 7903cca9..bfb70cb2 100644 --- a/vendor/symfony/config/ConfigCacheFactory.php +++ b/vendor/symfony/config/ConfigCacheFactory.php @@ -27,7 +27,7 @@ class ConfigCacheFactory implements ConfigCacheFactoryInterface /** * @param bool $debug The debug flag to pass to ConfigCache */ - public function __construct($debug) + public function __construct(bool $debug) { $this->debug = $debug; } @@ -43,7 +43,7 @@ public function cache($file, $callback) $cache = new ConfigCache($file, $this->debug); if (!$cache->isFresh()) { - \call_user_func($callback, $cache); + $callback($cache); } return $cache; diff --git a/vendor/symfony/config/Definition/ArrayNode.php b/vendor/symfony/config/Definition/ArrayNode.php index 59a0af87..34201709 100644 --- a/vendor/symfony/config/Definition/ArrayNode.php +++ b/vendor/symfony/config/Definition/ArrayNode.php @@ -55,7 +55,7 @@ protected function preNormalize($value) $normalized = []; foreach ($value as $k => $v) { - if (false !== strpos($k, '-') && false === strpos($k, '_') && !\array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) { + if (str_contains($k, '-') && !str_contains($k, '_') && !\array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) { $normalized[$normalizedKey] = $v; } else { $normalized[$k] = $v; @@ -68,7 +68,7 @@ protected function preNormalize($value) /** * Retrieves the children of this node. * - * @return array The children + * @return array */ public function getChildren() { @@ -192,7 +192,7 @@ public function getDefaultValue() public function addChild(NodeInterface $node) { $name = $node->getName(); - if (!\strlen($name)) { + if ('' === $name) { throw new \InvalidArgumentException('Child nodes must be named.'); } if (isset($this->children[$name])) { @@ -203,11 +203,7 @@ public function addChild(NodeInterface $node) } /** - * Finalizes the value of this node. - * - * @param mixed $value - * - * @return mixed The finalised value + * {@inheritdoc} * * @throws UnsetKeyException * @throws InvalidConfigurationException if the node doesn't have enough children @@ -249,11 +245,7 @@ protected function finalizeValue($value) } /** - * Validates the type of the value. - * - * @param mixed $value - * - * @throws InvalidTypeException + * {@inheritdoc} */ protected function validateType($value) { @@ -269,11 +261,7 @@ protected function validateType($value) } /** - * Normalizes the value. - * - * @param mixed $value The value to normalize - * - * @return mixed The normalized value + * {@inheritdoc} * * @throws InvalidConfigurationException */ @@ -300,7 +288,31 @@ protected function normalizeValue($value) // if extra fields are present, throw exception if (\count($value) && !$this->ignoreExtraKeys) { - $ex = new InvalidConfigurationException(sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath())); + $proposals = array_keys($this->children); + sort($proposals); + $guesses = []; + + foreach (array_keys($value) as $subject) { + $minScore = \INF; + foreach ($proposals as $proposal) { + $distance = levenshtein($subject, $proposal); + if ($distance <= $minScore && $distance < 3) { + $guesses[$proposal] = $distance; + $minScore = $distance; + } + } + } + + $msg = sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath()); + + if (\count($guesses)) { + asort($guesses); + $msg .= sprintf('. Did you mean "%s"?', implode('", "', array_keys($guesses))); + } else { + $msg .= sprintf('. Available option%s %s "%s".', 1 === \count($proposals) ? '' : 's', 1 === \count($proposals) ? 'is' : 'are', implode('", "', $proposals)); + } + + $ex = new InvalidConfigurationException($msg); $ex->setPath($this->getPath()); throw $ex; @@ -318,7 +330,7 @@ protected function normalizeValue($value) */ protected function remapXml($value) { - foreach ($this->xmlRemappings as list($singular, $plural)) { + foreach ($this->xmlRemappings as [$singular, $plural]) { if (!isset($value[$singular])) { continue; } @@ -331,12 +343,7 @@ protected function remapXml($value) } /** - * Merges values together. - * - * @param mixed $leftSide The left side to merge - * @param mixed $rightSide The right side to merge - * - * @return mixed The merged values + * {@inheritdoc} * * @throws InvalidConfigurationException * @throws \RuntimeException @@ -368,7 +375,12 @@ protected function mergeValues($leftSide, $rightSide) } if (!isset($this->children[$k])) { - throw new \RuntimeException('merge() expects a normalized config array.'); + if (!$this->ignoreExtraKeys || $this->removeExtraKeys) { + throw new \RuntimeException('merge() expects a normalized config array.'); + } + + $leftSide[$k] = $v; + continue; } $leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v); @@ -376,4 +388,12 @@ protected function mergeValues($leftSide, $rightSide) return $leftSide; } + + /** + * {@inheritdoc} + */ + protected function allowPlaceholders(): bool + { + return false; + } } diff --git a/vendor/symfony/config/Definition/BaseNode.php b/vendor/symfony/config/Definition/BaseNode.php index 10bcb49c..209e3d26 100644 --- a/vendor/symfony/config/Definition/BaseNode.php +++ b/vendor/symfony/config/Definition/BaseNode.php @@ -15,6 +15,7 @@ use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\Config\Definition\Exception\InvalidTypeException; +use Symfony\Component\Config\Definition\Exception\UnsetKeyException; /** * The base node class. @@ -23,6 +24,11 @@ */ abstract class BaseNode implements NodeInterface { + public const DEFAULT_PATH_SEPARATOR = '.'; + + private static $placeholderUniquePrefixes = []; + private static $placeholders = []; + protected $name; protected $parent; protected $normalizationClosures = []; @@ -32,21 +38,63 @@ abstract class BaseNode implements NodeInterface protected $deprecationMessage = null; protected $equivalentValues = []; protected $attributes = []; + protected $pathSeparator; + + private $handlingPlaceholder; /** - * @param string|null $name The name of the node - * @param NodeInterface|null $parent The parent of this node - * * @throws \InvalidArgumentException if the name contains a period */ - public function __construct($name, NodeInterface $parent = null) + public function __construct(?string $name, NodeInterface $parent = null, string $pathSeparator = self::DEFAULT_PATH_SEPARATOR) { - if (false !== strpos($name = (string) $name, '.')) { - throw new \InvalidArgumentException('The name must not contain ".".'); + if (str_contains($name = (string) $name, $pathSeparator)) { + throw new \InvalidArgumentException('The name must not contain ".'.$pathSeparator.'".'); } $this->name = $name; $this->parent = $parent; + $this->pathSeparator = $pathSeparator; + } + + /** + * Register possible (dummy) values for a dynamic placeholder value. + * + * Matching configuration values will be processed with a provided value, one by one. After a provided value is + * successfully processed the configuration value is returned as is, thus preserving the placeholder. + * + * @internal + */ + public static function setPlaceholder(string $placeholder, array $values): void + { + if (!$values) { + throw new \InvalidArgumentException('At least one value must be provided.'); + } + + self::$placeholders[$placeholder] = $values; + } + + /** + * Adds a common prefix for dynamic placeholder values. + * + * Matching configuration values will be skipped from being processed and are returned as is, thus preserving the + * placeholder. An exact match provided by {@see setPlaceholder()} might take precedence. + * + * @internal + */ + public static function setPlaceholderUniquePrefix(string $prefix): void + { + self::$placeholderUniquePrefixes[] = $prefix; + } + + /** + * Resets all current placeholders available. + * + * @internal + */ + public static function resetPlaceholders(): void + { + self::$placeholderUniquePrefixes = []; + self::$placeholders = []; } /** @@ -64,7 +112,7 @@ public function setAttribute($key, $value) */ public function getAttribute($key, $default = null) { - return isset($this->attributes[$key]) ? $this->attributes[$key] : $default; + return $this->attributes[$key] ?? $default; } /** @@ -246,13 +294,11 @@ public function getName() */ public function getPath() { - $path = $this->name; - if (null !== $this->parent) { - $path = $this->parent->getPath().'.'.$path; + return $this->parent->getPath().$this->pathSeparator.$this->name; } - return $path; + return $this->name; } /** @@ -264,8 +310,34 @@ final public function merge($leftSide, $rightSide) throw new ForbiddenOverwriteException(sprintf('Configuration path "%s" cannot be overwritten. You have to define all options for this path, and any of its sub-paths in one configuration section.', $this->getPath())); } - $this->validateType($leftSide); - $this->validateType($rightSide); + if ($leftSide !== $leftPlaceholders = self::resolvePlaceholderValue($leftSide)) { + foreach ($leftPlaceholders as $leftPlaceholder) { + $this->handlingPlaceholder = $leftSide; + try { + $this->merge($leftPlaceholder, $rightSide); + } finally { + $this->handlingPlaceholder = null; + } + } + + return $rightSide; + } + + if ($rightSide !== $rightPlaceholders = self::resolvePlaceholderValue($rightSide)) { + foreach ($rightPlaceholders as $rightPlaceholder) { + $this->handlingPlaceholder = $rightSide; + try { + $this->merge($leftSide, $rightPlaceholder); + } finally { + $this->handlingPlaceholder = null; + } + } + + return $rightSide; + } + + $this->doValidateType($leftSide); + $this->doValidateType($rightSide); return $this->mergeValues($leftSide, $rightSide); } @@ -282,6 +354,20 @@ final public function normalize($value) $value = $closure($value); } + // resolve placeholder value + if ($value !== $placeholders = self::resolvePlaceholderValue($value)) { + foreach ($placeholders as $placeholder) { + $this->handlingPlaceholder = $value; + try { + $this->normalize($placeholder); + } finally { + $this->handlingPlaceholder = null; + } + } + + return $value; + } + // replace value with their equivalent foreach ($this->equivalentValues as $data) { if ($data[0] === $value) { @@ -290,7 +376,7 @@ final public function normalize($value) } // validate type - $this->validateType($value); + $this->doValidateType($value); // normalize value return $this->normalizeValue($value); @@ -323,7 +409,20 @@ public function getParent() */ final public function finalize($value) { - $this->validateType($value); + if ($value !== $placeholders = self::resolvePlaceholderValue($value)) { + foreach ($placeholders as $placeholder) { + $this->handlingPlaceholder = $value; + try { + $this->finalize($placeholder); + } finally { + $this->handlingPlaceholder = null; + } + } + + return $value; + } + + $this->doValidateType($value); $value = $this->finalizeValue($value); @@ -333,6 +432,10 @@ final public function finalize($value) try { $value = $closure($value); } catch (Exception $e) { + if ($e instanceof UnsetKeyException && null !== $this->handlingPlaceholder) { + continue; + } + throw $e; } catch (\Exception $e) { throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": ', $this->getPath()).$e->getMessage(), $e->getCode(), $e); @@ -378,4 +481,81 @@ abstract protected function mergeValues($leftSide, $rightSide); * @return mixed The finalized value */ abstract protected function finalizeValue($value); + + /** + * Tests if placeholder values are allowed for this node. + */ + protected function allowPlaceholders(): bool + { + return true; + } + + /** + * Tests if a placeholder is being handled currently. + */ + protected function isHandlingPlaceholder(): bool + { + return null !== $this->handlingPlaceholder; + } + + /** + * Gets allowed dynamic types for this node. + */ + protected function getValidPlaceholderTypes(): array + { + return []; + } + + private static function resolvePlaceholderValue($value) + { + if (\is_string($value)) { + if (isset(self::$placeholders[$value])) { + return self::$placeholders[$value]; + } + + foreach (self::$placeholderUniquePrefixes as $placeholderUniquePrefix) { + if (str_starts_with($value, $placeholderUniquePrefix)) { + return []; + } + } + } + + return $value; + } + + private function doValidateType($value): void + { + if (null !== $this->handlingPlaceholder && !$this->allowPlaceholders()) { + $e = new InvalidTypeException(sprintf('A dynamic value is not compatible with a "%s" node type at path "%s".', static::class, $this->getPath())); + $e->setPath($this->getPath()); + + throw $e; + } + + if (null === $this->handlingPlaceholder || null === $value) { + $this->validateType($value); + + return; + } + + $knownTypes = array_keys(self::$placeholders[$this->handlingPlaceholder]); + $validTypes = $this->getValidPlaceholderTypes(); + + if ($validTypes && array_diff($knownTypes, $validTypes)) { + $e = new InvalidTypeException(sprintf( + 'Invalid type for path "%s". Expected %s, but got %s.', + $this->getPath(), + 1 === \count($validTypes) ? '"'.reset($validTypes).'"' : 'one of "'.implode('", "', $validTypes).'"', + 1 === \count($knownTypes) ? '"'.reset($knownTypes).'"' : 'one of "'.implode('", "', $knownTypes).'"' + )); + if ($hint = $this->getInfo()) { + $e->addHint($hint); + } + $e->setPath($this->getPath()); + + throw $e; + } + + $this->validateType($value); + } } diff --git a/vendor/symfony/config/Definition/BooleanNode.php b/vendor/symfony/config/Definition/BooleanNode.php index 85f467b6..c43c46f0 100644 --- a/vendor/symfony/config/Definition/BooleanNode.php +++ b/vendor/symfony/config/Definition/BooleanNode.php @@ -44,4 +44,12 @@ protected function isValueEmpty($value) // a boolean value cannot be empty return false; } + + /** + * {@inheritdoc} + */ + protected function getValidPlaceholderTypes(): array + { + return ['bool']; + } } diff --git a/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php b/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php index da4ebf62..61348387 100644 --- a/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.php @@ -39,7 +39,7 @@ class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinition /** * {@inheritdoc} */ - public function __construct($name, NodeParentInterface $parent = null) + public function __construct(?string $name, NodeParentInterface $parent = null) { parent::__construct($name, $parent); @@ -280,8 +280,8 @@ public function canBeEnabled() ->treatNullLike(['enabled' => true]) ->beforeNormalization() ->ifArray() - ->then(function ($v) { - $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true; + ->then(function (array $v) { + $v['enabled'] = $v['enabled'] ?? true; return $v; }) @@ -393,7 +393,7 @@ protected function getNodeBuilder() protected function createNode() { if (null === $this->prototype) { - $node = new ArrayNode($this->name, $this->parent); + $node = new ArrayNode($this->name, $this->parent, $this->pathSeparator); $this->validateConcreteNode($node); @@ -404,7 +404,7 @@ protected function createNode() $node->addChild($child->getNode()); } } else { - $node = new PrototypedArrayNode($this->name, $this->parent); + $node = new PrototypedArrayNode($this->name, $this->parent, $this->pathSeparator); $this->validatePrototypeNode($node); @@ -412,11 +412,7 @@ protected function createNode() $node->setKeyAttribute($this->key, $this->removeKeyItem); } - if (false === $this->allowEmptyValue) { - @trigger_error(sprintf('Using %s::cannotBeEmpty() at path "%s" has no effect, consider requiresAtLeastOneElement() instead. In 4.0 both methods will behave the same.', __CLASS__, $node->getPath()), \E_USER_DEPRECATED); - } - - if (true === $this->atLeastOne) { + if (true === $this->atLeastOne || false === $this->allowEmptyValue) { $node->setMinNumberOfElements(1); } @@ -476,7 +472,7 @@ protected function validateConcreteNode(ArrayNode $node) } if (false === $this->allowEmptyValue) { - @trigger_error(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s". In 4.0 it will throw an exception.', $path), \E_USER_DEPRECATED); + throw new InvalidDefinitionException(sprintf('->cannotBeEmpty() is not applicable to concrete nodes at path "%s".', $path)); } if (true === $this->atLeastOne) { @@ -519,4 +515,34 @@ protected function validatePrototypeNode(PrototypedArrayNode $node) } } } + + /** + * @return NodeDefinition[] + */ + public function getChildNodeDefinitions() + { + return $this->children; + } + + /** + * Finds a node defined by the given $nodePath. + * + * @param string $nodePath The path of the node to find. e.g "doctrine.orm.mappings" + */ + public function find(string $nodePath): NodeDefinition + { + $firstPathSegment = (false === $pathSeparatorPos = strpos($nodePath, $this->pathSeparator)) + ? $nodePath + : substr($nodePath, 0, $pathSeparatorPos); + + if (null === $node = ($this->children[$firstPathSegment] ?? null)) { + throw new \RuntimeException(sprintf('Node with name "%s" does not exist in the current node "%s".', $firstPathSegment, $this->name)); + } + + if (false === $pathSeparatorPos) { + return $node; + } + + return $node->find(substr($nodePath, $pathSeparatorPos + \strlen($this->pathSeparator))); + } } diff --git a/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php b/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php index 28e56579..d1932427 100644 --- a/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php @@ -24,7 +24,7 @@ class BooleanNodeDefinition extends ScalarNodeDefinition /** * {@inheritdoc} */ - public function __construct($name, NodeParentInterface $parent = null) + public function __construct(?string $name, NodeParentInterface $parent = null) { parent::__construct($name, $parent); @@ -38,7 +38,7 @@ public function __construct($name, NodeParentInterface $parent = null) */ protected function instantiateNode() { - return new BooleanNode($this->name, $this->parent); + return new BooleanNode($this->name, $this->parent, $this->pathSeparator); } /** diff --git a/vendor/symfony/config/Definition/Builder/BuilderAwareInterface.php b/vendor/symfony/config/Definition/Builder/BuilderAwareInterface.php new file mode 100644 index 00000000..f30b8736 --- /dev/null +++ b/vendor/symfony/config/Definition/Builder/BuilderAwareInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config\Definition\Builder; + +/** + * An interface that can be implemented by nodes which build other nodes. + * + * @author Roland Franssen + */ +interface BuilderAwareInterface +{ + /** + * Sets a custom children builder. + */ + public function setBuilder(NodeBuilder $builder); +} diff --git a/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php b/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php index 817906f5..9a9c096e 100644 --- a/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/EnumNodeDefinition.php @@ -51,6 +51,6 @@ protected function instantiateNode() throw new \RuntimeException('You must call ->values() on enum nodes.'); } - return new EnumNode($this->name, $this->parent, $this->values); + return new EnumNode($this->name, $this->parent, $this->values, $this->pathSeparator); } } diff --git a/vendor/symfony/config/Definition/Builder/ExprBuilder.php b/vendor/symfony/config/Definition/Builder/ExprBuilder.php index 5db229dc..d102e56e 100644 --- a/vendor/symfony/config/Definition/Builder/ExprBuilder.php +++ b/vendor/symfony/config/Definition/Builder/ExprBuilder.php @@ -37,7 +37,7 @@ public function __construct(NodeDefinition $node) */ public function always(\Closure $then = null) { - $this->ifPart = function ($v) { return true; }; + $this->ifPart = function () { return true; }; if (null !== $then) { $this->thenPart = $then; @@ -91,7 +91,7 @@ public function ifNull() /** * Tests if the value is empty. * - * @return ExprBuilder + * @return $this */ public function ifEmpty() { @@ -168,7 +168,7 @@ public function then(\Closure $closure) */ public function thenEmptyArray() { - $this->thenPart = function ($v) { return []; }; + $this->thenPart = function () { return []; }; return $this; } @@ -200,7 +200,7 @@ public function thenInvalid($message) */ public function thenUnset() { - $this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key.'); }; + $this->thenPart = function () { throw new UnsetKeyException('Unsetting key.'); }; return $this; } diff --git a/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php b/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php index c0bed462..7b74271a 100644 --- a/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/FloatNodeDefinition.php @@ -27,6 +27,6 @@ class FloatNodeDefinition extends NumericNodeDefinition */ protected function instantiateNode() { - return new FloatNode($this->name, $this->parent, $this->min, $this->max); + return new FloatNode($this->name, $this->parent, $this->min, $this->max, $this->pathSeparator); } } diff --git a/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php b/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php index f6c3c147..0472a987 100644 --- a/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php @@ -27,6 +27,6 @@ class IntegerNodeDefinition extends NumericNodeDefinition */ protected function instantiateNode() { - return new IntegerNode($this->name, $this->parent, $this->min, $this->max); + return new IntegerNode($this->name, $this->parent, $this->min, $this->max, $this->pathSeparator); } } diff --git a/vendor/symfony/config/Definition/Builder/NodeBuilder.php b/vendor/symfony/config/Definition/Builder/NodeBuilder.php index 2809cb6c..be059f5d 100644 --- a/vendor/symfony/config/Definition/Builder/NodeBuilder.php +++ b/vendor/symfony/config/Definition/Builder/NodeBuilder.php @@ -179,7 +179,7 @@ public function node($name, $type) */ public function append(NodeDefinition $node) { - if ($node instanceof ParentNodeDefinitionInterface) { + if ($node instanceof BuilderAwareInterface) { $builder = clone $this; $builder->setParent(null); $node->setBuilder($builder); diff --git a/vendor/symfony/config/Definition/Builder/NodeDefinition.php b/vendor/symfony/config/Definition/Builder/NodeDefinition.php index cc245d74..6cc9bc85 100644 --- a/vendor/symfony/config/Definition/Builder/NodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/NodeDefinition.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Config\Definition\Builder; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException; use Symfony\Component\Config\Definition\NodeInterface; @@ -33,14 +34,11 @@ abstract class NodeDefinition implements NodeParentInterface protected $nullEquivalent; protected $trueEquivalent = true; protected $falseEquivalent = false; + protected $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR; protected $parent; protected $attributes = []; - /** - * @param string|null $name The name of the node - * @param NodeParentInterface|null $parent The parent - */ - public function __construct($name, NodeParentInterface $parent = null) + public function __construct(?string $name, NodeParentInterface $parent = null) { $this->parent = $parent; $this->name = $name; @@ -129,7 +127,9 @@ public function getNode($forceRootNode = false) } $node = $this->createNode(); - $node->setAttributes($this->attributes); + if ($node instanceof BaseNode) { + $node->setAttributes($this->attributes); + } return $node; } @@ -350,4 +350,26 @@ protected function normalization() * @throws InvalidDefinitionException When the definition is invalid */ abstract protected function createNode(); + + /** + * Set PathSeparator to use. + * + * @return $this + */ + public function setPathSeparator(string $separator) + { + if ($this instanceof ParentNodeDefinitionInterface) { + if (method_exists($this, 'getChildNodeDefinitions')) { + foreach ($this->getChildNodeDefinitions() as $child) { + $child->setPathSeparator($separator); + } + } else { + @trigger_error(sprintf('Not implementing the "%s::getChildNodeDefinitions()" method in "%s" is deprecated since Symfony 4.1.', ParentNodeDefinitionInterface::class, static::class), \E_USER_DEPRECATED); + } + } + + $this->pathSeparator = $separator; + + return $this; + } } diff --git a/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php b/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php index 390b1136..c4bff175 100644 --- a/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/NumericNodeDefinition.php @@ -26,7 +26,7 @@ abstract class NumericNodeDefinition extends ScalarNodeDefinition /** * Ensures that the value is smaller than the given reference. * - * @param mixed $max + * @param int|float $max * * @return $this * @@ -45,7 +45,7 @@ public function max($max) /** * Ensures that the value is bigger than the given reference. * - * @param mixed $min + * @param int|float $min * * @return $this * diff --git a/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php b/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php index 1bf2ad4b..c6328c29 100644 --- a/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php +++ b/vendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php @@ -15,8 +15,10 @@ * An interface that must be implemented by nodes which can have children. * * @author Victor Berchet + * + * @method NodeDefinition[] getChildNodeDefinitions() Gets the child node definitions - not implementing it is deprecated since Symfony 4.2 */ -interface ParentNodeDefinitionInterface +interface ParentNodeDefinitionInterface extends BuilderAwareInterface { /** * Returns a builder to add children nodes. @@ -41,9 +43,4 @@ public function children(); * @return $this */ public function append(NodeDefinition $node); - - /** - * Sets a custom children builder. - */ - public function setBuilder(NodeBuilder $builder); } diff --git a/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php b/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php index 6170555c..428f6129 100644 --- a/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/ScalarNodeDefinition.php @@ -27,6 +27,6 @@ class ScalarNodeDefinition extends VariableNodeDefinition */ protected function instantiateNode() { - return new ScalarNode($this->name, $this->parent); + return new ScalarNode($this->name, $this->parent, $this->pathSeparator); } } diff --git a/vendor/symfony/config/Definition/Builder/TreeBuilder.php b/vendor/symfony/config/Definition/Builder/TreeBuilder.php index 384477c5..359f590e 100644 --- a/vendor/symfony/config/Definition/Builder/TreeBuilder.php +++ b/vendor/symfony/config/Definition/Builder/TreeBuilder.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Config\Definition\Builder; +use Symfony\Component\Config\Definition\Exception\TreeWithoutRootNodeException; use Symfony\Component\Config\Definition\NodeInterface; /** @@ -23,29 +24,49 @@ class TreeBuilder implements NodeParentInterface protected $tree; protected $root; - /** - * @deprecated since 3.4. To be removed in 4.0 - */ - protected $builder; + public function __construct(string $name = null, string $type = 'array', NodeBuilder $builder = null) + { + if (null === $name) { + @trigger_error('A tree builder without a root node is deprecated since Symfony 4.2 and will not be supported anymore in 5.0.', \E_USER_DEPRECATED); + } else { + $builder = $builder ?? new NodeBuilder(); + $this->root = $builder->node($name, $type)->setParent($this); + } + } /** * Creates the root node. * - * @param string $name The name of the root node - * @param string $type The type of the root node - * @param NodeBuilder $builder A custom node builder instance + * @param string $name The name of the root node + * @param string $type The type of the root node * * @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array') * * @throws \RuntimeException When the node type is not supported + * + * @deprecated since Symfony 4.3, pass the root name to the constructor instead */ public function root($name, $type = 'array', NodeBuilder $builder = null) { - $builder = $builder ?: new NodeBuilder(); + @trigger_error(sprintf('The "%s()" method called for the "%s" configuration is deprecated since Symfony 4.3, pass the root name to the constructor instead.', __METHOD__, $name), \E_USER_DEPRECATED); + + $builder = $builder ?? new NodeBuilder(); return $this->root = $builder->node($name, $type)->setParent($this); } + /** + * @return NodeDefinition|ArrayNodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array') + */ + public function getRootNode(): NodeDefinition + { + if (null === $this->root) { + throw new \RuntimeException(sprintf('Calling "%s()" before creating the root node is not supported, migrate to the new constructor signature instead.', __METHOD__)); + } + + return $this->root; + } + /** * Builds the tree. * @@ -55,13 +76,31 @@ public function root($name, $type = 'array', NodeBuilder $builder = null) */ public function buildTree() { - if (null === $this->root) { - throw new \RuntimeException('The configuration tree has no root node.'); - } + $this->assertTreeHasRootNode(); if (null !== $this->tree) { return $this->tree; } return $this->tree = $this->root->getNode(true); } + + public function setPathSeparator(string $separator) + { + $this->assertTreeHasRootNode(); + + // unset last built as changing path separator changes all nodes + $this->tree = null; + + $this->root->setPathSeparator($separator); + } + + /** + * @throws \RuntimeException if root node is not defined + */ + private function assertTreeHasRootNode() + { + if (null === $this->root) { + throw new TreeWithoutRootNodeException('The configuration tree has no root node.'); + } + } } diff --git a/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php b/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php index 26565e17..39a564f4 100644 --- a/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php +++ b/vendor/symfony/config/Definition/Builder/VariableNodeDefinition.php @@ -27,7 +27,7 @@ class VariableNodeDefinition extends NodeDefinition */ protected function instantiateNode() { - return new VariableNode($this->name, $this->parent); + return new VariableNode($this->name, $this->parent, $this->pathSeparator); } /** diff --git a/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php b/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php index 7f863990..a6b6240c 100644 --- a/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php +++ b/vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php @@ -12,13 +12,14 @@ namespace Symfony\Component\Config\Definition\Dumper; use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\EnumNode; use Symfony\Component\Config\Definition\NodeInterface; use Symfony\Component\Config\Definition\PrototypedArrayNode; /** - * Dumps a XML reference configuration for the given configuration/node instance. + * Dumps an XML reference configuration for the given configuration/node instance. * * @author Wouter J */ @@ -41,24 +42,19 @@ public function dumpNode(NodeInterface $node, $namespace = null) return $ref; } - /** - * @param int $depth - * @param bool $root If the node is the root node - * @param string $namespace The namespace of the node - */ - private function writeNode(NodeInterface $node, $depth = 0, $root = false, $namespace = null) + private function writeNode(NodeInterface $node, int $depth = 0, bool $root = false, string $namespace = null) { $rootName = ($root ? 'config' : $node->getName()); $rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null)); // xml remapping if ($node->getParent()) { - $remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) { + $remapping = array_filter($node->getParent()->getXmlRemappings(), function (array $mapping) use ($rootName) { return $rootName === $mapping[1]; }); if (\count($remapping)) { - list($singular) = current($remapping); + [$singular] = current($remapping); $rootName = $singular; } } @@ -96,7 +92,7 @@ private function writeNode(NodeInterface $node, $depth = 0, $root = false, $name } if ($prototype instanceof PrototypedArrayNode) { - $prototype->setName($key); + $prototype->setName($key ?? ''); $children = [$key => $prototype]; } elseif ($prototype instanceof ArrayNode) { $children = $prototype->getChildren(); @@ -131,50 +127,52 @@ private function writeNode(NodeInterface $node, $depth = 0, $root = false, $name // get attributes and elements foreach ($children as $child) { - if (!$child instanceof ArrayNode) { - // get attributes + if ($child instanceof ArrayNode) { + // get elements + $rootChildren[] = $child; - // metadata - $name = str_replace('_', '-', $child->getName()); - $value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world + continue; + } - // comments - $comments = []; - if ($info = $child->getInfo()) { - $comments[] = $info; - } + // get attributes - if ($example = $child->getExample()) { - $comments[] = 'Example: '.$example; - } + // metadata + $name = str_replace('_', '-', $child->getName()); + $value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world - if ($child->isRequired()) { - $comments[] = 'Required'; - } + // comments + $comments = []; + if ($child instanceof BaseNode && $info = $child->getInfo()) { + $comments[] = $info; + } - if ($child->isDeprecated()) { - $comments[] = sprintf('Deprecated (%s)', $child->getDeprecationMessage($child->getName(), $node->getPath())); - } + if ($child instanceof BaseNode && $example = $child->getExample()) { + $comments[] = 'Example: '.$example; + } - if ($child instanceof EnumNode) { - $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues())); - } + if ($child->isRequired()) { + $comments[] = 'Required'; + } - if (\count($comments)) { - $rootAttributeComments[$name] = implode(";\n", $comments); - } + if ($child instanceof BaseNode && $child->isDeprecated()) { + $comments[] = sprintf('Deprecated (%s)', $child->getDeprecationMessage($child->getName(), $node->getPath())); + } - // default values - if ($child->hasDefaultValue()) { - $value = $child->getDefaultValue(); - } + if ($child instanceof EnumNode) { + $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues())); + } - // append attribute - $rootAttributes[$name] = $value; - } else { - // get elements - $rootChildren[] = $child; + if (\count($comments)) { + $rootAttributeComments[$name] = implode(";\n", $comments); + } + + // default values + if ($child->hasDefaultValue()) { + $value = $child->getDefaultValue(); } + + // append attribute + $rootAttributes[$name] = $value; } } @@ -258,11 +256,8 @@ private function writeNode(NodeInterface $node, $depth = 0, $root = false, $name /** * Outputs a single config reference line. - * - * @param string $text - * @param int $indent */ - private function writeLine($text, $indent = 0) + private function writeLine(string $text, int $indent = 0) { $indent = \strlen($text) + $indent; $format = '%'.$indent.'s'; @@ -274,10 +269,8 @@ private function writeLine($text, $indent = 0) * Renders the string conversion of the value. * * @param mixed $value - * - * @return string */ - private function writeValue($value) + private function writeValue($value): string { if ('%%%%not_defined%%%%' === $value) { return ''; diff --git a/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php b/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php index ba355394..c455344d 100644 --- a/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php +++ b/vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php @@ -12,11 +12,13 @@ namespace Symfony\Component\Config\Definition\Dumper; use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\EnumNode; use Symfony\Component\Config\Definition\NodeInterface; use Symfony\Component\Config\Definition\PrototypedArrayNode; use Symfony\Component\Config\Definition\ScalarNode; +use Symfony\Component\Config\Definition\VariableNode; use Symfony\Component\Yaml\Inline; /** @@ -69,17 +71,16 @@ public function dumpNode(NodeInterface $node) return $ref; } - /** - * @param int $depth - * @param bool $prototypedArray - */ - private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, $depth = 0, $prototypedArray = false) + private function writeNode(NodeInterface $node, NodeInterface $parentNode = null, int $depth = 0, bool $prototypedArray = false) { $comments = []; $default = ''; $defaultArray = null; $children = null; - $example = $node->getExample(); + $example = null; + if ($node instanceof BaseNode) { + $example = $node->getExample(); + } // defaults if ($node instanceof ArrayNode) { @@ -99,6 +100,9 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null } elseif ($node instanceof EnumNode) { $comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues())); $default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~'; + } elseif (VariableNode::class === \get_class($node) && \is_array($example)) { + // If there is an array example, we are sure we dont need to print a default value + $default = ''; } else { $default = '~'; @@ -123,13 +127,13 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null } // deprecated? - if ($node->isDeprecated()) { + if ($node instanceof BaseNode && $node->isDeprecated()) { $comments[] = sprintf('Deprecated (%s)', $node->getDeprecationMessage($node->getName(), $parentNode ? $parentNode->getPath() : $node->getPath())); } // example if ($example && !\is_array($example)) { - $comments[] = 'Example: '.$example; + $comments[] = 'Example: '.Inline::dump($example); } $default = '' != (string) $default ? ' '.$default : ''; @@ -138,7 +142,7 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null $key = $prototypedArray ? '-' : $node->getName().':'; $text = rtrim(sprintf('%-21s%s %s', $key, $default, $comments), ' '); - if ($info = $node->getInfo()) { + if ($node instanceof BaseNode && $info = $node->getInfo()) { $this->writeLine(''); // indenting multi-line info $info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info); @@ -165,7 +169,7 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null $this->writeLine('# '.$message.':', $depth * 4 + 4); - $this->writeArray($example, $depth + 1); + $this->writeArray(array_map([Inline::class, 'dump'], $example), $depth + 1); } if ($children) { @@ -177,11 +181,8 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null /** * Outputs a single config reference line. - * - * @param string $text - * @param int $indent */ - private function writeLine($text, $indent = 0) + private function writeLine(string $text, int $indent = 0) { $indent = \strlen($text) + $indent; $format = '%'.$indent.'s'; @@ -189,7 +190,7 @@ private function writeLine($text, $indent = 0) $this->reference .= sprintf($format, $text)."\n"; } - private function writeArray(array $array, $depth) + private function writeArray(array $array, int $depth) { $isIndexed = array_values($array) === $array; @@ -212,10 +213,7 @@ private function writeArray(array $array, $depth) } } - /** - * @return array - */ - private function getPrototypeChildren(PrototypedArrayNode $node) + private function getPrototypeChildren(PrototypedArrayNode $node): array { $prototype = $node->getPrototype(); $key = $node->getKeyAttribute(); diff --git a/vendor/symfony/config/Definition/EnumNode.php b/vendor/symfony/config/Definition/EnumNode.php index 15c8db3e..822e6b57 100644 --- a/vendor/symfony/config/Definition/EnumNode.php +++ b/vendor/symfony/config/Definition/EnumNode.php @@ -22,14 +22,14 @@ class EnumNode extends ScalarNode { private $values; - public function __construct($name, NodeInterface $parent = null, array $values = []) + public function __construct(?string $name, NodeInterface $parent = null, array $values = [], string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) { $values = array_unique($values); if (empty($values)) { throw new \InvalidArgumentException('$values must contain at least one element.'); } - parent::__construct($name, $parent); + parent::__construct($name, $parent, $pathSeparator); $this->values = $values; } @@ -38,6 +38,9 @@ public function getValues() return $this->values; } + /** + * {@inheritdoc} + */ protected function finalizeValue($value) { $value = parent::finalizeValue($value); @@ -51,4 +54,12 @@ protected function finalizeValue($value) return $value; } + + /** + * {@inheritdoc} + */ + protected function allowPlaceholders(): bool + { + return false; + } } diff --git a/vendor/symfony/config/Definition/Exception/TreeWithoutRootNodeException.php b/vendor/symfony/config/Definition/Exception/TreeWithoutRootNodeException.php new file mode 100644 index 00000000..04406fc9 --- /dev/null +++ b/vendor/symfony/config/Definition/Exception/TreeWithoutRootNodeException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config\Definition\Exception; + +/** + * @author Roland Franssen + * + * @internal + */ +class TreeWithoutRootNodeException extends \RuntimeException +{ +} diff --git a/vendor/symfony/config/Definition/FloatNode.php b/vendor/symfony/config/Definition/FloatNode.php index 9eb87899..8e229ed4 100644 --- a/vendor/symfony/config/Definition/FloatNode.php +++ b/vendor/symfony/config/Definition/FloatNode.php @@ -40,4 +40,12 @@ protected function validateType($value) throw $ex; } } + + /** + * {@inheritdoc} + */ + protected function getValidPlaceholderTypes(): array + { + return ['float']; + } } diff --git a/vendor/symfony/config/Definition/IntegerNode.php b/vendor/symfony/config/Definition/IntegerNode.php index 8ec068a8..e8c6a81c 100644 --- a/vendor/symfony/config/Definition/IntegerNode.php +++ b/vendor/symfony/config/Definition/IntegerNode.php @@ -35,4 +35,12 @@ protected function validateType($value) throw $ex; } } + + /** + * {@inheritdoc} + */ + protected function getValidPlaceholderTypes(): array + { + return ['int']; + } } diff --git a/vendor/symfony/config/Definition/NumericNode.php b/vendor/symfony/config/Definition/NumericNode.php index 439935e4..50d137c2 100644 --- a/vendor/symfony/config/Definition/NumericNode.php +++ b/vendor/symfony/config/Definition/NumericNode.php @@ -23,9 +23,13 @@ class NumericNode extends ScalarNode protected $min; protected $max; - public function __construct($name, NodeInterface $parent = null, $min = null, $max = null) + /** + * @param int|float|null $min + * @param int|float|null $max + */ + public function __construct(?string $name, NodeInterface $parent = null, $min = null, $max = null, string $pathSeparator = BaseNode::DEFAULT_PATH_SEPARATOR) { - parent::__construct($name, $parent); + parent::__construct($name, $parent, $pathSeparator); $this->min = $min; $this->max = $max; } diff --git a/vendor/symfony/config/Definition/Processor.php b/vendor/symfony/config/Definition/Processor.php index 0a935eeb..e7b36486 100644 --- a/vendor/symfony/config/Definition/Processor.php +++ b/vendor/symfony/config/Definition/Processor.php @@ -15,14 +15,15 @@ * This class is the entry point for config normalization/merging/finalization. * * @author Johannes M. Schmitt + * + * @final since version 4.1 */ class Processor { /** * Processes an array of configurations. * - * @param NodeInterface $configTree The node tree describing the configuration - * @param array $configs An array of configuration items to process + * @param array $configs An array of configuration items to process * * @return array The processed configuration */ @@ -40,8 +41,7 @@ public function process(NodeInterface $configTree, array $configs) /** * Processes an array of configurations. * - * @param ConfigurationInterface $configuration The configuration class - * @param array $configs An array of configuration items to process + * @param array $configs An array of configuration items to process * * @return array The processed configuration */ @@ -86,10 +86,10 @@ public static function normalizeConfig($config, $key, $plural = null) if (isset($config[$key])) { if (\is_string($config[$key]) || !\is_int(key($config[$key]))) { // only one - return [$config[$key]]; + return [$config[$key]]; } - return $config[$key]; + return $config[$key]; } return []; diff --git a/vendor/symfony/config/Definition/PrototypedArrayNode.php b/vendor/symfony/config/Definition/PrototypedArrayNode.php index d18a109a..03822236 100644 --- a/vendor/symfony/config/Definition/PrototypedArrayNode.php +++ b/vendor/symfony/config/Definition/PrototypedArrayNode.php @@ -173,14 +173,7 @@ public function addChild(NodeInterface $node) } /** - * Finalizes the value of this node. - * - * @param mixed $value - * - * @return mixed The finalized value - * - * @throws UnsetKeyException - * @throws InvalidConfigurationException if the node doesn't have enough children + * {@inheritdoc} */ protected function finalizeValue($value) { @@ -208,13 +201,8 @@ protected function finalizeValue($value) } /** - * Normalizes the value. - * - * @param mixed $value The value to normalize - * - * @return mixed The normalized value + * {@inheritdoc} * - * @throws InvalidConfigurationException * @throws DuplicateKeyException */ protected function normalizeValue($value) @@ -225,11 +213,11 @@ protected function normalizeValue($value) $value = $this->remapXml($value); - $isAssoc = array_keys($value) !== range(0, \count($value) - 1); + $isList = array_is_list($value); $normalized = []; foreach ($value as $k => $v) { if (null !== $this->keyAttribute && \is_array($v)) { - if (!isset($v[$this->keyAttribute]) && \is_int($k) && !$isAssoc) { + if (!isset($v[$this->keyAttribute]) && \is_int($k) && $isList) { $ex = new InvalidConfigurationException(sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath())); $ex->setPath($this->getPath()); @@ -237,6 +225,10 @@ protected function normalizeValue($value) } elseif (isset($v[$this->keyAttribute])) { $k = $v[$this->keyAttribute]; + if (\is_float($k)) { + $k = var_export($k, true); + } + // remove the key attribute when required if ($this->removeKeyAttribute) { unset($v[$this->keyAttribute]); @@ -267,7 +259,7 @@ protected function normalizeValue($value) } $prototype = $this->getPrototypeForChild($k); - if (null !== $this->keyAttribute || $isAssoc) { + if (null !== $this->keyAttribute || !$isList) { $normalized[$k] = $prototype->normalize($v); } else { $normalized[] = $prototype->normalize($v); @@ -278,15 +270,7 @@ protected function normalizeValue($value) } /** - * Merges values together. - * - * @param mixed $leftSide The left side to merge - * @param mixed $rightSide The right side to merge - * - * @return mixed The merged values - * - * @throws InvalidConfigurationException - * @throws \RuntimeException + * {@inheritdoc} */ protected function mergeValues($leftSide, $rightSide) { @@ -300,9 +284,10 @@ protected function mergeValues($leftSide, $rightSide) return $rightSide; } + $isList = array_is_list($rightSide); foreach ($rightSide as $k => $v) { - // prototype, and key is irrelevant, append the element - if (null === $this->keyAttribute) { + // prototype, and key is irrelevant there are no named keys, append the element + if (null === $this->keyAttribute && $isList) { $leftSide[] = $v; continue; } @@ -363,13 +348,11 @@ protected function mergeValues($leftSide, $rightSide) * Now, the key becomes 'name001' and the child node becomes 'value001' and * the prototype of child node 'name001' should be a ScalarNode instead of an ArrayNode instance. * - * @param string $key The key of the child node - * * @return mixed The prototype instance */ - private function getPrototypeForChild($key) + private function getPrototypeForChild(string $key) { - $prototype = isset($this->valuePrototypes[$key]) ? $this->valuePrototypes[$key] : $this->prototype; + $prototype = $this->valuePrototypes[$key] ?? $this->prototype; $prototype->setName($key); return $prototype; diff --git a/vendor/symfony/config/Definition/ScalarNode.php b/vendor/symfony/config/Definition/ScalarNode.php index 53c1ed29..7a5adf1b 100644 --- a/vendor/symfony/config/Definition/ScalarNode.php +++ b/vendor/symfony/config/Definition/ScalarNode.php @@ -32,7 +32,7 @@ class ScalarNode extends VariableNode */ protected function validateType($value) { - if (!is_scalar($value) && null !== $value) { + if (!\is_scalar($value) && null !== $value) { $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected scalar, but got %s.', $this->getPath(), \gettype($value))); if ($hint = $this->getInfo()) { $ex->addHint($hint); @@ -48,6 +48,20 @@ protected function validateType($value) */ protected function isValueEmpty($value) { + // assume environment variables are never empty (which in practice is likely to be true during runtime) + // not doing so breaks many configs that are valid today + if ($this->isHandlingPlaceholder()) { + return false; + } + return null === $value || '' === $value; } + + /** + * {@inheritdoc} + */ + protected function getValidPlaceholderTypes(): array + { + return ['bool', 'int', 'float', 'string']; + } } diff --git a/vendor/symfony/config/Definition/VariableNode.php b/vendor/symfony/config/Definition/VariableNode.php index 1a3442d9..5c616f66 100644 --- a/vendor/symfony/config/Definition/VariableNode.php +++ b/vendor/symfony/config/Definition/VariableNode.php @@ -81,6 +81,19 @@ protected function validateType($value) */ protected function finalizeValue($value) { + // deny environment variables only when using custom validators + // this avoids ever passing an empty value to final validation closures + if (!$this->allowEmptyValue && $this->isHandlingPlaceholder() && $this->finalValidationClosures) { + @trigger_error(sprintf('Setting path "%s" to an environment variable is deprecated since Symfony 4.3. Remove "cannotBeEmpty()", "validate()" or include a prefix/suffix value instead.', $this->getPath()), \E_USER_DEPRECATED); +// $e = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an environment variable when empty values are not allowed by definition and are validated.', $this->getPath())); +// if ($hint = $this->getInfo()) { +// $e->addHint($hint); +// } +// $e->setPath($this->getPath()); +// +// throw $e; + } + if (!$this->allowEmptyValue && $this->isValueEmpty($value)) { $ex = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value))); if ($hint = $this->getInfo()) { @@ -120,6 +133,8 @@ protected function mergeValues($leftSide, $rightSide) * @param mixed $value * * @return bool + * + * @see finalizeValue() */ protected function isValueEmpty($value) { diff --git a/vendor/symfony/config/DependencyInjection/ConfigCachePass.php b/vendor/symfony/config/DependencyInjection/ConfigCachePass.php deleted file mode 100644 index 30df15be..00000000 --- a/vendor/symfony/config/DependencyInjection/ConfigCachePass.php +++ /dev/null @@ -1,52 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\DependencyInjection; - -@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use tagged iterator arguments instead.', ConfigCachePass::class), \E_USER_DEPRECATED); - -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -/** - * Adds services tagged config_cache.resource_checker to the config_cache_factory service, ordering them by priority. - * - * @author Matthias Pigulla - * @author Benjamin Klotz - * - * @deprecated since version 3.4, to be removed in 4.0. Use tagged iterator arguments instead. - */ -class ConfigCachePass implements CompilerPassInterface -{ - use PriorityTaggedServiceTrait; - - private $factoryServiceId; - private $resourceCheckerTag; - - public function __construct($factoryServiceId = 'config_cache_factory', $resourceCheckerTag = 'config_cache.resource_checker') - { - $this->factoryServiceId = $factoryServiceId; - $this->resourceCheckerTag = $resourceCheckerTag; - } - - public function process(ContainerBuilder $container) - { - $resourceCheckers = $this->findAndSortTaggedServices($this->resourceCheckerTag, $container); - - if (empty($resourceCheckers)) { - return; - } - - $container->getDefinition($this->factoryServiceId)->replaceArgument(0, new IteratorArgument($resourceCheckers)); - } -} diff --git a/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php b/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php index 6a3b01cf..aa27f986 100644 --- a/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php +++ b/vendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.php @@ -16,9 +16,9 @@ * * @author Fabien Potencier */ -class FileLoaderImportCircularReferenceException extends FileLoaderLoadException +class FileLoaderImportCircularReferenceException extends LoaderLoadException { - public function __construct(array $resources, $code = null, $previous = null) + public function __construct(array $resources, ?int $code = 0, \Throwable $previous = null) { $message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]); diff --git a/vendor/symfony/config/Exception/FileLoaderLoadException.php b/vendor/symfony/config/Exception/FileLoaderLoadException.php index 82d90eb3..2c815192 100644 --- a/vendor/symfony/config/Exception/FileLoaderLoadException.php +++ b/vendor/symfony/config/Exception/FileLoaderLoadException.php @@ -15,24 +15,26 @@ * Exception class for when a resource cannot be loaded or imported. * * @author Ryan Weaver + * + * @deprecated since Symfony 4.2, use LoaderLoadException instead. */ class FileLoaderLoadException extends \Exception { /** - * @param string $resource The resource that could not be imported - * @param string $sourceResource The original resource importing the new resource - * @param int $code The error code - * @param \Exception $previous A previous exception - * @param string $type The type of resource + * @param string $resource The resource that could not be imported + * @param string|null $sourceResource The original resource importing the new resource + * @param int|null $code The error code + * @param \Throwable|null $previous A previous exception + * @param string|null $type The type of resource */ - public function __construct($resource, $sourceResource = null, $code = null, $previous = null, $type = null) + public function __construct(string $resource, string $sourceResource = null, ?int $code = 0, \Throwable $previous = null, string $type = null) { $message = ''; if ($previous) { // Include the previous exception, to help the user see what might be the underlying cause // Trim the trailing period of the previous message. We only want 1 period remove so no rtrim... - if ('.' === substr($previous->getMessage(), -1)) { + if (str_ends_with($previous->getMessage(), '.')) { $trimmedMessage = substr($previous->getMessage(), 0, -1); $message .= sprintf('%s', $trimmedMessage).' in '; } else { @@ -42,17 +44,17 @@ public function __construct($resource, $sourceResource = null, $code = null, $pr // show tweaked trace to complete the human readable sentence if (null === $sourceResource) { - $message .= sprintf('(which is loaded in resource "%s")', $this->varToString($resource)); + $message .= sprintf('(which is loaded in resource "%s")', $resource); } else { - $message .= sprintf('(which is being imported from "%s")', $this->varToString($sourceResource)); + $message .= sprintf('(which is being imported from "%s")', $sourceResource); } $message .= '.'; // if there's no previous message, present it the default way } elseif (null === $sourceResource) { - $message .= sprintf('Cannot load resource "%s".', $this->varToString($resource)); + $message .= sprintf('Cannot load resource "%s".', $resource); } else { - $message .= sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource)); + $message .= sprintf('Cannot import resource "%s" from "%s".', $resource, $sourceResource); } // Is the resource located inside a bundle? diff --git a/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php b/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php index 648cf0e7..3ee4b938 100644 --- a/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php +++ b/vendor/symfony/config/Exception/FileLocatorFileNotFoundException.php @@ -20,7 +20,7 @@ class FileLocatorFileNotFoundException extends \InvalidArgumentException { private $paths; - public function __construct($message = '', $code = 0, $previous = null, array $paths = []) + public function __construct(string $message = '', int $code = 0, \Throwable $previous = null, array $paths = []) { parent::__construct($message, $code, $previous); diff --git a/vendor/symfony/config/Exception/LoaderLoadException.php b/vendor/symfony/config/Exception/LoaderLoadException.php new file mode 100644 index 00000000..41a959d3 --- /dev/null +++ b/vendor/symfony/config/Exception/LoaderLoadException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Config\Exception; + +/** + * Exception class for when a resource cannot be loaded or imported. + * + * @author Ryan Weaver + */ +class LoaderLoadException extends FileLoaderLoadException +{ +} diff --git a/vendor/symfony/config/FileLocator.php b/vendor/symfony/config/FileLocator.php index 5f315ba7..685ec5b6 100644 --- a/vendor/symfony/config/FileLocator.php +++ b/vendor/symfony/config/FileLocator.php @@ -23,7 +23,7 @@ class FileLocator implements FileLocatorInterface protected $paths; /** - * @param string|array $paths A path or an array of paths where to look for resources + * @param string|string[] $paths A path or an array of paths where to look for resources */ public function __construct($paths = []) { @@ -76,12 +76,8 @@ public function locate($name, $currentPath = null, $first = true) /** * Returns whether the file path is an absolute path. - * - * @param string $file A file path - * - * @return bool */ - private function isAbsolutePath($file) + private function isAbsolutePath(string $file): bool { if ('/' === $file[0] || '\\' === $file[0] || (\strlen($file) > 3 && ctype_alpha($file[0]) diff --git a/vendor/symfony/config/LICENSE b/vendor/symfony/config/LICENSE index 9e936ec0..88bf75bb 100644 --- a/vendor/symfony/config/LICENSE +++ b/vendor/symfony/config/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/config/Loader/DelegatingLoader.php b/vendor/symfony/config/Loader/DelegatingLoader.php index 452e81c5..fd5c8e95 100644 --- a/vendor/symfony/config/Loader/DelegatingLoader.php +++ b/vendor/symfony/config/Loader/DelegatingLoader.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Config\Loader; -use Symfony\Component\Config\Exception\FileLoaderLoadException; +use Symfony\Component\Config\Exception\LoaderLoadException; /** * DelegatingLoader delegates loading to other loaders using a loader resolver. @@ -34,7 +34,7 @@ public function __construct(LoaderResolverInterface $resolver) public function load($resource, $type = null) { if (false === $loader = $this->resolver->resolve($resource, $type)) { - throw new FileLoaderLoadException($resource, null, null, null, $type); + throw new LoaderLoadException($resource, null, 0, null, $type); } return $loader->load($resource, $type); diff --git a/vendor/symfony/config/Loader/FileLoader.php b/vendor/symfony/config/Loader/FileLoader.php index 2f1d471b..f4cdb8aa 100644 --- a/vendor/symfony/config/Loader/FileLoader.php +++ b/vendor/symfony/config/Loader/FileLoader.php @@ -12,8 +12,8 @@ namespace Symfony\Component\Config\Loader; use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException; -use Symfony\Component\Config\Exception\FileLoaderLoadException; use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException; +use Symfony\Component\Config\Exception\LoaderLoadException; use Symfony\Component\Config\FileLocatorInterface; use Symfony\Component\Config\Resource\FileExistenceResource; use Symfony\Component\Config\Resource\GlobResource; @@ -59,23 +59,37 @@ public function getLocator() /** * Imports a resource. * - * @param mixed $resource A Resource - * @param string|null $type The resource type or null if unknown - * @param bool $ignoreErrors Whether to ignore import errors or not - * @param string|null $sourceResource The original resource importing the new resource + * @param mixed $resource A Resource + * @param string|null $type The resource type or null if unknown + * @param bool $ignoreErrors Whether to ignore import errors or not + * @param string|null $sourceResource The original resource importing the new resource + * @param string|string[]|null $exclude Glob patterns to exclude from the import * * @return mixed * - * @throws FileLoaderLoadException + * @throws LoaderLoadException * @throws FileLoaderImportCircularReferenceException * @throws FileLocatorFileNotFoundException */ - public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) + public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null/* , $exclude = null */) { - if (\is_string($resource) && \strlen($resource) !== $i = strcspn($resource, '*?{[')) { + if (\func_num_args() < 5 && __CLASS__ !== static::class && !str_starts_with(static::class, 'Symfony\Component\\') && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface && !$this instanceof \Mockery\MockInterface) { + @trigger_error(sprintf('The "%s()" method will have a new "$exclude = null" argument in version 5.0, not defining it is deprecated since Symfony 4.4.', __METHOD__), \E_USER_DEPRECATED); + } + $exclude = \func_num_args() >= 5 ? func_get_arg(4) : null; + + if (\is_string($resource) && \strlen($resource) !== ($i = strcspn($resource, '*?{[')) && !str_contains($resource, "\n")) { + $excluded = []; + foreach ((array) $exclude as $pattern) { + foreach ($this->glob($pattern, true, $_, false, true) as $path => $info) { + // normalize Windows slashes and remove trailing slashes + $excluded[rtrim(str_replace('\\', '/', $path), '/')] = true; + } + } + $ret = []; - $isSubpath = 0 !== $i && false !== strpos(substr($resource, 0, $i), '/'); - foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath) as $path => $info) { + $isSubpath = 0 !== $i && str_contains(substr($resource, 0, $i), '/'); + foreach ($this->glob($resource, false, $_, $ignoreErrors || !$isSubpath, false, $excluded) as $path => $info) { if (null !== $res = $this->doImport($path, 'glob' === $type ? null : $type, $ignoreErrors, $sourceResource)) { $ret[] = $res; } @@ -83,7 +97,7 @@ public function import($resource, $type = null, $ignoreErrors = false, $sourceRe } if ($isSubpath) { - return isset($ret[1]) ? $ret : (isset($ret[0]) ? $ret[0] : null); + return isset($ret[1]) ? $ret : ($ret[0] ?? null); } } @@ -93,12 +107,12 @@ public function import($resource, $type = null, $ignoreErrors = false, $sourceRe /** * @internal */ - protected function glob($pattern, $recursive, &$resource = null, $ignoreErrors = false) + protected function glob(string $pattern, bool $recursive, &$resource = null, bool $ignoreErrors = false, bool $forExclusion = false, array $excluded = []) { if (\strlen($pattern) === $i = strcspn($pattern, '*?{[')) { $prefix = $pattern; $pattern = ''; - } elseif (0 === $i || false === strpos(substr($pattern, 0, $i), '/')) { + } elseif (0 === $i || !str_contains(substr($pattern, 0, $i), '/')) { $prefix = '.'; $pattern = '/'.$pattern; } else { @@ -120,14 +134,12 @@ protected function glob($pattern, $recursive, &$resource = null, $ignoreErrors = return; } - $resource = new GlobResource($prefix, $pattern, $recursive); + $resource = new GlobResource($prefix, $pattern, $recursive, $forExclusion, $excluded); - foreach ($resource as $path => $info) { - yield $path => $info; - } + yield from $resource; } - private function doImport($resource, $type = null, $ignoreErrors = false, $sourceResource = null) + private function doImport($resource, string $type = null, bool $ignoreErrors = false, $sourceResource = null) { try { $loader = $this->resolve($resource, $type); @@ -161,11 +173,11 @@ private function doImport($resource, $type = null, $ignoreErrors = false, $sourc } catch (\Exception $e) { if (!$ignoreErrors) { // prevent embedded imports from nesting multiple exceptions - if ($e instanceof FileLoaderLoadException) { + if ($e instanceof LoaderLoadException) { throw $e; } - throw new FileLoaderLoadException($resource, $sourceResource, null, $e, $type); + throw new LoaderLoadException($resource, $sourceResource, 0, $e, $type); } } diff --git a/vendor/symfony/config/Loader/Loader.php b/vendor/symfony/config/Loader/Loader.php index d2f2ec90..a83088e4 100644 --- a/vendor/symfony/config/Loader/Loader.php +++ b/vendor/symfony/config/Loader/Loader.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Config\Loader; -use Symfony\Component\Config\Exception\FileLoaderLoadException; +use Symfony\Component\Config\Exception\LoaderLoadException; /** * Loader is the abstract class used by all built-in loaders. @@ -59,7 +59,7 @@ public function import($resource, $type = null) * * @return $this|LoaderInterface * - * @throws FileLoaderLoadException If no loader is found + * @throws LoaderLoadException If no loader is found */ public function resolve($resource, $type = null) { @@ -70,7 +70,7 @@ public function resolve($resource, $type = null) $loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type); if (false === $loader) { - throw new FileLoaderLoadException($resource, null, null, null, $type); + throw new LoaderLoadException($resource, null, 0, null, $type); } return $loader; diff --git a/vendor/symfony/config/Loader/LoaderInterface.php b/vendor/symfony/config/Loader/LoaderInterface.php index dfca9dd2..130296ea 100644 --- a/vendor/symfony/config/Loader/LoaderInterface.php +++ b/vendor/symfony/config/Loader/LoaderInterface.php @@ -24,6 +24,8 @@ interface LoaderInterface * @param mixed $resource The resource * @param string|null $type The resource type or null if unknown * + * @return mixed + * * @throws \Exception If something went wrong */ public function load($resource, $type = null); diff --git a/vendor/symfony/config/README.md b/vendor/symfony/config/README.md index 0bbde552..10c2ddd0 100644 --- a/vendor/symfony/config/README.md +++ b/vendor/symfony/config/README.md @@ -1,15 +1,15 @@ Config Component ================ -The Config component provides several classes to help you find, load, combine, -autofill and validate configuration values of any kind, whatever their source -may be (YAML, XML, INI files, or for instance a database). +The Config component helps find, load, combine, autofill and validate +configuration values of any kind, whatever their source may be (YAML, XML, INI +files, or for instance a database). Resources --------- - * [Documentation](https://symfony.com/doc/current/components/config.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Documentation](https://symfony.com/doc/current/components/config.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/config/Resource/ClassExistenceResource.php b/vendor/symfony/config/Resource/ClassExistenceResource.php index f58d2a6d..f04b767e 100644 --- a/vendor/symfony/config/Resource/ClassExistenceResource.php +++ b/vendor/symfony/config/Resource/ClassExistenceResource.php @@ -18,8 +18,10 @@ * The resource must be a fully-qualified class name. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ -class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializable +class ClassExistenceResource implements SelfCheckingResourceInterface { private $resource; private $exists; @@ -32,17 +34,14 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ * @param string $resource The fully-qualified class name * @param bool|null $exists Boolean when the existency check has already been done */ - public function __construct($resource, $exists = null) + public function __construct(string $resource, bool $exists = null) { $this->resource = $resource; if (null !== $exists) { - $this->exists = [(bool) $exists, null]; + $this->exists = [$exists, null]; } } - /** - * {@inheritdoc} - */ public function __toString() { return $this->resource; @@ -112,22 +111,20 @@ public function isFresh($timestamp) /** * @internal */ - public function serialize() + public function __sleep(): array { if (null === $this->exists) { $this->isFresh(0); } - return serialize([$this->resource, $this->exists]); + return ['resource', 'exists']; } /** * @internal */ - public function unserialize($serialized) + public function __wakeup() { - list($this->resource, $this->exists) = unserialize($serialized); - if (\is_bool($this->exists)) { $this->exists = [$this->exists, null]; } @@ -219,14 +216,14 @@ public static function throwOnRequiredClass($class, \Exception $previous = null) } $props = [ - 'file' => isset($callerFrame['file']) ? $callerFrame['file'] : null, - 'line' => isset($callerFrame['line']) ? $callerFrame['line'] : null, + 'file' => $callerFrame['file'] ?? null, + 'line' => $callerFrame['line'] ?? null, 'trace' => \array_slice($trace, 1 + $i), ]; foreach ($props as $p => $v) { if (null !== $v) { - $r = new \ReflectionProperty('Exception', $p); + $r = new \ReflectionProperty(\Exception::class, $p); $r->setAccessible(true); $r->setValue($e, $v); } diff --git a/vendor/symfony/config/Resource/ComposerResource.php b/vendor/symfony/config/Resource/ComposerResource.php index 9fb304be..aee6f02b 100644 --- a/vendor/symfony/config/Resource/ComposerResource.php +++ b/vendor/symfony/config/Resource/ComposerResource.php @@ -15,8 +15,10 @@ * ComposerResource tracks the PHP version and Composer dependencies. * * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ -class ComposerResource implements SelfCheckingResourceInterface, \Serializable +class ComposerResource implements SelfCheckingResourceInterface { private $vendors; @@ -33,9 +35,6 @@ public function getVendors() return array_keys($this->vendors); } - /** - * {@inheritdoc} - */ public function __toString() { return __CLASS__; @@ -51,30 +50,14 @@ public function isFresh($timestamp) return array_values(self::$runtimeVendors) === array_values($this->vendors); } - /** - * @internal - */ - public function serialize() - { - return serialize($this->vendors); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - $this->vendors = unserialize($serialized); - } - private static function refresh() { self::$runtimeVendors = []; foreach (get_declared_classes() as $class) { - if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { + if ('C' === $class[0] && str_starts_with($class, 'ComposerAutoloaderInit')) { $r = new \ReflectionClass($class); - $v = \dirname(\dirname($r->getFileName())); + $v = \dirname($r->getFileName(), 2); if (file_exists($v.'/composer/installed.json')) { self::$runtimeVendors[$v] = @filemtime($v.'/composer/installed.json'); } diff --git a/vendor/symfony/config/Resource/DirectoryResource.php b/vendor/symfony/config/Resource/DirectoryResource.php index e79b19ec..a29bd5ee 100644 --- a/vendor/symfony/config/Resource/DirectoryResource.php +++ b/vendor/symfony/config/Resource/DirectoryResource.php @@ -15,8 +15,10 @@ * DirectoryResource represents a resources stored in a subdirectory tree. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ -class DirectoryResource implements SelfCheckingResourceInterface, \Serializable +class DirectoryResource implements SelfCheckingResourceInterface { private $resource; private $pattern; @@ -27,7 +29,7 @@ class DirectoryResource implements SelfCheckingResourceInterface, \Serializable * * @throws \InvalidArgumentException */ - public function __construct($resource, $pattern = null) + public function __construct(string $resource, string $pattern = null) { $this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false); $this->pattern = $pattern; @@ -37,9 +39,6 @@ public function __construct($resource, $pattern = null) } } - /** - * {@inheritdoc} - */ public function __toString() { return md5(serialize([$this->resource, $this->pattern])); @@ -84,7 +83,7 @@ public function isFresh($timestamp) // always monitor directories for changes, except the .. entries // (otherwise deleted files wouldn't get detected) - if ($file->isDir() && '/..' === substr($file, -3)) { + if ($file->isDir() && str_ends_with($file, '/..')) { continue; } @@ -103,20 +102,4 @@ public function isFresh($timestamp) return true; } - - /** - * @internal - */ - public function serialize() - { - return serialize([$this->resource, $this->pattern]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->resource, $this->pattern) = unserialize($serialized); - } } diff --git a/vendor/symfony/config/Resource/FileExistenceResource.php b/vendor/symfony/config/Resource/FileExistenceResource.php index 34047651..760c061b 100644 --- a/vendor/symfony/config/Resource/FileExistenceResource.php +++ b/vendor/symfony/config/Resource/FileExistenceResource.php @@ -18,8 +18,10 @@ * The resource can be a file or a directory. * * @author Charles-Henri Bruyand + * + * @final since Symfony 4.3 */ -class FileExistenceResource implements SelfCheckingResourceInterface, \Serializable +class FileExistenceResource implements SelfCheckingResourceInterface { private $resource; @@ -28,15 +30,12 @@ class FileExistenceResource implements SelfCheckingResourceInterface, \Serializa /** * @param string $resource The file path to the resource */ - public function __construct($resource) + public function __construct(string $resource) { - $this->resource = (string) $resource; + $this->resource = $resource; $this->exists = file_exists($resource); } - /** - * {@inheritdoc} - */ public function __toString() { return $this->resource; @@ -57,20 +56,4 @@ public function isFresh($timestamp) { return file_exists($this->resource) === $this->exists; } - - /** - * @internal - */ - public function serialize() - { - return serialize([$this->resource, $this->exists]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->resource, $this->exists) = unserialize($serialized); - } } diff --git a/vendor/symfony/config/Resource/FileResource.php b/vendor/symfony/config/Resource/FileResource.php index bee06237..96d7d973 100644 --- a/vendor/symfony/config/Resource/FileResource.php +++ b/vendor/symfony/config/Resource/FileResource.php @@ -17,8 +17,10 @@ * The resource can be a file or a directory. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ -class FileResource implements SelfCheckingResourceInterface, \Serializable +class FileResource implements SelfCheckingResourceInterface { /** * @var string|false @@ -30,7 +32,7 @@ class FileResource implements SelfCheckingResourceInterface, \Serializable * * @throws \InvalidArgumentException */ - public function __construct($resource) + public function __construct(string $resource) { $this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false); @@ -39,9 +41,6 @@ public function __construct($resource) } } - /** - * {@inheritdoc} - */ public function __toString() { return $this->resource; @@ -62,20 +61,4 @@ public function isFresh($timestamp) { return false !== ($filemtime = @filemtime($this->resource)) && $filemtime <= $timestamp; } - - /** - * @internal - */ - public function serialize() - { - return serialize($this->resource); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - $this->resource = unserialize($serialized); - } } diff --git a/vendor/symfony/config/Resource/GlobResource.php b/vendor/symfony/config/Resource/GlobResource.php index 1aa3bcf6..57e52846 100644 --- a/vendor/symfony/config/Resource/GlobResource.php +++ b/vendor/symfony/config/Resource/GlobResource.php @@ -20,13 +20,18 @@ * Only existence/removal is tracked (not mtimes.) * * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ -class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface, \Serializable +class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface { private $prefix; private $pattern; private $recursive; private $hash; + private $forExclusion; + private $excludedPrefixes; + private $globBrace; /** * @param string $prefix A directory prefix @@ -35,11 +40,15 @@ class GlobResource implements \IteratorAggregate, SelfCheckingResourceInterface, * * @throws \InvalidArgumentException */ - public function __construct($prefix, $pattern, $recursive) + public function __construct(string $prefix, string $pattern, bool $recursive, bool $forExclusion = false, array $excludedPrefixes = []) { + ksort($excludedPrefixes); $this->prefix = realpath($prefix) ?: (file_exists($prefix) ? $prefix : false); $this->pattern = $pattern; $this->recursive = $recursive; + $this->forExclusion = $forExclusion; + $this->excludedPrefixes = $excludedPrefixes; + $this->globBrace = \defined('GLOB_BRACE') ? \GLOB_BRACE : 0; if (false === $this->prefix) { throw new \InvalidArgumentException(sprintf('The path "%s" does not exist.', $prefix)); @@ -51,12 +60,9 @@ public function getPrefix() return $this->prefix; } - /** - * {@inheritdoc} - */ public function __toString() { - return 'glob.'.$this->prefix.$this->pattern.(int) $this->recursive; + return 'glob.'.$this->prefix.(int) $this->recursive.$this->pattern.(int) $this->forExclusion.implode("\0", $this->excludedPrefixes); } /** @@ -76,52 +82,88 @@ public function isFresh($timestamp) /** * @internal */ - public function serialize() + public function __sleep(): array { if (null === $this->hash) { $this->hash = $this->computeHash(); } - return serialize([$this->prefix, $this->pattern, $this->recursive, $this->hash]); + return ['prefix', 'pattern', 'recursive', 'hash', 'forExclusion', 'excludedPrefixes']; } /** * @internal */ - public function unserialize($serialized) + public function __wakeup(): void { - list($this->prefix, $this->pattern, $this->recursive, $this->hash) = unserialize($serialized); + $this->globBrace = \defined('GLOB_BRACE') ? \GLOB_BRACE : 0; } + /** + * @return \Traversable + */ + #[\ReturnTypeWillChange] public function getIterator() { if (!file_exists($this->prefix) || (!$this->recursive && '' === $this->pattern)) { return; } + $prefix = str_replace('\\', '/', $this->prefix); + $paths = null; + + if ('' === $this->pattern && is_file($prefix)) { + $paths = [$this->prefix]; + } elseif (!str_starts_with($this->prefix, 'phar://') && !str_contains($this->pattern, '/**/')) { + if ($this->globBrace || !str_contains($this->pattern, '{')) { + $paths = glob($this->prefix.$this->pattern, \GLOB_NOSORT | $this->globBrace); + } elseif (!str_contains($this->pattern, '\\') || !preg_match('/\\\\[,{}]/', $this->pattern)) { + foreach ($this->expandGlob($this->pattern) as $p) { + $paths[] = glob($this->prefix.$p, \GLOB_NOSORT); + } + $paths = array_merge(...$paths); + } + } - if (0 !== strpos($this->prefix, 'phar://') && false === strpos($this->pattern, '/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern, '{'))) { - $paths = glob($this->prefix.$this->pattern, \GLOB_NOSORT | (\defined('GLOB_BRACE') ? \GLOB_BRACE : 0)); - sort($paths); + if (null !== $paths) { + natsort($paths); foreach ($paths as $path) { - if ($this->recursive && is_dir($path)) { - $files = iterator_to_array(new \RecursiveIteratorIterator( - new \RecursiveCallbackFilterIterator( - new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS), - function (\SplFileInfo $file) { return '.' !== $file->getBasename()[0]; } - ), - \RecursiveIteratorIterator::LEAVES_ONLY - )); - uasort($files, function (\SplFileInfo $a, \SplFileInfo $b) { - return (string) $a > (string) $b ? 1 : -1; - }); - - foreach ($files as $path => $info) { - if ($info->isFile()) { - yield $path => $info; + if ($this->excludedPrefixes) { + $normalizedPath = str_replace('\\', '/', $path); + do { + if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) { + continue 2; } - } - } elseif (is_file($path)) { + } while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath)); + } + + if (is_file($path)) { + yield $path => new \SplFileInfo($path); + } + if (!is_dir($path)) { + continue; + } + if ($this->forExclusion) { yield $path => new \SplFileInfo($path); + continue; + } + if (!$this->recursive || isset($this->excludedPrefixes[str_replace('\\', '/', $path)])) { + continue; + } + $files = iterator_to_array(new \RecursiveIteratorIterator( + new \RecursiveCallbackFilterIterator( + new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS), + function (\SplFileInfo $file, $path) { + return !isset($this->excludedPrefixes[str_replace('\\', '/', $path)]) && '.' !== $file->getBasename()[0]; + } + ), + \RecursiveIteratorIterator::LEAVES_ONLY + )); + uksort($files, 'strnatcmp'); + + foreach ($files as $path => $info) { + if ($info->isFile()) { + yield $path => $info; + } } } @@ -132,21 +174,38 @@ function (\SplFileInfo $file) { return '.' !== $file->getBasename()[0]; } throw new \LogicException(sprintf('Extended glob pattern "%s" cannot be used as the Finder component is not installed.', $this->pattern)); } + if (is_file($prefix = $this->prefix)) { + $prefix = \dirname($prefix); + $pattern = basename($prefix).$this->pattern; + } else { + $pattern = $this->pattern; + } + $finder = new Finder(); - $regex = Glob::toRegex($this->pattern); + $regex = Glob::toRegex($pattern); if ($this->recursive) { $regex = substr_replace($regex, '(/|$)', -2, 1); } - $prefixLen = \strlen($this->prefix); - foreach ($finder->followLinks()->sortByName()->in($this->prefix) as $path => $info) { - if (preg_match($regex, substr('\\' === \DIRECTORY_SEPARATOR ? str_replace('\\', '/', $path) : $path, $prefixLen)) && $info->isFile()) { - yield $path => $info; + $prefixLen = \strlen($prefix); + foreach ($finder->followLinks()->sortByName()->in($prefix) as $path => $info) { + $normalizedPath = str_replace('\\', '/', $path); + if (!preg_match($regex, substr($normalizedPath, $prefixLen)) || !$info->isFile()) { + continue; } + if ($this->excludedPrefixes) { + do { + if (isset($this->excludedPrefixes[$dirPath = $normalizedPath])) { + continue 2; + } + } while ($prefix !== $dirPath && $dirPath !== $normalizedPath = \dirname($dirPath)); + } + + yield $path => $info; } } - private function computeHash() + private function computeHash(): string { $hash = hash_init('md5'); @@ -156,4 +215,34 @@ private function computeHash() return hash_final($hash); } + + private function expandGlob(string $pattern): array + { + $segments = preg_split('/\{([^{}]*+)\}/', $pattern, -1, \PREG_SPLIT_DELIM_CAPTURE); + $paths = [$segments[0]]; + $patterns = []; + + for ($i = 1; $i < \count($segments); $i += 2) { + $patterns = []; + + foreach (explode(',', $segments[$i]) as $s) { + foreach ($paths as $p) { + $patterns[] = $p.$s.$segments[1 + $i]; + } + } + + $paths = $patterns; + } + + $j = 0; + foreach ($patterns as $i => $p) { + if (str_contains($p, '{')) { + $p = $this->expandGlob($p); + array_splice($paths, $i + $j, 1, $p); + $j += \count($p) - 1; + } + } + + return $paths; + } } diff --git a/vendor/symfony/config/Resource/ReflectionClassResource.php b/vendor/symfony/config/Resource/ReflectionClassResource.php index 79b21fbf..f9661789 100644 --- a/vendor/symfony/config/Resource/ReflectionClassResource.php +++ b/vendor/symfony/config/Resource/ReflectionClassResource.php @@ -11,13 +11,17 @@ namespace Symfony\Component\Config\Resource; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; +use Symfony\Component\DependencyInjection\ServiceSubscriberInterface as LegacyServiceSubscriberInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Messenger\Handler\MessageSubscriberInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; /** * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ -class ReflectionClassResource implements SelfCheckingResourceInterface, \Serializable +class ReflectionClassResource implements SelfCheckingResourceInterface { private $files = []; private $className; @@ -25,7 +29,7 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali private $excludedVendors = []; private $hash; - public function __construct(\ReflectionClass $classReflector, $excludedVendors = []) + public function __construct(\ReflectionClass $classReflector, array $excludedVendors = []) { $this->className = $classReflector->name; $this->classReflector = $classReflector; @@ -60,22 +64,14 @@ public function __toString() /** * @internal */ - public function serialize() + public function __sleep(): array { if (null === $this->hash) { $this->hash = $this->computeHash(); $this->loadFiles($this->classReflector); } - return serialize([$this->files, $this->className, $this->hash]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - list($this->files, $this->className, $this->hash) = unserialize($serialized); + return ['files', 'className', 'hash']; } private function loadFiles(\ReflectionClass $class) @@ -87,7 +83,7 @@ private function loadFiles(\ReflectionClass $class) $file = $class->getFileName(); if (false !== $file && file_exists($file)) { foreach ($this->excludedVendors as $vendor) { - if (0 === strpos($file, $vendor) && false !== strpbrk(substr($file, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) { + if (str_starts_with($file, $vendor) && false !== strpbrk(substr($file, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) { $file = false; break; } @@ -102,7 +98,7 @@ private function loadFiles(\ReflectionClass $class) } while ($class = $class->getParentClass()); } - private function computeHash() + private function computeHash(): string { if (null === $this->classReflector) { try { @@ -121,8 +117,17 @@ private function computeHash() return hash_final($hash); } - private function generateSignature(\ReflectionClass $class) + private function generateSignature(\ReflectionClass $class): iterable { + if (\PHP_VERSION_ID >= 80000) { + $attributes = []; + foreach ($class->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; + } + yield print_r($attributes, true); + $attributes = []; + } + yield $class->getDocComment(); yield (int) $class->isFinal(); yield (int) $class->isAbstract(); @@ -139,6 +144,14 @@ private function generateSignature(\ReflectionClass $class) $defaults = $class->getDefaultProperties(); foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) { + if (\PHP_VERSION_ID >= 80000) { + foreach ($p->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; + } + yield print_r($attributes, true); + $attributes = []; + } + yield $p->getDocComment(); yield $p->isDefault() ? '' : ''; yield $p->isPublic() ? 'public' : 'protected'; @@ -148,67 +161,84 @@ private function generateSignature(\ReflectionClass $class) } } - if (\defined('HHVM_VERSION')) { - foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { - // workaround HHVM bug with variadics, see https://github.com/facebook/hhvm/issues/5762 - yield preg_replace('/^ @@.*/m', '', new ReflectionMethodHhvmWrapper($m->class, $m->name)); + $defined = \Closure::bind(static function ($c) { return \defined($c); }, null, $class->name); + + foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { + if (\PHP_VERSION_ID >= 80000) { + foreach ($m->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; + } + yield print_r($attributes, true); + $attributes = []; } - } else { - foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { - $defaults = []; - $parametersWithUndefinedConstants = []; - foreach ($m->getParameters() as $p) { - if (!$p->isDefaultValueAvailable()) { - $defaults[$p->name] = null; - continue; + $defaults = []; + $parametersWithUndefinedConstants = []; + foreach ($m->getParameters() as $p) { + if (\PHP_VERSION_ID >= 80000) { + foreach ($p->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; } + yield print_r($attributes, true); + $attributes = []; + } - if (!$p->isDefaultValueConstant() || \defined($p->getDefaultValueConstantName())) { - $defaults[$p->name] = $p->getDefaultValue(); + if (!$p->isDefaultValueAvailable()) { + $defaults[$p->name] = null; - continue; - } + continue; + } + + if (\PHP_VERSION_ID >= 80100) { + $defaults[$p->name] = (string) $p; - $defaults[$p->name] = $p->getDefaultValueConstantName(); - $parametersWithUndefinedConstants[$p->name] = true; + continue; } - if (!$parametersWithUndefinedConstants) { - yield preg_replace('/^ @@.*/m', '', $m); - } else { - $t = \PHP_VERSION_ID >= 70000 ? $m->getReturnType() : ''; - $stack = [ - $m->getDocComment(), - $m->getName(), - $m->isAbstract(), - $m->isFinal(), - $m->isStatic(), - $m->isPublic(), - $m->isPrivate(), - $m->isProtected(), - $m->returnsReference(), - $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t, - ]; - - foreach ($m->getParameters() as $p) { - if (!isset($parametersWithUndefinedConstants[$p->name])) { - $stack[] = (string) $p; - } else { - $t = \PHP_VERSION_ID >= 70000 ? $p->getType() : ''; - $stack[] = $p->isOptional(); - $stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t; - $stack[] = $p->isPassedByReference(); - $stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : ''; - $stack[] = $p->getName(); - } - } + if (!$p->isDefaultValueConstant() || $defined($p->getDefaultValueConstantName())) { + $defaults[$p->name] = $p->getDefaultValue(); + + continue; + } - yield implode(',', $stack); + $defaults[$p->name] = $p->getDefaultValueConstantName(); + $parametersWithUndefinedConstants[$p->name] = true; + } + + if (!$parametersWithUndefinedConstants) { + yield preg_replace('/^ @@.*/m', '', $m); + } else { + $t = $m->getReturnType(); + $stack = [ + $m->getDocComment(), + $m->getName(), + $m->isAbstract(), + $m->isFinal(), + $m->isStatic(), + $m->isPublic(), + $m->isPrivate(), + $m->isProtected(), + $m->returnsReference(), + $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t, + ]; + + foreach ($m->getParameters() as $p) { + if (!isset($parametersWithUndefinedConstants[$p->name])) { + $stack[] = (string) $p; + } else { + $t = $p->getType(); + $stack[] = $p->isOptional(); + $stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t; + $stack[] = $p->isPassedByReference(); + $stack[] = $p->isVariadic(); + $stack[] = $p->getName(); + } } - yield print_r($defaults, true); + yield implode(',', $stack); } + + yield print_r($defaults, true); } if ($class->isAbstract() || $class->isInterface() || $class->isTrait()) { @@ -217,40 +247,22 @@ private function generateSignature(\ReflectionClass $class) if (interface_exists(EventSubscriberInterface::class, false) && $class->isSubclassOf(EventSubscriberInterface::class)) { yield EventSubscriberInterface::class; - yield print_r(\call_user_func([$class->name, 'getSubscribedEvents']), true); + yield print_r($class->name::getSubscribedEvents(), true); } - if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) { - yield ServiceSubscriberInterface::class; - yield print_r(\call_user_func([$class->name, 'getSubscribedServices']), true); + if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) { + yield MessageSubscriberInterface::class; + foreach ($class->name::getHandledMessages() as $key => $value) { + yield $key.print_r($value, true); + } } - } -} - -/** - * @internal - */ -class ReflectionMethodHhvmWrapper extends \ReflectionMethod -{ - public function getParameters() - { - $params = []; - foreach (parent::getParameters() as $i => $p) { - $params[] = new ReflectionParameterHhvmWrapper([$this->class, $this->name], $i); + if (interface_exists(LegacyServiceSubscriberInterface::class, false) && $class->isSubclassOf(LegacyServiceSubscriberInterface::class)) { + yield LegacyServiceSubscriberInterface::class; + yield print_r([$class->name, 'getSubscribedServices'](), true); + } elseif (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) { + yield ServiceSubscriberInterface::class; + yield print_r($class->name::getSubscribedServices(), true); } - - return $params; - } -} - -/** - * @internal - */ -class ReflectionParameterHhvmWrapper extends \ReflectionParameter -{ - public function getDefaultValue() - { - return [$this->isVariadic(), $this->isDefaultValueAvailable() ? parent::getDefaultValue() : null]; } } diff --git a/vendor/symfony/config/Resource/ResourceInterface.php b/vendor/symfony/config/Resource/ResourceInterface.php index d98fd427..9a0cd9a4 100644 --- a/vendor/symfony/config/Resource/ResourceInterface.php +++ b/vendor/symfony/config/Resource/ResourceInterface.php @@ -26,8 +26,6 @@ interface ResourceInterface * to be identical for different ResourceInterface instances referring to the same * resource; and it should be unlikely to collide with that of other, unrelated * resource instances. - * - * @return string A string representation unique to the underlying Resource */ public function __toString(); } diff --git a/vendor/symfony/config/ResourceCheckerConfigCache.php b/vendor/symfony/config/ResourceCheckerConfigCache.php index 0538f3f4..51311731 100644 --- a/vendor/symfony/config/ResourceCheckerConfigCache.php +++ b/vendor/symfony/config/ResourceCheckerConfigCache.php @@ -37,7 +37,7 @@ class ResourceCheckerConfigCache implements ConfigCacheInterface * @param string $file The absolute cache path * @param iterable|ResourceCheckerInterface[] $resourceCheckers The ResourceCheckers to use for the freshness check */ - public function __construct($file, $resourceCheckers = []) + public function __construct(string $file, iterable $resourceCheckers = []) { $this->file = $file; $this->resourceCheckers = $resourceCheckers; @@ -137,28 +137,25 @@ public function write($content, array $metadata = null) } } - if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) { + if (\function_exists('opcache_invalidate') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN)) { @opcache_invalidate($this->file, true); } } /** * Gets the meta file path. - * - * @return string The meta file path */ - private function getMetaFile() + private function getMetaFile(): string { return $this->file.'.meta'; } - private function safelyUnserialize($file) + private function safelyUnserialize(string $file) { - $e = null; $meta = false; $content = file_get_contents($file); $signalingException = new \UnexpectedValueException(); - $prevUnserializeHandler = ini_set('unserialize_callback_func', ''); + $prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback'); $prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) { if (__FILE__ === $file) { throw $signalingException; @@ -169,15 +166,23 @@ private function safelyUnserialize($file) try { $meta = unserialize($content); - } catch (\Error $e) { - } catch (\Exception $e) { - } - restore_error_handler(); - ini_set('unserialize_callback_func', $prevUnserializeHandler); - if (null !== $e && $e !== $signalingException) { - throw $e; + } catch (\Throwable $e) { + if ($e !== $signalingException) { + throw $e; + } + } finally { + restore_error_handler(); + ini_set('unserialize_callback_func', $prevUnserializeHandler); } return $meta; } + + /** + * @internal + */ + public static function handleUnserializeCallback($class) + { + trigger_error('Class not found: '.$class); + } } diff --git a/vendor/symfony/config/ResourceCheckerConfigCacheFactory.php b/vendor/symfony/config/ResourceCheckerConfigCacheFactory.php index c00fa7db..0338635f 100644 --- a/vendor/symfony/config/ResourceCheckerConfigCacheFactory.php +++ b/vendor/symfony/config/ResourceCheckerConfigCacheFactory.php @@ -24,7 +24,7 @@ class ResourceCheckerConfigCacheFactory implements ConfigCacheFactoryInterface /** * @param iterable|ResourceCheckerInterface[] $resourceCheckers */ - public function __construct($resourceCheckers = []) + public function __construct(iterable $resourceCheckers = []) { $this->resourceCheckers = $resourceCheckers; } @@ -40,7 +40,7 @@ public function cache($file, $callback) $cache = new ResourceCheckerConfigCache($file, $this->resourceCheckers); if (!$cache->isFresh()) { - \call_user_func($callback, $cache); + $callback($cache); } return $cache; diff --git a/vendor/symfony/config/ResourceCheckerInterface.php b/vendor/symfony/config/ResourceCheckerInterface.php index 612d7778..ac0d4024 100644 --- a/vendor/symfony/config/ResourceCheckerInterface.php +++ b/vendor/symfony/config/ResourceCheckerInterface.php @@ -30,8 +30,6 @@ interface ResourceCheckerInterface * Queries the ResourceChecker whether it can validate a given * resource or not. * - * @param ResourceInterface $metadata The resource to be checked for freshness - * * @return bool True if the ResourceChecker can handle this resource type, false if not */ public function supports(ResourceInterface $metadata); @@ -39,8 +37,7 @@ public function supports(ResourceInterface $metadata); /** * Validates the resource. * - * @param ResourceInterface $resource The resource to be validated - * @param int $timestamp The timestamp at which the cache associated with this resource was created + * @param int $timestamp The timestamp at which the cache associated with this resource was created * * @return bool True if the resource has not changed since the given timestamp, false otherwise */ diff --git a/vendor/symfony/config/Tests/ConfigCacheFactoryTest.php b/vendor/symfony/config/Tests/ConfigCacheFactoryTest.php deleted file mode 100644 index 6190b9b4..00000000 --- a/vendor/symfony/config/Tests/ConfigCacheFactoryTest.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\ConfigCacheFactory; - -class ConfigCacheFactoryTest extends TestCase -{ - public function testCacheWithInvalidCallback() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('Invalid type for callback argument. Expected callable, but got "object".'); - $cacheFactory = new ConfigCacheFactory(true); - - $cacheFactory->cache('file', new \stdClass()); - } -} diff --git a/vendor/symfony/config/Tests/ConfigCacheTest.php b/vendor/symfony/config/Tests/ConfigCacheTest.php deleted file mode 100644 index 95a58817..00000000 --- a/vendor/symfony/config/Tests/ConfigCacheTest.php +++ /dev/null @@ -1,99 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\ConfigCache; -use Symfony\Component\Config\Tests\Resource\ResourceStub; - -class ConfigCacheTest extends TestCase -{ - private $cacheFile = null; - - protected function setUp() - { - $this->cacheFile = tempnam(sys_get_temp_dir(), 'config_'); - } - - protected function tearDown() - { - $files = [$this->cacheFile, $this->cacheFile.'.meta']; - - foreach ($files as $file) { - if (file_exists($file)) { - @unlink($file); - } - } - } - - /** - * @dataProvider debugModes - */ - public function testCacheIsNotValidIfNothingHasBeenCached($debug) - { - unlink($this->cacheFile); // remove tempnam() side effect - $cache = new ConfigCache($this->cacheFile, $debug); - - $this->assertFalse($cache->isFresh()); - } - - public function testIsAlwaysFreshInProduction() - { - $staleResource = new ResourceStub(); - $staleResource->setFresh(false); - - $cache = new ConfigCache($this->cacheFile, false); - $cache->write('', [$staleResource]); - - $this->assertTrue($cache->isFresh()); - } - - /** - * @dataProvider debugModes - */ - public function testIsFreshWhenNoResourceProvided($debug) - { - $cache = new ConfigCache($this->cacheFile, $debug); - $cache->write('', []); - $this->assertTrue($cache->isFresh()); - } - - public function testFreshResourceInDebug() - { - $freshResource = new ResourceStub(); - $freshResource->setFresh(true); - - $cache = new ConfigCache($this->cacheFile, true); - $cache->write('', [$freshResource]); - - $this->assertTrue($cache->isFresh()); - } - - public function testStaleResourceInDebug() - { - $staleResource = new ResourceStub(); - $staleResource->setFresh(false); - - $cache = new ConfigCache($this->cacheFile, true); - $cache->write('', [$staleResource]); - - $this->assertFalse($cache->isFresh()); - } - - public function debugModes() - { - return [ - [true], - [false], - ]; - } -} diff --git a/vendor/symfony/config/Tests/Definition/ArrayNodeTest.php b/vendor/symfony/config/Tests/Definition/ArrayNodeTest.php deleted file mode 100644 index f726e8dd..00000000 --- a/vendor/symfony/config/Tests/Definition/ArrayNodeTest.php +++ /dev/null @@ -1,237 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\ArrayNode; -use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; -use Symfony\Component\Config\Definition\ScalarNode; - -class ArrayNodeTest extends TestCase -{ - public function testNormalizeThrowsExceptionWhenFalseIsNotAllowed() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $node = new ArrayNode('root'); - $node->normalize(false); - } - - public function testExceptionThrownOnUnrecognizedChild() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('Unrecognized option "foo" under "root"'); - $node = new ArrayNode('root'); - $node->normalize(['foo' => 'bar']); - } - - public function ignoreAndRemoveMatrixProvider() - { - $unrecognizedOptionException = new InvalidConfigurationException('Unrecognized option "foo" under "root"'); - - return [ - [true, true, [], 'no exception is thrown for an unrecognized child if the ignoreExtraKeys option is set to true'], - [true, false, ['foo' => 'bar'], 'extra keys are not removed when ignoreExtraKeys second option is set to false'], - [false, true, $unrecognizedOptionException], - [false, false, $unrecognizedOptionException], - ]; - } - - /** - * @dataProvider ignoreAndRemoveMatrixProvider - */ - public function testIgnoreAndRemoveBehaviors($ignore, $remove, $expected, $message = '') - { - if ($expected instanceof \Exception) { - $this->expectException(\get_class($expected)); - $this->expectExceptionMessage($expected->getMessage()); - } - $node = new ArrayNode('root'); - $node->setIgnoreExtraKeys($ignore, $remove); - $result = $node->normalize(['foo' => 'bar']); - $this->assertSame($expected, $result, $message); - } - - /** - * @dataProvider getPreNormalizationTests - */ - public function testPreNormalize($denormalized, $normalized) - { - $node = new ArrayNode('foo'); - - $r = new \ReflectionMethod($node, 'preNormalize'); - $r->setAccessible(true); - - $this->assertSame($normalized, $r->invoke($node, $denormalized)); - } - - public function getPreNormalizationTests() - { - return [ - [ - ['foo-bar' => 'foo'], - ['foo_bar' => 'foo'], - ], - [ - ['foo-bar_moo' => 'foo'], - ['foo-bar_moo' => 'foo'], - ], - [ - ['anything-with-dash-and-no-underscore' => 'first', 'no_dash' => 'second'], - ['anything_with_dash_and_no_underscore' => 'first', 'no_dash' => 'second'], - ], - [ - ['foo-bar' => null, 'foo_bar' => 'foo'], - ['foo-bar' => null, 'foo_bar' => 'foo'], - ], - ]; - } - - /** - * @dataProvider getZeroNamedNodeExamplesData - */ - public function testNodeNameCanBeZero($denormalized, $normalized) - { - $zeroNode = new ArrayNode(0); - $zeroNode->addChild(new ScalarNode('name')); - $fiveNode = new ArrayNode(5); - $fiveNode->addChild(new ScalarNode(0)); - $fiveNode->addChild(new ScalarNode('new_key')); - $rootNode = new ArrayNode('root'); - $rootNode->addChild($zeroNode); - $rootNode->addChild($fiveNode); - $rootNode->addChild(new ScalarNode('string_key')); - $r = new \ReflectionMethod($rootNode, 'normalizeValue'); - $r->setAccessible(true); - - $this->assertSame($normalized, $r->invoke($rootNode, $denormalized)); - } - - public function getZeroNamedNodeExamplesData() - { - return [ - [ - [ - 0 => [ - 'name' => 'something', - ], - 5 => [ - 0 => 'this won\'t work too', - 'new_key' => 'some other value', - ], - 'string_key' => 'just value', - ], - [ - 0 => [ - 'name' => 'something', - ], - 5 => [ - 0 => 'this won\'t work too', - 'new_key' => 'some other value', - ], - 'string_key' => 'just value', - ], - ], - ]; - } - - /** - * @dataProvider getPreNormalizedNormalizedOrderedData - */ - public function testChildrenOrderIsMaintainedOnNormalizeValue($prenormalized, $normalized) - { - $scalar1 = new ScalarNode('1'); - $scalar2 = new ScalarNode('2'); - $scalar3 = new ScalarNode('3'); - $node = new ArrayNode('foo'); - $node->addChild($scalar1); - $node->addChild($scalar3); - $node->addChild($scalar2); - - $r = new \ReflectionMethod($node, 'normalizeValue'); - $r->setAccessible(true); - - $this->assertSame($normalized, $r->invoke($node, $prenormalized)); - } - - public function getPreNormalizedNormalizedOrderedData() - { - return [ - [ - ['2' => 'two', '1' => 'one', '3' => 'three'], - ['2' => 'two', '1' => 'one', '3' => 'three'], - ], - ]; - } - - public function testAddChildEmptyName() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('Child nodes must be named.'); - $node = new ArrayNode('root'); - - $childNode = new ArrayNode(''); - $node->addChild($childNode); - } - - public function testAddChildNameAlreadyExists() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('A child node named "foo" already exists.'); - $node = new ArrayNode('root'); - - $childNode = new ArrayNode('foo'); - $node->addChild($childNode); - - $childNodeWithSameName = new ArrayNode('foo'); - $node->addChild($childNodeWithSameName); - } - - public function testGetDefaultValueWithoutDefaultValue() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('The node at path "foo" has no default value.'); - $node = new ArrayNode('foo'); - $node->getDefaultValue(); - } - - public function testSetDeprecated() - { - $childNode = new ArrayNode('foo'); - $childNode->setDeprecated('"%node%" is deprecated'); - - $this->assertTrue($childNode->isDeprecated()); - $this->assertSame('"foo" is deprecated', $childNode->getDeprecationMessage($childNode->getName(), $childNode->getPath())); - - $node = new ArrayNode('root'); - $node->addChild($childNode); - - $deprecationTriggered = false; - $deprecationHandler = function ($level, $message, $file, $line) use (&$prevErrorHandler, &$deprecationTriggered) { - if (\E_USER_DEPRECATED === $level) { - return $deprecationTriggered = true; - } - - return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false; - }; - - $prevErrorHandler = set_error_handler($deprecationHandler); - $node->finalize([]); - restore_error_handler(); - - $this->assertFalse($deprecationTriggered, '->finalize() should not trigger if the deprecated node is not set'); - - $prevErrorHandler = set_error_handler($deprecationHandler); - $node->finalize(['foo' => []]); - restore_error_handler(); - $this->assertTrue($deprecationTriggered, '->finalize() should trigger if the deprecated node is set'); - } -} diff --git a/vendor/symfony/config/Tests/Definition/BooleanNodeTest.php b/vendor/symfony/config/Tests/Definition/BooleanNodeTest.php deleted file mode 100644 index 8552eeba..00000000 --- a/vendor/symfony/config/Tests/Definition/BooleanNodeTest.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\BooleanNode; - -class BooleanNodeTest extends TestCase -{ - /** - * @dataProvider getValidValues - */ - public function testNormalize($value) - { - $node = new BooleanNode('test'); - $this->assertSame($value, $node->normalize($value)); - } - - /** - * @dataProvider getValidValues - * - * @param bool $value - */ - public function testValidNonEmptyValues($value) - { - $node = new BooleanNode('test'); - $node->setAllowEmptyValue(false); - - $this->assertSame($value, $node->finalize($value)); - } - - public function getValidValues() - { - return [ - [false], - [true], - ]; - } - - /** - * @dataProvider getInvalidValues - */ - public function testNormalizeThrowsExceptionOnInvalidValues($value) - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $node = new BooleanNode('test'); - $node->normalize($value); - } - - public function getInvalidValues() - { - return [ - [null], - [''], - ['foo'], - [0], - [1], - [0.0], - [0.1], - [[]], - [['foo' => 'bar']], - [new \stdClass()], - ]; - } -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php deleted file mode 100644 index 1123b415..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php +++ /dev/null @@ -1,362 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; -use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition; -use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException; -use Symfony\Component\Config\Definition\Processor; - -class ArrayNodeDefinitionTest extends TestCase -{ - public function testAppendingSomeNode() - { - $parent = new ArrayNodeDefinition('root'); - $child = new ScalarNodeDefinition('child'); - - $parent - ->children() - ->scalarNode('foo')->end() - ->scalarNode('bar')->end() - ->end() - ->append($child); - - $this->assertCount(3, $this->getField($parent, 'children')); - $this->assertContains($child, $this->getField($parent, 'children')); - } - - /** - * @dataProvider providePrototypeNodeSpecificCalls - */ - public function testPrototypeNodeSpecificOption($method, $args) - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidDefinitionException'); - $node = new ArrayNodeDefinition('root'); - - \call_user_func_array([$node, $method], $args); - - $node->getNode(); - } - - public function providePrototypeNodeSpecificCalls() - { - return [ - ['defaultValue', [[]]], - ['addDefaultChildrenIfNoneSet', []], - ['requiresAtLeastOneElement', []], - ['useAttributeAsKey', ['foo']], - ]; - } - - public function testConcreteNodeSpecificOption() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidDefinitionException'); - $node = new ArrayNodeDefinition('root'); - $node - ->addDefaultsIfNotSet() - ->prototype('array') - ; - $node->getNode(); - } - - public function testPrototypeNodesCantHaveADefaultValueWhenUsingDefaultChildren() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidDefinitionException'); - $node = new ArrayNodeDefinition('root'); - $node - ->defaultValue([]) - ->addDefaultChildrenIfNoneSet('foo') - ->prototype('array') - ; - $node->getNode(); - } - - public function testPrototypedArrayNodeDefaultWhenUsingDefaultChildren() - { - $node = new ArrayNodeDefinition('root'); - $node - ->addDefaultChildrenIfNoneSet() - ->prototype('array') - ; - $tree = $node->getNode(); - $this->assertEquals([[]], $tree->getDefaultValue()); - } - - /** - * @dataProvider providePrototypedArrayNodeDefaults - */ - public function testPrototypedArrayNodeDefault($args, $shouldThrowWhenUsingAttrAsKey, $shouldThrowWhenNotUsingAttrAsKey, $defaults) - { - $node = new ArrayNodeDefinition('root'); - $node - ->addDefaultChildrenIfNoneSet($args) - ->prototype('array') - ; - - try { - $tree = $node->getNode(); - $this->assertFalse($shouldThrowWhenNotUsingAttrAsKey); - $this->assertEquals($defaults, $tree->getDefaultValue()); - } catch (InvalidDefinitionException $e) { - $this->assertTrue($shouldThrowWhenNotUsingAttrAsKey); - } - - $node = new ArrayNodeDefinition('root'); - $node - ->useAttributeAsKey('attr') - ->addDefaultChildrenIfNoneSet($args) - ->prototype('array') - ; - - try { - $tree = $node->getNode(); - $this->assertFalse($shouldThrowWhenUsingAttrAsKey); - $this->assertEquals($defaults, $tree->getDefaultValue()); - } catch (InvalidDefinitionException $e) { - $this->assertTrue($shouldThrowWhenUsingAttrAsKey); - } - } - - public function providePrototypedArrayNodeDefaults() - { - return [ - [null, true, false, [[]]], - [2, true, false, [[], []]], - ['2', false, true, ['2' => []]], - ['foo', false, true, ['foo' => []]], - [['foo'], false, true, ['foo' => []]], - [['foo', 'bar'], false, true, ['foo' => [], 'bar' => []]], - ]; - } - - public function testNestedPrototypedArrayNodes() - { - $nodeDefinition = new ArrayNodeDefinition('root'); - $nodeDefinition - ->addDefaultChildrenIfNoneSet() - ->prototype('array') - ->prototype('array') - ; - $node = $nodeDefinition->getNode(); - - $this->assertInstanceOf('Symfony\Component\Config\Definition\PrototypedArrayNode', $node); - $this->assertInstanceOf('Symfony\Component\Config\Definition\PrototypedArrayNode', $node->getPrototype()); - } - - public function testEnabledNodeDefaults() - { - $node = new ArrayNodeDefinition('root'); - $node - ->canBeEnabled() - ->children() - ->scalarNode('foo')->defaultValue('bar')->end() - ; - - $this->assertEquals(['enabled' => false, 'foo' => 'bar'], $node->getNode()->getDefaultValue()); - } - - /** - * @dataProvider getEnableableNodeFixtures - */ - public function testTrueEnableEnabledNode($expected, $config, $message) - { - $processor = new Processor(); - $node = new ArrayNodeDefinition('root'); - $node - ->canBeEnabled() - ->children() - ->scalarNode('foo')->defaultValue('bar')->end() - ; - - $this->assertEquals( - $expected, - $processor->process($node->getNode(), $config), - $message - ); - } - - public function testCanBeDisabled() - { - $node = new ArrayNodeDefinition('root'); - $node->canBeDisabled(); - - $this->assertTrue($this->getField($node, 'addDefaults')); - $this->assertEquals(['enabled' => false], $this->getField($node, 'falseEquivalent')); - $this->assertEquals(['enabled' => true], $this->getField($node, 'trueEquivalent')); - $this->assertEquals(['enabled' => true], $this->getField($node, 'nullEquivalent')); - - $nodeChildren = $this->getField($node, 'children'); - $this->assertArrayHasKey('enabled', $nodeChildren); - - $enabledNode = $nodeChildren['enabled']; - $this->assertTrue($this->getField($enabledNode, 'default')); - $this->assertTrue($this->getField($enabledNode, 'defaultValue')); - } - - public function testIgnoreExtraKeys() - { - $node = new ArrayNodeDefinition('root'); - - $this->assertFalse($this->getField($node, 'ignoreExtraKeys')); - - $result = $node->ignoreExtraKeys(); - - $this->assertEquals($node, $result); - $this->assertTrue($this->getField($node, 'ignoreExtraKeys')); - } - - public function testNormalizeKeys() - { - $node = new ArrayNodeDefinition('root'); - - $this->assertTrue($this->getField($node, 'normalizeKeys')); - - $result = $node->normalizeKeys(false); - - $this->assertEquals($node, $result); - $this->assertFalse($this->getField($node, 'normalizeKeys')); - } - - public function testUnsetChild() - { - $node = new ArrayNodeDefinition('root'); - $node - ->children() - ->scalarNode('value') - ->beforeNormalization() - ->ifTrue(function ($value) { - return empty($value); - }) - ->thenUnset() - ->end() - ->end() - ->end() - ; - - $this->assertSame([], $node->getNode()->normalize(['value' => null])); - } - - public function testPrototypeVariable() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('variable'), $node->variablePrototype()); - } - - public function testPrototypeScalar() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('scalar'), $node->scalarPrototype()); - } - - public function testPrototypeBoolean() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('boolean'), $node->booleanPrototype()); - } - - public function testPrototypeInteger() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('integer'), $node->integerPrototype()); - } - - public function testPrototypeFloat() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('float'), $node->floatPrototype()); - } - - public function testPrototypeArray() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('array'), $node->arrayPrototype()); - } - - public function testPrototypeEnum() - { - $node = new ArrayNodeDefinition('root'); - $this->assertEquals($node->prototype('enum'), $node->enumPrototype()); - } - - public function getEnableableNodeFixtures() - { - return [ - [['enabled' => true, 'foo' => 'bar'], [true], 'true enables an enableable node'], - [['enabled' => true, 'foo' => 'bar'], [null], 'null enables an enableable node'], - [['enabled' => true, 'foo' => 'bar'], [['enabled' => true]], 'An enableable node can be enabled'], - [['enabled' => true, 'foo' => 'baz'], [['foo' => 'baz']], 'any configuration enables an enableable node'], - [['enabled' => false, 'foo' => 'baz'], [['foo' => 'baz', 'enabled' => false]], 'An enableable node can be disabled'], - [['enabled' => false, 'foo' => 'bar'], [false], 'false disables an enableable node'], - ]; - } - - public function testRequiresAtLeastOneElement() - { - $node = new ArrayNodeDefinition('root'); - $node - ->requiresAtLeastOneElement() - ->integerPrototype(); - - $node->getNode()->finalize([1]); - - $this->addToAssertionCount(1); - } - - /** - * @group legacy - * @expectedDeprecation Using Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition::cannotBeEmpty() at path "root" has no effect, consider requiresAtLeastOneElement() instead. In 4.0 both methods will behave the same. - */ - public function testCannotBeEmpty() - { - $node = new ArrayNodeDefinition('root'); - $node - ->cannotBeEmpty() - ->integerPrototype(); - - $node->getNode()->finalize([]); - } - - public function testSetDeprecated() - { - $node = new ArrayNodeDefinition('root'); - $node - ->children() - ->arrayNode('foo')->setDeprecated('The "%path%" node is deprecated.')->end() - ->end() - ; - $deprecatedNode = $node->getNode()->getChildren()['foo']; - - $this->assertTrue($deprecatedNode->isDeprecated()); - $this->assertSame('The "root.foo" node is deprecated.', $deprecatedNode->getDeprecationMessage($deprecatedNode->getName(), $deprecatedNode->getPath())); - } - - /** - * @group legacy - * @expectedDeprecation ->cannotBeEmpty() is not applicable to concrete nodes at path "root". In 4.0 it will throw an exception. - */ - public function testCannotBeEmptyOnConcreteNode() - { - $node = new ArrayNodeDefinition('root'); - $node->cannotBeEmpty(); - - $node->getNode()->finalize([]); - } - - protected function getField($object, $field) - { - $reflection = new \ReflectionProperty($object, $field); - $reflection->setAccessible(true); - - return $reflection->getValue($object); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/BooleanNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/BooleanNodeDefinitionTest.php deleted file mode 100644 index 6f568a2d..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/BooleanNodeDefinitionTest.php +++ /dev/null @@ -1,37 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition; - -class BooleanNodeDefinitionTest extends TestCase -{ - public function testCannotBeEmptyThrowsAnException() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidDefinitionException'); - $this->expectExceptionMessage('->cannotBeEmpty() is not applicable to BooleanNodeDefinition.'); - $def = new BooleanNodeDefinition('foo'); - $def->cannotBeEmpty(); - } - - public function testSetDeprecated() - { - $def = new BooleanNodeDefinition('foo'); - $def->setDeprecated('The "%path%" node is deprecated.'); - - $node = $def->getNode(); - - $this->assertTrue($node->isDeprecated()); - $this->assertSame('The "foo" node is deprecated.', $node->getDeprecationMessage($node->getName(), $node->getPath())); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/EnumNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/EnumNodeDefinitionTest.php deleted file mode 100644 index 2e43a135..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/EnumNodeDefinitionTest.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\EnumNodeDefinition; - -class EnumNodeDefinitionTest extends TestCase -{ - public function testWithOneValue() - { - $def = new EnumNodeDefinition('foo'); - $def->values(['foo']); - - $node = $def->getNode(); - $this->assertEquals(['foo'], $node->getValues()); - } - - public function testWithOneDistinctValue() - { - $def = new EnumNodeDefinition('foo'); - $def->values(['foo', 'foo']); - - $node = $def->getNode(); - $this->assertEquals(['foo'], $node->getValues()); - } - - public function testNoValuesPassed() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('You must call ->values() on enum nodes.'); - $def = new EnumNodeDefinition('foo'); - $def->getNode(); - } - - public function testWithNoValues() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('->values() must be called with at least one value.'); - $def = new EnumNodeDefinition('foo'); - $def->values([]); - } - - public function testGetNode() - { - $def = new EnumNodeDefinition('foo'); - $def->values(['foo', 'bar']); - - $node = $def->getNode(); - $this->assertEquals(['foo', 'bar'], $node->getValues()); - } - - public function testSetDeprecated() - { - $def = new EnumNodeDefinition('foo'); - $def->values(['foo', 'bar']); - $def->setDeprecated('The "%path%" node is deprecated.'); - - $node = $def->getNode(); - - $this->assertTrue($node->isDeprecated()); - $this->assertSame('The "foo" node is deprecated.', $def->getNode()->getDeprecationMessage($node->getName(), $node->getPath())); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/ExprBuilderTest.php b/vendor/symfony/config/Tests/Definition/Builder/ExprBuilderTest.php deleted file mode 100644 index 2dfb7a0a..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/ExprBuilderTest.php +++ /dev/null @@ -1,264 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; - -class ExprBuilderTest extends TestCase -{ - public function testAlwaysExpression() - { - $test = $this->getTestBuilder() - ->always($this->returnClosure('new_value')) - ->end(); - - $this->assertFinalizedValueIs('new_value', $test); - } - - public function testIfTrueExpression() - { - $test = $this->getTestBuilder() - ->ifTrue() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test, ['key' => true]); - - $test = $this->getTestBuilder() - ->ifTrue(function ($v) { return true; }) - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test); - - $test = $this->getTestBuilder() - ->ifTrue(function ($v) { return false; }) - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('value', $test); - } - - public function testIfStringExpression() - { - $test = $this->getTestBuilder() - ->ifString() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test); - - $test = $this->getTestBuilder() - ->ifString() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs(45, $test, ['key' => 45]); - } - - public function testIfNullExpression() - { - $test = $this->getTestBuilder() - ->ifNull() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test, ['key' => null]); - - $test = $this->getTestBuilder() - ->ifNull() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('value', $test); - } - - public function testIfEmptyExpression() - { - $test = $this->getTestBuilder() - ->ifEmpty() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test, ['key' => []]); - - $test = $this->getTestBuilder() - ->ifEmpty() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('value', $test); - } - - public function testIfArrayExpression() - { - $test = $this->getTestBuilder() - ->ifArray() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test, ['key' => []]); - - $test = $this->getTestBuilder() - ->ifArray() - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('value', $test); - } - - public function testIfInArrayExpression() - { - $test = $this->getTestBuilder() - ->ifInArray(['foo', 'bar', 'value']) - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test); - - $test = $this->getTestBuilder() - ->ifInArray(['foo', 'bar']) - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('value', $test); - } - - public function testIfNotInArrayExpression() - { - $test = $this->getTestBuilder() - ->ifNotInArray(['foo', 'bar']) - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test); - - $test = $this->getTestBuilder() - ->ifNotInArray(['foo', 'bar', 'value_from_config']) - ->then($this->returnClosure('new_value')) - ->end(); - $this->assertFinalizedValueIs('new_value', $test); - } - - public function testThenEmptyArrayExpression() - { - $test = $this->getTestBuilder() - ->ifString() - ->thenEmptyArray() - ->end(); - $this->assertFinalizedValueIs([], $test); - } - - /** - * @dataProvider castToArrayValues - */ - public function testCastToArrayExpression($configValue, $expectedValue) - { - $test = $this->getTestBuilder() - ->castToArray() - ->end(); - $this->assertFinalizedValueIs($expectedValue, $test, ['key' => $configValue]); - } - - public function castToArrayValues() - { - yield ['value', ['value']]; - yield [-3.14, [-3.14]]; - yield [null, [null]]; - yield [['value'], ['value']]; - } - - public function testThenInvalid() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $test = $this->getTestBuilder() - ->ifString() - ->thenInvalid('Invalid value') - ->end(); - $this->finalizeTestBuilder($test); - } - - public function testThenUnsetExpression() - { - $test = $this->getTestBuilder() - ->ifString() - ->thenUnset() - ->end(); - $this->assertEquals([], $this->finalizeTestBuilder($test)); - } - - public function testEndIfPartNotSpecified() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('You must specify an if part.'); - $this->getTestBuilder()->end(); - } - - public function testEndThenPartNotSpecified() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('You must specify a then part.'); - $builder = $this->getTestBuilder(); - $builder->ifPart = 'test'; - $builder->end(); - } - - /** - * Create a test treebuilder with a variable node, and init the validation. - * - * @return TreeBuilder - */ - protected function getTestBuilder() - { - $builder = new TreeBuilder(); - - return $builder - ->root('test') - ->children() - ->variableNode('key') - ->validate() - ; - } - - /** - * Close the validation process and finalize with the given config. - * - * @param TreeBuilder $testBuilder The tree builder to finalize - * @param array $config The config you want to use for the finalization, if nothing provided - * a simple ['key'=>'value'] will be used - * - * @return array The finalized config values - */ - protected function finalizeTestBuilder($testBuilder, $config = null) - { - return $testBuilder - ->end() - ->end() - ->end() - ->buildTree() - ->finalize(null === $config ? ['key' => 'value'] : $config) - ; - } - - /** - * Return a closure that will return the given value. - * - * @param mixed $val The value that the closure must return - * - * @return \Closure - */ - protected function returnClosure($val) - { - return function ($v) use ($val) { - return $val; - }; - } - - /** - * Assert that the given test builder, will return the given value. - * - * @param mixed $value The value to test - * @param TreeBuilder $treeBuilder The tree builder to finalize - * @param mixed $config The config values that new to be finalized - */ - protected function assertFinalizedValueIs($value, $treeBuilder, $config = null) - { - $this->assertEquals(['key' => $value], $this->finalizeTestBuilder($treeBuilder, $config)); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/NodeBuilderTest.php b/vendor/symfony/config/Tests/Definition/Builder/NodeBuilderTest.php deleted file mode 100644 index 46518c65..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/NodeBuilderTest.php +++ /dev/null @@ -1,91 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\NodeBuilder as BaseNodeBuilder; -use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition as BaseVariableNodeDefinition; - -class NodeBuilderTest extends TestCase -{ - public function testThrowsAnExceptionWhenTryingToCreateANonRegisteredNodeType() - { - $this->expectException('RuntimeException'); - $builder = new BaseNodeBuilder(); - $builder->node('', 'foobar'); - } - - public function testThrowsAnExceptionWhenTheNodeClassIsNotFound() - { - $this->expectException('RuntimeException'); - $builder = new BaseNodeBuilder(); - $builder - ->setNodeClass('noclasstype', '\\foo\\bar\\noclass') - ->node('', 'noclasstype'); - } - - public function testAddingANewNodeType() - { - $class = SomeNodeDefinition::class; - - $builder = new BaseNodeBuilder(); - $node = $builder - ->setNodeClass('newtype', $class) - ->node('', 'newtype'); - - $this->assertInstanceOf($class, $node); - } - - public function testOverridingAnExistingNodeType() - { - $class = SomeNodeDefinition::class; - - $builder = new BaseNodeBuilder(); - $node = $builder - ->setNodeClass('variable', $class) - ->node('', 'variable'); - - $this->assertInstanceOf($class, $node); - } - - public function testNodeTypesAreNotCaseSensitive() - { - $builder = new BaseNodeBuilder(); - - $node1 = $builder->node('', 'VaRiAbLe'); - $node2 = $builder->node('', 'variable'); - - $this->assertInstanceOf(\get_class($node1), $node2); - - $builder->setNodeClass('CuStOm', SomeNodeDefinition::class); - - $node1 = $builder->node('', 'CUSTOM'); - $node2 = $builder->node('', 'custom'); - - $this->assertInstanceOf(\get_class($node1), $node2); - } - - public function testNumericNodeCreation() - { - $builder = new BaseNodeBuilder(); - - $node = $builder->integerNode('foo')->min(3)->max(5); - $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition', $node); - - $node = $builder->floatNode('bar')->min(3.0)->max(5.0); - $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\FloatNodeDefinition', $node); - } -} - -class SomeNodeDefinition extends BaseVariableNodeDefinition -{ -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/NumericNodeDefinitionTest.php b/vendor/symfony/config/Tests/Definition/Builder/NumericNodeDefinitionTest.php deleted file mode 100644 index aa938bba..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/NumericNodeDefinitionTest.php +++ /dev/null @@ -1,89 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\FloatNodeDefinition; -use Symfony\Component\Config\Definition\Builder\IntegerNodeDefinition; - -class NumericNodeDefinitionTest extends TestCase -{ - public function testIncoherentMinAssertion() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('You cannot define a min(4) as you already have a max(3)'); - $def = new IntegerNodeDefinition('foo'); - $def->max(3)->min(4); - } - - public function testIncoherentMaxAssertion() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('You cannot define a max(2) as you already have a min(3)'); - $node = new IntegerNodeDefinition('foo'); - $node->min(3)->max(2); - } - - public function testIntegerMinAssertion() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('The value 4 is too small for path "foo". Should be greater than or equal to 5'); - $def = new IntegerNodeDefinition('foo'); - $def->min(5)->getNode()->finalize(4); - } - - public function testIntegerMaxAssertion() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('The value 4 is too big for path "foo". Should be less than or equal to 3'); - $def = new IntegerNodeDefinition('foo'); - $def->max(3)->getNode()->finalize(4); - } - - public function testIntegerValidMinMaxAssertion() - { - $def = new IntegerNodeDefinition('foo'); - $node = $def->min(3)->max(7)->getNode(); - $this->assertEquals(4, $node->finalize(4)); - } - - public function testFloatMinAssertion() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('The value 400 is too small for path "foo". Should be greater than or equal to 500'); - $def = new FloatNodeDefinition('foo'); - $def->min(5E2)->getNode()->finalize(4e2); - } - - public function testFloatMaxAssertion() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('The value 4.3 is too big for path "foo". Should be less than or equal to 0.3'); - $def = new FloatNodeDefinition('foo'); - $def->max(0.3)->getNode()->finalize(4.3); - } - - public function testFloatValidMinMaxAssertion() - { - $def = new FloatNodeDefinition('foo'); - $node = $def->min(3.0)->max(7e2)->getNode(); - $this->assertEquals(4.5, $node->finalize(4.5)); - } - - public function testCannotBeEmptyThrowsAnException() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidDefinitionException'); - $this->expectExceptionMessage('->cannotBeEmpty() is not applicable to NumericNodeDefinition.'); - $def = new IntegerNodeDefinition('foo'); - $def->cannotBeEmpty(); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Builder/TreeBuilderTest.php b/vendor/symfony/config/Tests/Definition/Builder/TreeBuilderTest.php deleted file mode 100644 index 53c9c256..00000000 --- a/vendor/symfony/config/Tests/Definition/Builder/TreeBuilderTest.php +++ /dev/null @@ -1,134 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Builder; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; -use Symfony\Component\Config\Tests\Fixtures\Builder\NodeBuilder as CustomNodeBuilder; - -class TreeBuilderTest extends TestCase -{ - public function testUsingACustomNodeBuilder() - { - $builder = new TreeBuilder(); - $root = $builder->root('custom', 'array', new CustomNodeBuilder()); - - $nodeBuilder = $root->children(); - - $this->assertInstanceOf('Symfony\Component\Config\Tests\Fixtures\Builder\NodeBuilder', $nodeBuilder); - - $nodeBuilder = $nodeBuilder->arrayNode('deeper')->children(); - - $this->assertInstanceOf('Symfony\Component\Config\Tests\Fixtures\Builder\NodeBuilder', $nodeBuilder); - } - - public function testOverrideABuiltInNodeType() - { - $builder = new TreeBuilder(); - $root = $builder->root('override', 'array', new CustomNodeBuilder()); - - $definition = $root->children()->variableNode('variable'); - - $this->assertInstanceOf('Symfony\Component\Config\Tests\Fixtures\Builder\VariableNodeDefinition', $definition); - } - - public function testAddANodeType() - { - $builder = new TreeBuilder(); - $root = $builder->root('override', 'array', new CustomNodeBuilder()); - - $definition = $root->children()->barNode('variable'); - - $this->assertInstanceOf('Symfony\Component\Config\Tests\Fixtures\Builder\BarNodeDefinition', $definition); - } - - public function testCreateABuiltInNodeTypeWithACustomNodeBuilder() - { - $builder = new TreeBuilder(); - $root = $builder->root('builtin', 'array', new CustomNodeBuilder()); - - $definition = $root->children()->booleanNode('boolean'); - - $this->assertInstanceOf('Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition', $definition); - } - - public function testPrototypedArrayNodeUseTheCustomNodeBuilder() - { - $builder = new TreeBuilder(); - $root = $builder->root('override', 'array', new CustomNodeBuilder()); - - $root->prototype('bar')->end(); - - $this->assertInstanceOf('Symfony\Component\Config\Tests\Fixtures\BarNode', $root->getNode(true)->getPrototype()); - } - - public function testAnExtendedNodeBuilderGetsPropagatedToTheChildren() - { - $builder = new TreeBuilder(); - - $builder->root('propagation') - ->children() - ->setNodeClass('extended', 'Symfony\Component\Config\Definition\Builder\BooleanNodeDefinition') - ->node('foo', 'extended')->end() - ->arrayNode('child') - ->children() - ->node('foo', 'extended') - ->end() - ->end() - ->end() - ->end(); - - $node = $builder->buildTree(); - $children = $node->getChildren(); - - $this->assertInstanceOf('Symfony\Component\Config\Definition\BooleanNode', $children['foo']); - - $childChildren = $children['child']->getChildren(); - - $this->assertInstanceOf('Symfony\Component\Config\Definition\BooleanNode', $childChildren['foo']); - } - - public function testDefinitionInfoGetsTransferredToNode() - { - $builder = new TreeBuilder(); - - $builder->root('test')->info('root info') - ->children() - ->node('child', 'variable')->info('child info')->defaultValue('default') - ->end() - ->end(); - - $tree = $builder->buildTree(); - $children = $tree->getChildren(); - - $this->assertEquals('root info', $tree->getInfo()); - $this->assertEquals('child info', $children['child']->getInfo()); - } - - public function testDefinitionExampleGetsTransferredToNode() - { - $builder = new TreeBuilder(); - - $builder->root('test') - ->example(['key' => 'value']) - ->children() - ->node('child', 'variable')->info('child info')->defaultValue('default')->example('example') - ->end() - ->end(); - - $tree = $builder->buildTree(); - $children = $tree->getChildren(); - - $this->assertIsArray($tree->getExample()); - $this->assertEquals('example', $children['child']->getExample()); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/vendor/symfony/config/Tests/Definition/Dumper/XmlReferenceDumperTest.php deleted file mode 100644 index 1bd60215..00000000 --- a/vendor/symfony/config/Tests/Definition/Dumper/XmlReferenceDumperTest.php +++ /dev/null @@ -1,114 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Dumper; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper; -use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration; - -class XmlReferenceDumperTest extends TestCase -{ - public function testDumper() - { - $configuration = new ExampleConfiguration(); - - $dumper = new XmlReferenceDumper(); - $this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration)); - } - - public function testNamespaceDumper() - { - $configuration = new ExampleConfiguration(); - - $dumper = new XmlReferenceDumper(); - $this->assertEquals(str_replace('http://example.org/schema/dic/acme_root', 'http://symfony.com/schema/dic/symfony', $this->getConfigurationAsString()), $dumper->dump($configuration, 'http://symfony.com/schema/dic/symfony')); - } - - private function getConfigurationAsString() - { - return str_replace("\n", \PHP_EOL, <<<'EOL' - - - - - - - - - - - - - - scalar value - - - scalar value - - - - - - - - - - - - - - - - - - - - - - - - -EOL - ); - } -} diff --git a/vendor/symfony/config/Tests/Definition/Dumper/YamlReferenceDumperTest.php b/vendor/symfony/config/Tests/Definition/Dumper/YamlReferenceDumperTest.php deleted file mode 100644 index 3cb9121b..00000000 --- a/vendor/symfony/config/Tests/Definition/Dumper/YamlReferenceDumperTest.php +++ /dev/null @@ -1,143 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition\Dumper; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper; -use Symfony\Component\Config\Tests\Fixtures\Configuration\ExampleConfiguration; - -class YamlReferenceDumperTest extends TestCase -{ - public function testDumper() - { - $configuration = new ExampleConfiguration(); - - $dumper = new YamlReferenceDumper(); - - $this->assertEquals($this->getConfigurationAsString(), $dumper->dump($configuration)); - } - - public function provideDumpAtPath() - { - return [ - 'Regular node' => ['scalar_true', << ['array', << ['array.child2', << ['cms_pages.page', << ['cms_pages.page.locale', <<assertSame(trim($expected), trim($dumper->dumpAtPath($configuration, $path))); - } - - private function getConfigurationAsString() - { - return <<<'EOL' -acme_root: - boolean: true - scalar_empty: ~ - scalar_null: null - scalar_true: true - scalar_false: false - scalar_default: default - scalar_array_empty: [] - scalar_array_defaults: - - # Defaults: - - elem1 - - elem2 - scalar_required: ~ # Required - scalar_deprecated: ~ # Deprecated (The child node "scalar_deprecated" at path "acme_root" is deprecated.) - scalar_deprecated_with_message: ~ # Deprecated (Deprecation custom message for "scalar_deprecated_with_message" at "acme_root") - node_with_a_looong_name: ~ - enum_with_default: this # One of "this"; "that" - enum: ~ # One of "this"; "that" - - # some info - array: - child1: ~ - child2: ~ - - # this is a long - # multi-line info text - # which should be indented - child3: ~ # Example: example setting - scalar_prototyped: [] - parameters: - - # Prototype: Parameter name - name: ~ - connections: - - # Prototype - - - user: ~ - pass: ~ - cms_pages: - - # Prototype - page: - - # Prototype - locale: - title: ~ # Required - path: ~ # Required - pipou: - - # Prototype - name: [] - -EOL; - } -} diff --git a/vendor/symfony/config/Tests/Definition/EnumNodeTest.php b/vendor/symfony/config/Tests/Definition/EnumNodeTest.php deleted file mode 100644 index fa89eea2..00000000 --- a/vendor/symfony/config/Tests/Definition/EnumNodeTest.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\EnumNode; - -class EnumNodeTest extends TestCase -{ - public function testFinalizeValue() - { - $node = new EnumNode('foo', null, ['foo', 'bar']); - $this->assertSame('foo', $node->finalize('foo')); - } - - public function testConstructionWithNoValues() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('$values must contain at least one element.'); - new EnumNode('foo', null, []); - } - - public function testConstructionWithOneValue() - { - $node = new EnumNode('foo', null, ['foo']); - $this->assertSame('foo', $node->finalize('foo')); - } - - public function testConstructionWithOneDistinctValue() - { - $node = new EnumNode('foo', null, ['foo', 'foo']); - $this->assertSame('foo', $node->finalize('foo')); - } - - public function testFinalizeWithInvalidValue() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('The value "foobar" is not allowed for path "foo". Permissible values: "foo", "bar"'); - $node = new EnumNode('foo', null, ['foo', 'bar']); - $node->finalize('foobar'); - } -} diff --git a/vendor/symfony/config/Tests/Definition/FinalizationTest.php b/vendor/symfony/config/Tests/Definition/FinalizationTest.php deleted file mode 100644 index be68a27c..00000000 --- a/vendor/symfony/config/Tests/Definition/FinalizationTest.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; -use Symfony\Component\Config\Definition\NodeInterface; -use Symfony\Component\Config\Definition\Processor; - -class FinalizationTest extends TestCase -{ - public function testUnsetKeyWithDeepHierarchy() - { - $tb = new TreeBuilder(); - $tree = $tb - ->root('config', 'array') - ->children() - ->node('level1', 'array') - ->canBeUnset() - ->children() - ->node('level2', 'array') - ->canBeUnset() - ->children() - ->node('somevalue', 'scalar')->end() - ->node('anothervalue', 'scalar')->end() - ->end() - ->end() - ->node('level1_scalar', 'scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $a = [ - 'level1' => [ - 'level2' => [ - 'somevalue' => 'foo', - 'anothervalue' => 'bar', - ], - 'level1_scalar' => 'foo', - ], - ]; - - $b = [ - 'level1' => [ - 'level2' => false, - ], - ]; - - $this->assertEquals([ - 'level1' => [ - 'level1_scalar' => 'foo', - ], - ], $this->process($tree, [$a, $b])); - } - - protected function process(NodeInterface $tree, array $configs) - { - $processor = new Processor(); - - return $processor->process($tree, $configs); - } -} diff --git a/vendor/symfony/config/Tests/Definition/FloatNodeTest.php b/vendor/symfony/config/Tests/Definition/FloatNodeTest.php deleted file mode 100644 index fed9f013..00000000 --- a/vendor/symfony/config/Tests/Definition/FloatNodeTest.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\FloatNode; - -class FloatNodeTest extends TestCase -{ - /** - * @dataProvider getValidValues - */ - public function testNormalize($value) - { - $node = new FloatNode('test'); - $this->assertSame($value, $node->normalize($value)); - } - - /** - * @dataProvider getValidValues - * - * @param int $value - */ - public function testValidNonEmptyValues($value) - { - $node = new FloatNode('test'); - $node->setAllowEmptyValue(false); - - $this->assertSame($value, $node->finalize($value)); - } - - public function getValidValues() - { - return [ - [1798.0], - [-678.987], - [12.56E45], - [0.0], - // Integer are accepted too, they will be cast - [17], - [-10], - [0], - ]; - } - - /** - * @dataProvider getInvalidValues - */ - public function testNormalizeThrowsExceptionOnInvalidValues($value) - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $node = new FloatNode('test'); - $node->normalize($value); - } - - public function getInvalidValues() - { - return [ - [null], - [''], - ['foo'], - [true], - [false], - [[]], - [['foo' => 'bar']], - [new \stdClass()], - ]; - } -} diff --git a/vendor/symfony/config/Tests/Definition/IntegerNodeTest.php b/vendor/symfony/config/Tests/Definition/IntegerNodeTest.php deleted file mode 100644 index 3fb1b771..00000000 --- a/vendor/symfony/config/Tests/Definition/IntegerNodeTest.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\IntegerNode; - -class IntegerNodeTest extends TestCase -{ - /** - * @dataProvider getValidValues - */ - public function testNormalize($value) - { - $node = new IntegerNode('test'); - $this->assertSame($value, $node->normalize($value)); - } - - /** - * @dataProvider getValidValues - * - * @param int $value - */ - public function testValidNonEmptyValues($value) - { - $node = new IntegerNode('test'); - $node->setAllowEmptyValue(false); - - $this->assertSame($value, $node->finalize($value)); - } - - public function getValidValues() - { - return [ - [1798], - [-678], - [0], - ]; - } - - /** - * @dataProvider getInvalidValues - */ - public function testNormalizeThrowsExceptionOnInvalidValues($value) - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $node = new IntegerNode('test'); - $node->normalize($value); - } - - public function getInvalidValues() - { - return [ - [null], - [''], - ['foo'], - [true], - [false], - [0.0], - [0.1], - [[]], - [['foo' => 'bar']], - [new \stdClass()], - ]; - } -} diff --git a/vendor/symfony/config/Tests/Definition/MergeTest.php b/vendor/symfony/config/Tests/Definition/MergeTest.php deleted file mode 100644 index 8fee2635..00000000 --- a/vendor/symfony/config/Tests/Definition/MergeTest.php +++ /dev/null @@ -1,192 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; - -class MergeTest extends TestCase -{ - public function testForbiddenOverwrite() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException'); - $tb = new TreeBuilder(); - $tree = $tb - ->root('root', 'array') - ->children() - ->node('foo', 'scalar') - ->cannotBeOverwritten() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $a = [ - 'foo' => 'bar', - ]; - - $b = [ - 'foo' => 'moo', - ]; - - $tree->merge($a, $b); - } - - public function testUnsetKey() - { - $tb = new TreeBuilder(); - $tree = $tb - ->root('root', 'array') - ->children() - ->node('foo', 'scalar')->end() - ->node('bar', 'scalar')->end() - ->node('unsettable', 'array') - ->canBeUnset() - ->children() - ->node('foo', 'scalar')->end() - ->node('bar', 'scalar')->end() - ->end() - ->end() - ->node('unsetted', 'array') - ->canBeUnset() - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $a = [ - 'foo' => 'bar', - 'unsettable' => [ - 'foo' => 'a', - 'bar' => 'b', - ], - 'unsetted' => false, - ]; - - $b = [ - 'foo' => 'moo', - 'bar' => 'b', - 'unsettable' => false, - 'unsetted' => ['a', 'b'], - ]; - - $this->assertEquals([ - 'foo' => 'moo', - 'bar' => 'b', - 'unsettable' => false, - 'unsetted' => ['a', 'b'], - ], $tree->merge($a, $b)); - } - - public function testDoesNotAllowNewKeysInSubsequentConfigs() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $tb = new TreeBuilder(); - $tree = $tb - ->root('config', 'array') - ->children() - ->node('test', 'array') - ->disallowNewKeysInSubsequentConfigs() - ->useAttributeAsKey('key') - ->prototype('array') - ->children() - ->node('value', 'scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->buildTree(); - - $a = [ - 'test' => [ - 'a' => ['value' => 'foo'], - ], - ]; - - $b = [ - 'test' => [ - 'b' => ['value' => 'foo'], - ], - ]; - - $tree->merge($a, $b); - } - - public function testPerformsNoDeepMerging() - { - $tb = new TreeBuilder(); - - $tree = $tb - ->root('config', 'array') - ->children() - ->node('no_deep_merging', 'array') - ->performNoDeepMerging() - ->children() - ->node('foo', 'scalar')->end() - ->node('bar', 'scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $a = [ - 'no_deep_merging' => [ - 'foo' => 'a', - 'bar' => 'b', - ], - ]; - - $b = [ - 'no_deep_merging' => [ - 'c' => 'd', - ], - ]; - - $this->assertEquals([ - 'no_deep_merging' => [ - 'c' => 'd', - ], - ], $tree->merge($a, $b)); - } - - public function testPrototypeWithoutAKeyAttribute() - { - $tb = new TreeBuilder(); - - $tree = $tb - ->root('config', 'array') - ->children() - ->arrayNode('append_elements') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $a = [ - 'append_elements' => ['a', 'b'], - ]; - - $b = [ - 'append_elements' => ['c', 'd'], - ]; - - $this->assertEquals(['append_elements' => ['a', 'b', 'c', 'd']], $tree->merge($a, $b)); - } -} diff --git a/vendor/symfony/config/Tests/Definition/NormalizationTest.php b/vendor/symfony/config/Tests/Definition/NormalizationTest.php deleted file mode 100644 index 200a9859..00000000 --- a/vendor/symfony/config/Tests/Definition/NormalizationTest.php +++ /dev/null @@ -1,228 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; -use Symfony\Component\Config\Definition\NodeInterface; - -class NormalizationTest extends TestCase -{ - /** - * @dataProvider getEncoderTests - */ - public function testNormalizeEncoders($denormalized) - { - $tb = new TreeBuilder(); - $tree = $tb - ->root('root_name', 'array') - ->fixXmlConfig('encoder') - ->children() - ->node('encoders', 'array') - ->useAttributeAsKey('class') - ->prototype('array') - ->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end() - ->children() - ->node('algorithm', 'scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $normalized = [ - 'encoders' => [ - 'foo' => ['algorithm' => 'plaintext'], - ], - ]; - - $this->assertNormalized($tree, $denormalized, $normalized); - } - - public function getEncoderTests() - { - $configs = []; - - // XML - $configs[] = [ - 'encoder' => [ - ['class' => 'foo', 'algorithm' => 'plaintext'], - ], - ]; - - // XML when only one element of this type - $configs[] = [ - 'encoder' => ['class' => 'foo', 'algorithm' => 'plaintext'], - ]; - - // YAML/PHP - $configs[] = [ - 'encoders' => [ - ['class' => 'foo', 'algorithm' => 'plaintext'], - ], - ]; - - // YAML/PHP - $configs[] = [ - 'encoders' => [ - 'foo' => 'plaintext', - ], - ]; - - // YAML/PHP - $configs[] = [ - 'encoders' => [ - 'foo' => ['algorithm' => 'plaintext'], - ], - ]; - - return array_map(function ($v) { - return [$v]; - }, $configs); - } - - /** - * @dataProvider getAnonymousKeysTests - */ - public function testAnonymousKeysArray($denormalized) - { - $tb = new TreeBuilder(); - $tree = $tb - ->root('root', 'array') - ->children() - ->node('logout', 'array') - ->fixXmlConfig('handler') - ->children() - ->node('handlers', 'array') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $normalized = ['logout' => ['handlers' => ['a', 'b', 'c']]]; - - $this->assertNormalized($tree, $denormalized, $normalized); - } - - public function getAnonymousKeysTests() - { - $configs = []; - - $configs[] = [ - 'logout' => [ - 'handlers' => ['a', 'b', 'c'], - ], - ]; - - $configs[] = [ - 'logout' => [ - 'handler' => ['a', 'b', 'c'], - ], - ]; - - return array_map(function ($v) { return [$v]; }, $configs); - } - - /** - * @dataProvider getNumericKeysTests - */ - public function testNumericKeysAsAttributes($denormalized) - { - $normalized = [ - 'thing' => [42 => ['foo', 'bar'], 1337 => ['baz', 'qux']], - ]; - - $this->assertNormalized($this->getNumericKeysTestTree(), $denormalized, $normalized); - } - - public function getNumericKeysTests() - { - $configs = []; - - $configs[] = [ - 'thing' => [ - 42 => ['foo', 'bar'], 1337 => ['baz', 'qux'], - ], - ]; - - $configs[] = [ - 'thing' => [ - ['foo', 'bar', 'id' => 42], ['baz', 'qux', 'id' => 1337], - ], - ]; - - return array_map(function ($v) { return [$v]; }, $configs); - } - - public function testNonAssociativeArrayThrowsExceptionIfAttributeNotSet() - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $this->expectExceptionMessage('The attribute "id" must be set for path "root.thing".'); - $denormalized = [ - 'thing' => [ - ['foo', 'bar'], ['baz', 'qux'], - ], - ]; - - $this->assertNormalized($this->getNumericKeysTestTree(), $denormalized, []); - } - - public function testAssociativeArrayPreserveKeys() - { - $tb = new TreeBuilder(); - $tree = $tb - ->root('root', 'array') - ->prototype('array') - ->children() - ->node('foo', 'scalar')->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - $data = ['first' => ['foo' => 'bar']]; - - $this->assertNormalized($tree, $data, $data); - } - - public static function assertNormalized(NodeInterface $tree, $denormalized, $normalized) - { - self::assertSame($normalized, $tree->normalize($denormalized)); - } - - private function getNumericKeysTestTree() - { - $tb = new TreeBuilder(); - $tree = $tb - ->root('root', 'array') - ->children() - ->node('thing', 'array') - ->useAttributeAsKey('id') - ->prototype('array') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->buildTree() - ; - - return $tree; - } -} diff --git a/vendor/symfony/config/Tests/Definition/PrototypedArrayNodeTest.php b/vendor/symfony/config/Tests/Definition/PrototypedArrayNodeTest.php deleted file mode 100644 index 7a58ead8..00000000 --- a/vendor/symfony/config/Tests/Definition/PrototypedArrayNodeTest.php +++ /dev/null @@ -1,341 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\ArrayNode; -use Symfony\Component\Config\Definition\PrototypedArrayNode; -use Symfony\Component\Config\Definition\ScalarNode; -use Symfony\Component\Config\Definition\VariableNode; - -class PrototypedArrayNodeTest extends TestCase -{ - public function testGetDefaultValueReturnsAnEmptyArrayForPrototypes() - { - $node = new PrototypedArrayNode('root'); - $prototype = new ArrayNode(null, $node); - $node->setPrototype($prototype); - $this->assertEmpty($node->getDefaultValue()); - } - - public function testGetDefaultValueReturnsDefaultValueForPrototypes() - { - $node = new PrototypedArrayNode('root'); - $prototype = new ArrayNode(null, $node); - $node->setPrototype($prototype); - $node->setDefaultValue(['test']); - $this->assertEquals(['test'], $node->getDefaultValue()); - } - - // a remapped key (e.g. "mapping" -> "mappings") should be unset after being used - public function testRemappedKeysAreUnset() - { - $node = new ArrayNode('root'); - $mappingsNode = new PrototypedArrayNode('mappings'); - $node->addChild($mappingsNode); - - // each item under mappings is just a scalar - $prototype = new ScalarNode(null, $mappingsNode); - $mappingsNode->setPrototype($prototype); - - $remappings = []; - $remappings[] = ['mapping', 'mappings']; - $node->setXmlRemappings($remappings); - - $normalized = $node->normalize(['mapping' => ['foo', 'bar']]); - $this->assertEquals(['mappings' => ['foo', 'bar']], $normalized); - } - - /** - * Tests that when a key attribute is mapped, that key is removed from the array. - * - * - * - * - * The above should finally be mapped to an array that looks like this - * (because "id" is the key attribute). - * - * [ - * 'things' => [ - * 'option1' => 'foo', - * 'option2' => 'bar', - * ] - * ] - */ - public function testMappedAttributeKeyIsRemoved() - { - $node = new PrototypedArrayNode('root'); - $node->setKeyAttribute('id', true); - - // each item under the root is an array, with one scalar item - $prototype = new ArrayNode(null, $node); - $prototype->addChild(new ScalarNode('foo')); - $node->setPrototype($prototype); - - $children = []; - $children[] = ['id' => 'item_name', 'foo' => 'bar']; - $normalized = $node->normalize($children); - - $expected = []; - $expected['item_name'] = ['foo' => 'bar']; - $this->assertEquals($expected, $normalized); - } - - /** - * Tests the opposite of the testMappedAttributeKeyIsRemoved because - * the removal can be toggled with an option. - */ - public function testMappedAttributeKeyNotRemoved() - { - $node = new PrototypedArrayNode('root'); - $node->setKeyAttribute('id', false); - - // each item under the root is an array, with two scalar items - $prototype = new ArrayNode(null, $node); - $prototype->addChild(new ScalarNode('foo')); - $prototype->addChild(new ScalarNode('id')); // the key attribute will remain - $node->setPrototype($prototype); - - $children = []; - $children[] = ['id' => 'item_name', 'foo' => 'bar']; - $normalized = $node->normalize($children); - - $expected = []; - $expected['item_name'] = ['id' => 'item_name', 'foo' => 'bar']; - $this->assertEquals($expected, $normalized); - } - - public function testAddDefaultChildren() - { - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setAddChildrenIfNoneSet(); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals([['foo' => 'bar']], $node->getDefaultValue()); - - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setKeyAttribute('foobar'); - $node->setAddChildrenIfNoneSet(); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals(['defaults' => ['foo' => 'bar']], $node->getDefaultValue()); - - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setKeyAttribute('foobar'); - $node->setAddChildrenIfNoneSet('defaultkey'); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals(['defaultkey' => ['foo' => 'bar']], $node->getDefaultValue()); - - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setKeyAttribute('foobar'); - $node->setAddChildrenIfNoneSet(['defaultkey']); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals(['defaultkey' => ['foo' => 'bar']], $node->getDefaultValue()); - - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setKeyAttribute('foobar'); - $node->setAddChildrenIfNoneSet(['dk1', 'dk2']); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals(['dk1' => ['foo' => 'bar'], 'dk2' => ['foo' => 'bar']], $node->getDefaultValue()); - - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setAddChildrenIfNoneSet([5, 6]); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals([0 => ['foo' => 'bar'], 1 => ['foo' => 'bar']], $node->getDefaultValue()); - - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setAddChildrenIfNoneSet(2); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals([['foo' => 'bar'], ['foo' => 'bar']], $node->getDefaultValue()); - } - - public function testDefaultChildrenWinsOverDefaultValue() - { - $node = $this->getPrototypeNodeWithDefaultChildren(); - $node->setAddChildrenIfNoneSet(); - $node->setDefaultValue(['bar' => 'foo']); - $this->assertTrue($node->hasDefaultValue()); - $this->assertEquals([['foo' => 'bar']], $node->getDefaultValue()); - } - - protected function getPrototypeNodeWithDefaultChildren() - { - $node = new PrototypedArrayNode('root'); - $prototype = new ArrayNode(null, $node); - $child = new ScalarNode('foo'); - $child->setDefaultValue('bar'); - $prototype->addChild($child); - $prototype->setAddIfNotSet(true); - $node->setPrototype($prototype); - - return $node; - } - - /** - * Tests that when a key attribute is mapped, that key is removed from the array. - * And if only 'value' element is left in the array, it will replace its wrapper array. - * - * - * - * - * The above should finally be mapped to an array that looks like this - * (because "id" is the key attribute). - * - * [ - * 'things' => [ - * 'option1' => 'value1' - * ] - * ] - * - * It's also possible to mix 'value-only' and 'non-value-only' elements in the array. - * - * - * - * - * The above should finally be mapped to an array as follows - * - * [ - * 'things' => [ - * 'option1' => 'value1', - * 'option2' => [ - * 'value' => 'value2', - * 'foo' => 'foo2' - * ] - * ] - * ] - * - * The 'value' element can also be ArrayNode: - * - * - * - * - * - * The above should be finally be mapped to an array as follows - * - * [ - * 'things' => [ - * 'option1' => [ - * 'foo' => 'foo1', - * 'bar' => 'bar1' - * ] - * ] - * ] - * - * If using VariableNode for value node, it's also possible to mix different types of value nodes: - * - * - * - * - * - * The above should be finally mapped to an array as follows - * - * [ - * 'things' => [ - * 'option1' => [ - * 'foo' => 'foo1', - * 'bar' => 'bar1' - * ], - * 'option2' => 'value2' - * ] - * ] - * - * @dataProvider getDataForKeyRemovedLeftValueOnly - */ - public function testMappedAttributeKeyIsRemovedLeftValueOnly($value, $children, $expected) - { - $node = new PrototypedArrayNode('root'); - $node->setKeyAttribute('id', true); - - // each item under the root is an array, with one scalar item - $prototype = new ArrayNode(null, $node); - $prototype->addChild(new ScalarNode('id')); - $prototype->addChild(new ScalarNode('foo')); - $prototype->addChild($value); - $node->setPrototype($prototype); - - $normalized = $node->normalize($children); - $this->assertEquals($expected, $normalized); - } - - public function getDataForKeyRemovedLeftValueOnly() - { - $scalarValue = new ScalarNode('value'); - - $arrayValue = new ArrayNode('value'); - $arrayValue->addChild(new ScalarNode('foo')); - $arrayValue->addChild(new ScalarNode('bar')); - - $variableValue = new VariableNode('value'); - - return [ - [ - $scalarValue, - [ - ['id' => 'option1', 'value' => 'value1'], - ], - ['option1' => 'value1'], - ], - - [ - $scalarValue, - [ - ['id' => 'option1', 'value' => 'value1'], - ['id' => 'option2', 'value' => 'value2', 'foo' => 'foo2'], - ], - [ - 'option1' => 'value1', - 'option2' => ['value' => 'value2', 'foo' => 'foo2'], - ], - ], - - [ - $arrayValue, - [ - [ - 'id' => 'option1', - 'value' => ['foo' => 'foo1', 'bar' => 'bar1'], - ], - ], - [ - 'option1' => ['foo' => 'foo1', 'bar' => 'bar1'], - ], - ], - - [$variableValue, - [ - [ - 'id' => 'option1', 'value' => ['foo' => 'foo1', 'bar' => 'bar1'], - ], - ['id' => 'option2', 'value' => 'value2'], - ], - [ - 'option1' => ['foo' => 'foo1', 'bar' => 'bar1'], - 'option2' => 'value2', - ], - ], - ]; - } -} diff --git a/vendor/symfony/config/Tests/Definition/ScalarNodeTest.php b/vendor/symfony/config/Tests/Definition/ScalarNodeTest.php deleted file mode 100644 index ac2d9376..00000000 --- a/vendor/symfony/config/Tests/Definition/ScalarNodeTest.php +++ /dev/null @@ -1,161 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Definition; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\ArrayNode; -use Symfony\Component\Config\Definition\ScalarNode; - -class ScalarNodeTest extends TestCase -{ - /** - * @dataProvider getValidValues - */ - public function testNormalize($value) - { - $node = new ScalarNode('test'); - $this->assertSame($value, $node->normalize($value)); - } - - public function getValidValues() - { - return [ - [false], - [true], - [null], - [''], - ['foo'], - [0], - [1], - [0.0], - [0.1], - ]; - } - - public function testSetDeprecated() - { - $childNode = new ScalarNode('foo'); - $childNode->setDeprecated('"%node%" is deprecated'); - - $this->assertTrue($childNode->isDeprecated()); - $this->assertSame('"foo" is deprecated', $childNode->getDeprecationMessage($childNode->getName(), $childNode->getPath())); - - $node = new ArrayNode('root'); - $node->addChild($childNode); - - $deprecationTriggered = 0; - $deprecationHandler = function ($level, $message, $file, $line) use (&$prevErrorHandler, &$deprecationTriggered) { - if (\E_USER_DEPRECATED === $level) { - return ++$deprecationTriggered; - } - - return $prevErrorHandler ? $prevErrorHandler($level, $message, $file, $line) : false; - }; - - $prevErrorHandler = set_error_handler($deprecationHandler); - $node->finalize([]); - restore_error_handler(); - $this->assertSame(0, $deprecationTriggered, '->finalize() should not trigger if the deprecated node is not set'); - - $prevErrorHandler = set_error_handler($deprecationHandler); - $node->finalize(['foo' => '']); - restore_error_handler(); - $this->assertSame(1, $deprecationTriggered, '->finalize() should trigger if the deprecated node is set'); - } - - /** - * @dataProvider getInvalidValues - */ - public function testNormalizeThrowsExceptionOnInvalidValues($value) - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $node = new ScalarNode('test'); - $node->normalize($value); - } - - public function getInvalidValues() - { - return [ - [[]], - [['foo' => 'bar']], - [new \stdClass()], - ]; - } - - public function testNormalizeThrowsExceptionWithoutHint() - { - $node = new ScalarNode('test'); - - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $this->expectExceptionMessage('Invalid type for path "test". Expected scalar, but got array.'); - - $node->normalize([]); - } - - public function testNormalizeThrowsExceptionWithErrorMessage() - { - $node = new ScalarNode('test'); - $node->setInfo('"the test value"'); - - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidTypeException'); - $this->expectExceptionMessage("Invalid type for path \"test\". Expected scalar, but got array.\nHint: \"the test value\""); - - $node->normalize([]); - } - - /** - * @dataProvider getValidNonEmptyValues - * - * @param mixed $value - */ - public function testValidNonEmptyValues($value) - { - $node = new ScalarNode('test'); - $node->setAllowEmptyValue(false); - - $this->assertSame($value, $node->finalize($value)); - } - - public function getValidNonEmptyValues() - { - return [ - [false], - [true], - ['foo'], - [0], - [1], - [0.0], - [0.1], - ]; - } - - /** - * @dataProvider getEmptyValues - * - * @param mixed $value - */ - public function testNotAllowedEmptyValuesThrowException($value) - { - $this->expectException('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException'); - $node = new ScalarNode('test'); - $node->setAllowEmptyValue(false); - $node->finalize($value); - } - - public function getEmptyValues() - { - return [ - [null], - [''], - ]; - } -} diff --git a/vendor/symfony/config/Tests/DependencyInjection/ConfigCachePassTest.php b/vendor/symfony/config/Tests/DependencyInjection/ConfigCachePassTest.php deleted file mode 100644 index c2b95195..00000000 --- a/vendor/symfony/config/Tests/DependencyInjection/ConfigCachePassTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\DependencyInjection; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\DependencyInjection\ConfigCachePass; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; - -/** - * @group legacy - */ -class ConfigCachePassTest extends TestCase -{ - public function testThatCheckersAreProcessedInPriorityOrder() - { - $container = new ContainerBuilder(); - - $definition = $container->register('config_cache_factory')->addArgument(null); - $container->register('checker_2')->addTag('config_cache.resource_checker', ['priority' => 100]); - $container->register('checker_1')->addTag('config_cache.resource_checker', ['priority' => 200]); - $container->register('checker_3')->addTag('config_cache.resource_checker'); - - $pass = new ConfigCachePass(); - $pass->process($container); - - $expected = new IteratorArgument([ - new Reference('checker_1'), - new Reference('checker_2'), - new Reference('checker_3'), - ]); - $this->assertEquals($expected, $definition->getArgument(0)); - } - - public function testThatCheckersCanBeMissing() - { - $container = new ContainerBuilder(); - - $definitionsBefore = \count($container->getDefinitions()); - $aliasesBefore = \count($container->getAliases()); - - $pass = new ConfigCachePass(); - $pass->process($container); - - // the container is untouched (i.e. no new definitions or aliases) - $this->assertCount($definitionsBefore, $container->getDefinitions()); - $this->assertCount($aliasesBefore, $container->getAliases()); - } -} diff --git a/vendor/symfony/config/Tests/Exception/FileLoaderLoadExceptionTest.php b/vendor/symfony/config/Tests/Exception/FileLoaderLoadExceptionTest.php deleted file mode 100644 index 8363084c..00000000 --- a/vendor/symfony/config/Tests/Exception/FileLoaderLoadExceptionTest.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Exception; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Exception\FileLoaderLoadException; - -class FileLoaderLoadExceptionTest extends TestCase -{ - public function testMessageCannotLoadResource() - { - $exception = new FileLoaderLoadException('resource', null); - $this->assertEquals('Cannot load resource "resource".', $exception->getMessage()); - } - - public function testMessageCannotLoadResourceWithType() - { - $exception = new FileLoaderLoadException('resource', null, null, null, 'foobar'); - $this->assertEquals('Cannot load resource "resource". Make sure there is a loader supporting the "foobar" type.', $exception->getMessage()); - } - - public function testMessageCannotLoadResourceWithAnnotationType() - { - $exception = new FileLoaderLoadException('resource', null, null, null, 'annotation'); - $this->assertEquals('Cannot load resource "resource". Make sure annotations are installed and enabled.', $exception->getMessage()); - } - - public function testMessageCannotImportResourceFromSource() - { - $exception = new FileLoaderLoadException('resource', 'sourceResource'); - $this->assertEquals('Cannot import resource "resource" from "sourceResource".', $exception->getMessage()); - } - - public function testMessageCannotImportBundleResource() - { - $exception = new FileLoaderLoadException('@resource', 'sourceResource'); - $this->assertEquals( - 'Cannot import resource "@resource" from "sourceResource". '. - 'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class. '. - 'If the bundle is registered, make sure the bundle path "@resource" is not empty.', - $exception->getMessage() - ); - } - - public function testMessageHasPreviousErrorWithDotAndUnableToLoad() - { - $exception = new FileLoaderLoadException( - 'resource', - null, - null, - new \Exception('There was a previous error with an ending dot.') - ); - $this->assertEquals( - 'There was a previous error with an ending dot in resource (which is loaded in resource "resource").', - $exception->getMessage() - ); - } - - public function testMessageHasPreviousErrorWithoutDotAndUnableToLoad() - { - $exception = new FileLoaderLoadException( - 'resource', - null, - null, - new \Exception('There was a previous error with no ending dot') - ); - $this->assertEquals( - 'There was a previous error with no ending dot in resource (which is loaded in resource "resource").', - $exception->getMessage() - ); - } - - public function testMessageHasPreviousErrorAndUnableToLoadBundle() - { - $exception = new FileLoaderLoadException( - '@resource', - null, - null, - new \Exception('There was a previous error with an ending dot.') - ); - $this->assertEquals( - 'There was a previous error with an ending dot in @resource '. - '(which is loaded in resource "@resource"). '. - 'Make sure the "resource" bundle is correctly registered and loaded in the application kernel class. '. - 'If the bundle is registered, make sure the bundle path "@resource" is not empty.', - $exception->getMessage() - ); - } -} diff --git a/vendor/symfony/config/Tests/FileLocatorTest.php b/vendor/symfony/config/Tests/FileLocatorTest.php deleted file mode 100644 index e931916a..00000000 --- a/vendor/symfony/config/Tests/FileLocatorTest.php +++ /dev/null @@ -1,114 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; - -class FileLocatorTest extends TestCase -{ - /** - * @dataProvider getIsAbsolutePathTests - */ - public function testIsAbsolutePath($path) - { - $loader = new FileLocator([]); - $r = new \ReflectionObject($loader); - $m = $r->getMethod('isAbsolutePath'); - $m->setAccessible(true); - - $this->assertTrue($m->invoke($loader, $path), '->isAbsolutePath() returns true for an absolute path'); - } - - public function getIsAbsolutePathTests() - { - return [ - ['/foo.xml'], - ['c:\\\\foo.xml'], - ['c:/foo.xml'], - ['\\server\\foo.xml'], - ['https://server/foo.xml'], - ['phar://server/foo.xml'], - ]; - } - - public function testLocate() - { - $loader = new FileLocator(__DIR__.'/Fixtures'); - - $this->assertEquals( - __DIR__.\DIRECTORY_SEPARATOR.'FileLocatorTest.php', - $loader->locate('FileLocatorTest.php', __DIR__), - '->locate() returns the absolute filename if the file exists in the given path' - ); - - $this->assertEquals( - __DIR__.'/Fixtures'.\DIRECTORY_SEPARATOR.'foo.xml', - $loader->locate('foo.xml', __DIR__), - '->locate() returns the absolute filename if the file exists in one of the paths given in the constructor' - ); - - $this->assertEquals( - __DIR__.'/Fixtures'.\DIRECTORY_SEPARATOR.'foo.xml', - $loader->locate(__DIR__.'/Fixtures'.\DIRECTORY_SEPARATOR.'foo.xml', __DIR__), - '->locate() returns the absolute filename if the file exists in one of the paths given in the constructor' - ); - - $loader = new FileLocator([__DIR__.'/Fixtures', __DIR__.'/Fixtures/Again']); - - $this->assertEquals( - [__DIR__.'/Fixtures'.\DIRECTORY_SEPARATOR.'foo.xml', __DIR__.'/Fixtures/Again'.\DIRECTORY_SEPARATOR.'foo.xml'], - $loader->locate('foo.xml', __DIR__, false), - '->locate() returns an array of absolute filenames' - ); - - $this->assertEquals( - [__DIR__.'/Fixtures'.\DIRECTORY_SEPARATOR.'foo.xml', __DIR__.'/Fixtures/Again'.\DIRECTORY_SEPARATOR.'foo.xml'], - $loader->locate('foo.xml', __DIR__.'/Fixtures', false), - '->locate() returns an array of absolute filenames' - ); - - $loader = new FileLocator(__DIR__.'/Fixtures/Again'); - - $this->assertEquals( - [__DIR__.'/Fixtures'.\DIRECTORY_SEPARATOR.'foo.xml', __DIR__.'/Fixtures/Again'.\DIRECTORY_SEPARATOR.'foo.xml'], - $loader->locate('foo.xml', __DIR__.'/Fixtures', false), - '->locate() returns an array of absolute filenames' - ); - } - - public function testLocateThrowsAnExceptionIfTheFileDoesNotExists() - { - $this->expectException('Symfony\Component\Config\Exception\FileLocatorFileNotFoundException'); - $this->expectExceptionMessage('The file "foobar.xml" does not exist'); - $loader = new FileLocator([__DIR__.'/Fixtures']); - - $loader->locate('foobar.xml', __DIR__); - } - - public function testLocateThrowsAnExceptionIfTheFileDoesNotExistsInAbsolutePath() - { - $this->expectException('Symfony\Component\Config\Exception\FileLocatorFileNotFoundException'); - $loader = new FileLocator([__DIR__.'/Fixtures']); - - $loader->locate(__DIR__.'/Fixtures/foobar.xml', __DIR__); - } - - public function testLocateEmpty() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('An empty file name is not valid to be located.'); - $loader = new FileLocator([__DIR__.'/Fixtures']); - - $loader->locate(null, __DIR__); - } -} diff --git a/vendor/symfony/config/Tests/Fixtures/Again/foo.xml b/vendor/symfony/config/Tests/Fixtures/Again/foo.xml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/symfony/config/Tests/Fixtures/BadFileName.php b/vendor/symfony/config/Tests/Fixtures/BadFileName.php deleted file mode 100644 index 0f79bdd5..00000000 --- a/vendor/symfony/config/Tests/Fixtures/BadFileName.php +++ /dev/null @@ -1,9 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Fixtures; - -use Symfony\Component\Config\Definition\ArrayNode; - -class BarNode extends ArrayNode -{ -} diff --git a/vendor/symfony/config/Tests/Fixtures/Builder/BarNodeDefinition.php b/vendor/symfony/config/Tests/Fixtures/Builder/BarNodeDefinition.php deleted file mode 100644 index b9c62e53..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Builder/BarNodeDefinition.php +++ /dev/null @@ -1,23 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Fixtures\Builder; - -use Symfony\Component\Config\Definition\Builder\NodeDefinition; -use Symfony\Component\Config\Tests\Fixtures\BarNode; - -class BarNodeDefinition extends NodeDefinition -{ - protected function createNode() - { - return new BarNode($this->name); - } -} diff --git a/vendor/symfony/config/Tests/Fixtures/Builder/NodeBuilder.php b/vendor/symfony/config/Tests/Fixtures/Builder/NodeBuilder.php deleted file mode 100644 index 22b8b32f..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Builder/NodeBuilder.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Fixtures\Builder; - -use Symfony\Component\Config\Definition\Builder\NodeBuilder as BaseNodeBuilder; - -class NodeBuilder extends BaseNodeBuilder -{ - public function barNode($name) - { - return $this->node($name, 'bar'); - } - - protected function getNodeClass($type) - { - switch ($type) { - case 'variable': - return __NAMESPACE__.'\\'.ucfirst($type).'NodeDefinition'; - case 'bar': - return __NAMESPACE__.'\\'.ucfirst($type).'NodeDefinition'; - default: - return parent::getNodeClass($type); - } - } -} diff --git a/vendor/symfony/config/Tests/Fixtures/Builder/VariableNodeDefinition.php b/vendor/symfony/config/Tests/Fixtures/Builder/VariableNodeDefinition.php deleted file mode 100644 index 6126ed43..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Builder/VariableNodeDefinition.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Fixtures\Builder; - -use Symfony\Component\Config\Definition\Builder\VariableNodeDefinition as BaseVariableNodeDefinition; - -class VariableNodeDefinition extends BaseVariableNodeDefinition -{ -} diff --git a/vendor/symfony/config/Tests/Fixtures/Configuration/ExampleConfiguration.php b/vendor/symfony/config/Tests/Fixtures/Configuration/ExampleConfiguration.php deleted file mode 100644 index 3f02700a..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Configuration/ExampleConfiguration.php +++ /dev/null @@ -1,102 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Fixtures\Configuration; - -use Symfony\Component\Config\Definition\Builder\TreeBuilder; -use Symfony\Component\Config\Definition\ConfigurationInterface; - -class ExampleConfiguration implements ConfigurationInterface -{ - public function getConfigTreeBuilder() - { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('acme_root'); - - $rootNode - ->fixXmlConfig('parameter') - ->fixXmlConfig('connection') - ->fixXmlConfig('cms_page') - ->children() - ->booleanNode('boolean')->defaultTrue()->end() - ->scalarNode('scalar_empty')->end() - ->scalarNode('scalar_null')->defaultNull()->end() - ->scalarNode('scalar_true')->defaultTrue()->end() - ->scalarNode('scalar_false')->defaultFalse()->end() - ->scalarNode('scalar_default')->defaultValue('default')->end() - ->scalarNode('scalar_array_empty')->defaultValue([])->end() - ->scalarNode('scalar_array_defaults')->defaultValue(['elem1', 'elem2'])->end() - ->scalarNode('scalar_required')->isRequired()->end() - ->scalarNode('scalar_deprecated')->setDeprecated()->end() - ->scalarNode('scalar_deprecated_with_message')->setDeprecated('Deprecation custom message for "%node%" at "%path%"')->end() - ->scalarNode('node_with_a_looong_name')->end() - ->enumNode('enum_with_default')->values(['this', 'that'])->defaultValue('this')->end() - ->enumNode('enum')->values(['this', 'that'])->end() - ->arrayNode('array') - ->info('some info') - ->canBeUnset() - ->children() - ->scalarNode('child1')->end() - ->scalarNode('child2')->end() - ->scalarNode('child3') - ->info( - "this is a long\n". - "multi-line info text\n". - 'which should be indented' - ) - ->example('example setting') - ->end() - ->end() - ->end() - ->arrayNode('scalar_prototyped') - ->prototype('scalar')->end() - ->end() - ->arrayNode('parameters') - ->useAttributeAsKey('name') - ->prototype('scalar')->info('Parameter name')->end() - ->end() - ->arrayNode('connections') - ->prototype('array') - ->children() - ->scalarNode('user')->end() - ->scalarNode('pass')->end() - ->end() - ->end() - ->end() - ->arrayNode('cms_pages') - ->useAttributeAsKey('page') - ->prototype('array') - ->useAttributeAsKey('locale') - ->prototype('array') - ->children() - ->scalarNode('title')->isRequired()->end() - ->scalarNode('path')->isRequired()->end() - ->end() - ->end() - ->end() - ->end() - ->arrayNode('pipou') - ->useAttributeAsKey('name') - ->prototype('array') - ->prototype('array') - ->children() - ->scalarNode('didou') - ->end() - ->end() - ->end() - ->end() - ->end() - ->end() - ; - - return $treeBuilder; - } -} diff --git a/vendor/symfony/config/Tests/Fixtures/ParseError.php b/vendor/symfony/config/Tests/Fixtures/ParseError.php deleted file mode 100644 index 6bb22138..00000000 --- a/vendor/symfony/config/Tests/Fixtures/ParseError.php +++ /dev/null @@ -1,7 +0,0 @@ - -]> - diff --git a/vendor/symfony/config/Tests/Fixtures/Util/invalid.xml b/vendor/symfony/config/Tests/Fixtures/Util/invalid.xml deleted file mode 100644 index a07af9fd..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Util/invalid.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/vendor/symfony/config/Tests/Fixtures/Util/invalid_schema.xml b/vendor/symfony/config/Tests/Fixtures/Util/invalid_schema.xml deleted file mode 100644 index e2725a2c..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Util/invalid_schema.xml +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/vendor/symfony/config/Tests/Fixtures/Util/not_readable.xml b/vendor/symfony/config/Tests/Fixtures/Util/not_readable.xml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/symfony/config/Tests/Fixtures/Util/schema.xsd b/vendor/symfony/config/Tests/Fixtures/Util/schema.xsd deleted file mode 100644 index e56820f6..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Util/schema.xsd +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/vendor/symfony/config/Tests/Fixtures/Util/valid.xml b/vendor/symfony/config/Tests/Fixtures/Util/valid.xml deleted file mode 100644 index a96bb382..00000000 --- a/vendor/symfony/config/Tests/Fixtures/Util/valid.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/vendor/symfony/config/Tests/Fixtures/foo.xml b/vendor/symfony/config/Tests/Fixtures/foo.xml deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/symfony/config/Tests/Loader/DelegatingLoaderTest.php b/vendor/symfony/config/Tests/Loader/DelegatingLoaderTest.php deleted file mode 100644 index 38ae6ff7..00000000 --- a/vendor/symfony/config/Tests/Loader/DelegatingLoaderTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Loader\DelegatingLoader; -use Symfony\Component\Config\Loader\LoaderResolver; - -class DelegatingLoaderTest extends TestCase -{ - public function testConstructor() - { - new DelegatingLoader($resolver = new LoaderResolver()); - $this->assertTrue(true, '__construct() takes a loader resolver as its first argument'); - } - - public function testGetSetResolver() - { - $resolver = new LoaderResolver(); - $loader = new DelegatingLoader($resolver); - $this->assertSame($resolver, $loader->getResolver(), '->getResolver() gets the resolver loader'); - $loader->setResolver($resolver = new LoaderResolver()); - $this->assertSame($resolver, $loader->getResolver(), '->setResolver() sets the resolver loader'); - } - - public function testSupports() - { - $loader1 = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $loader1->expects($this->once())->method('supports')->willReturn(true); - $loader = new DelegatingLoader(new LoaderResolver([$loader1])); - $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable'); - - $loader1 = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $loader1->expects($this->once())->method('supports')->willReturn(false); - $loader = new DelegatingLoader(new LoaderResolver([$loader1])); - $this->assertFalse($loader->supports('foo.foo'), '->supports() returns false if the resource is not loadable'); - } - - public function testLoad() - { - $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $loader->expects($this->once())->method('supports')->willReturn(true); - $loader->expects($this->once())->method('load'); - $resolver = new LoaderResolver([$loader]); - $loader = new DelegatingLoader($resolver); - - $loader->load('foo'); - } - - public function testLoadThrowsAnExceptionIfTheResourceCannotBeLoaded() - { - $this->expectException('Symfony\Component\Config\Exception\FileLoaderLoadException'); - $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $loader->expects($this->once())->method('supports')->willReturn(false); - $resolver = new LoaderResolver([$loader]); - $loader = new DelegatingLoader($resolver); - - $loader->load('foo'); - } -} diff --git a/vendor/symfony/config/Tests/Loader/FileLoaderTest.php b/vendor/symfony/config/Tests/Loader/FileLoaderTest.php deleted file mode 100644 index b59ace46..00000000 --- a/vendor/symfony/config/Tests/Loader/FileLoaderTest.php +++ /dev/null @@ -1,128 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Loader\FileLoader; -use Symfony\Component\Config\Loader\LoaderResolver; - -class FileLoaderTest extends TestCase -{ - public function testImportWithFileLocatorDelegation() - { - $locatorMock = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock(); - - $locatorMockForAdditionalLoader = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock(); - $locatorMockForAdditionalLoader->expects($this->any())->method('locate')->will($this->onConsecutiveCalls( - ['path/to/file1'], // Default - ['path/to/file1', 'path/to/file2'], // First is imported - ['path/to/file1', 'path/to/file2'], // Second is imported - ['path/to/file1'], // Exception - ['path/to/file1', 'path/to/file2'] // Exception - )); - - $fileLoader = new TestFileLoader($locatorMock); - $fileLoader->setSupports(false); - $fileLoader->setCurrentDir('.'); - - $additionalLoader = new TestFileLoader($locatorMockForAdditionalLoader); - $additionalLoader->setCurrentDir('.'); - - $fileLoader->setResolver($loaderResolver = new LoaderResolver([$fileLoader, $additionalLoader])); - - // Default case - $this->assertSame('path/to/file1', $fileLoader->import('my_resource')); - - // Check first file is imported if not already loading - $this->assertSame('path/to/file1', $fileLoader->import('my_resource')); - - // Check second file is imported if first is already loading - $fileLoader->addLoading('path/to/file1'); - $this->assertSame('path/to/file2', $fileLoader->import('my_resource')); - - // Check exception throws if first (and only available) file is already loading - try { - $fileLoader->import('my_resource'); - $this->fail('->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException', $e, '->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading'); - } - - // Check exception throws if all files are already loading - try { - $fileLoader->addLoading('path/to/file2'); - $fileLoader->import('my_resource'); - $this->fail('->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException', $e, '->import() throws a FileLoaderImportCircularReferenceException if the resource is already loading'); - } - } - - public function testImportWithGlobLikeResource() - { - $locatorMock = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock(); - $loader = new TestFileLoader($locatorMock); - - $this->assertSame('[foo]', $loader->import('[foo]')); - } - - public function testImportWithNoGlobMatch() - { - $locatorMock = $this->getMockBuilder('Symfony\Component\Config\FileLocatorInterface')->getMock(); - $loader = new TestFileLoader($locatorMock); - - $this->assertNull($loader->import('./*.abc')); - } - - public function testImportWithSimpleGlob() - { - $loader = new TestFileLoader(new FileLocator(__DIR__)); - - $this->assertSame(__FILE__, strtr($loader->import('FileLoaderTest.*'), '/', \DIRECTORY_SEPARATOR)); - } -} - -class TestFileLoader extends FileLoader -{ - private $supports = true; - - public function load($resource, $type = null) - { - return $resource; - } - - public function supports($resource, $type = null) - { - return $this->supports; - } - - public function addLoading($resource) - { - self::$loading[$resource] = true; - } - - public function removeLoading($resource) - { - unset(self::$loading[$resource]); - } - - public function clearLoading() - { - self::$loading = []; - } - - public function setSupports($supports) - { - $this->supports = $supports; - } -} diff --git a/vendor/symfony/config/Tests/Loader/LoaderResolverTest.php b/vendor/symfony/config/Tests/Loader/LoaderResolverTest.php deleted file mode 100644 index aabc2a60..00000000 --- a/vendor/symfony/config/Tests/Loader/LoaderResolverTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Loader\LoaderResolver; - -class LoaderResolverTest extends TestCase -{ - public function testConstructor() - { - $resolver = new LoaderResolver([ - $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(), - ]); - - $this->assertEquals([$loader], $resolver->getLoaders(), '__construct() takes an array of loaders as its first argument'); - } - - public function testResolve() - { - $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $resolver = new LoaderResolver([$loader]); - $this->assertFalse($resolver->resolve('foo.foo'), '->resolve() returns false if no loader is able to load the resource'); - - $loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $loader->expects($this->once())->method('supports')->willReturn(true); - $resolver = new LoaderResolver([$loader]); - $this->assertEquals($loader, $resolver->resolve(function () {}), '->resolve() returns the loader for the given resource'); - } - - public function testLoaders() - { - $resolver = new LoaderResolver(); - $resolver->addLoader($loader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock()); - - $this->assertEquals([$loader], $resolver->getLoaders(), 'addLoader() adds a loader'); - } -} diff --git a/vendor/symfony/config/Tests/Loader/LoaderTest.php b/vendor/symfony/config/Tests/Loader/LoaderTest.php deleted file mode 100644 index 79ddf00f..00000000 --- a/vendor/symfony/config/Tests/Loader/LoaderTest.php +++ /dev/null @@ -1,116 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Loader\Loader; - -class LoaderTest extends TestCase -{ - public function testGetSetResolver() - { - $resolver = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderResolverInterface')->getMock(); - - $loader = new ProjectLoader1(); - $loader->setResolver($resolver); - - $this->assertSame($resolver, $loader->getResolver(), '->setResolver() sets the resolver loader'); - } - - public function testResolve() - { - $resolvedLoader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - - $resolver = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderResolverInterface')->getMock(); - $resolver->expects($this->once()) - ->method('resolve') - ->with('foo.xml') - ->willReturn($resolvedLoader); - - $loader = new ProjectLoader1(); - $loader->setResolver($resolver); - - $this->assertSame($loader, $loader->resolve('foo.foo'), '->resolve() finds a loader'); - $this->assertSame($resolvedLoader, $loader->resolve('foo.xml'), '->resolve() finds a loader'); - } - - public function testResolveWhenResolverCannotFindLoader() - { - $this->expectException('Symfony\Component\Config\Exception\FileLoaderLoadException'); - $resolver = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderResolverInterface')->getMock(); - $resolver->expects($this->once()) - ->method('resolve') - ->with('FOOBAR') - ->willReturn(false); - - $loader = new ProjectLoader1(); - $loader->setResolver($resolver); - - $loader->resolve('FOOBAR'); - } - - public function testImport() - { - $resolvedLoader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $resolvedLoader->expects($this->once()) - ->method('load') - ->with('foo') - ->willReturn('yes'); - - $resolver = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderResolverInterface')->getMock(); - $resolver->expects($this->once()) - ->method('resolve') - ->with('foo') - ->willReturn($resolvedLoader); - - $loader = new ProjectLoader1(); - $loader->setResolver($resolver); - - $this->assertEquals('yes', $loader->import('foo')); - } - - public function testImportWithType() - { - $resolvedLoader = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderInterface')->getMock(); - $resolvedLoader->expects($this->once()) - ->method('load') - ->with('foo', 'bar') - ->willReturn('yes'); - - $resolver = $this->getMockBuilder('Symfony\Component\Config\Loader\LoaderResolverInterface')->getMock(); - $resolver->expects($this->once()) - ->method('resolve') - ->with('foo', 'bar') - ->willReturn($resolvedLoader); - - $loader = new ProjectLoader1(); - $loader->setResolver($resolver); - - $this->assertEquals('yes', $loader->import('foo', 'bar')); - } -} - -class ProjectLoader1 extends Loader -{ - public function load($resource, $type = null) - { - } - - public function supports($resource, $type = null) - { - return \is_string($resource) && 'foo' === pathinfo($resource, \PATHINFO_EXTENSION); - } - - public function getType() - { - } -} diff --git a/vendor/symfony/config/Tests/Resource/ClassExistenceResourceTest.php b/vendor/symfony/config/Tests/Resource/ClassExistenceResourceTest.php deleted file mode 100644 index 8020a578..00000000 --- a/vendor/symfony/config/Tests/Resource/ClassExistenceResourceTest.php +++ /dev/null @@ -1,130 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\ClassExistenceResource; -use Symfony\Component\Config\Tests\Fixtures\BadFileName; -use Symfony\Component\Config\Tests\Fixtures\BadParent; -use Symfony\Component\Config\Tests\Fixtures\ParseError; -use Symfony\Component\Config\Tests\Fixtures\Resource\ConditionalClass; - -class ClassExistenceResourceTest extends TestCase -{ - public function testToString() - { - $res = new ClassExistenceResource('BarClass'); - $this->assertSame('BarClass', (string) $res); - } - - public function testGetResource() - { - $res = new ClassExistenceResource('BarClass'); - $this->assertSame('BarClass', $res->getResource()); - } - - public function testIsFreshWhenClassDoesNotExist() - { - $res = new ClassExistenceResource('Symfony\Component\Config\Tests\Fixtures\BarClass'); - - $this->assertTrue($res->isFresh(time())); - - eval(<<assertFalse($res->isFresh(time())); - } - - public function testIsFreshWhenClassExists() - { - $res = new ClassExistenceResource('Symfony\Component\Config\Tests\Resource\ClassExistenceResourceTest'); - - $this->assertTrue($res->isFresh(time())); - } - - public function testExistsKo() - { - spl_autoload_register($autoloader = function ($class) use (&$loadedClass) { $loadedClass = $class; }); - - try { - $res = new ClassExistenceResource('MissingFooClass'); - $this->assertTrue($res->isFresh(0)); - - $this->assertSame('MissingFooClass', $loadedClass); - - $loadedClass = 123; - - new ClassExistenceResource('MissingFooClass', false); - - $this->assertSame(123, $loadedClass); - } finally { - spl_autoload_unregister($autoloader); - } - } - - public function testBadParentWithTimestamp() - { - $res = new ClassExistenceResource(BadParent::class, false); - $this->assertTrue($res->isFresh(time())); - } - - public function testBadParentWithNoTimestamp() - { - $this->expectException('ReflectionException'); - $this->expectExceptionMessage('Class "Symfony\Component\Config\Tests\Fixtures\MissingParent" not found while loading "Symfony\Component\Config\Tests\Fixtures\BadParent".'); - - $res = new ClassExistenceResource(BadParent::class, false); - $res->isFresh(0); - } - - public function testBadFileName() - { - $this->expectException('ReflectionException'); - $this->expectExceptionMessage('Mismatch between file name and class name.'); - - $res = new ClassExistenceResource(BadFileName::class, false); - $res->isFresh(0); - } - - public function testBadFileNameBis() - { - $this->expectException('ReflectionException'); - $this->expectExceptionMessage('Mismatch between file name and class name.'); - - $res = new ClassExistenceResource(BadFileName::class, false); - $res->isFresh(0); - } - - public function testConditionalClass() - { - $res = new ClassExistenceResource(ConditionalClass::class, false); - - $this->assertFalse($res->isFresh(0)); - } - - /** - * @requires PHP 7 - */ - public function testParseError() - { - $this->expectException('ParseError'); - - $res = new ClassExistenceResource(ParseError::class, false); - $res->isFresh(0); - } -} diff --git a/vendor/symfony/config/Tests/Resource/ComposerResourceTest.php b/vendor/symfony/config/Tests/Resource/ComposerResourceTest.php deleted file mode 100644 index 6857c766..00000000 --- a/vendor/symfony/config/Tests/Resource/ComposerResourceTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use Composer\Autoload\ClassLoader; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\ComposerResource; - -class ComposerResourceTest extends TestCase -{ - public function testGetVendor() - { - $res = new ComposerResource(); - - $r = new \ReflectionClass(ClassLoader::class); - $found = false; - - foreach ($res->getVendors() as $vendor) { - if ($vendor && 0 === strpos($r->getFileName(), $vendor)) { - $found = true; - break; - } - } - - $this->assertTrue($found); - } - - public function testSerializeUnserialize() - { - $res = new ComposerResource(); - $ser = unserialize(serialize($res)); - - $this->assertTrue($res->isFresh(0)); - $this->assertTrue($ser->isFresh(0)); - - $this->assertEquals($res, $ser); - } -} diff --git a/vendor/symfony/config/Tests/Resource/DirectoryResourceTest.php b/vendor/symfony/config/Tests/Resource/DirectoryResourceTest.php deleted file mode 100644 index 700df456..00000000 --- a/vendor/symfony/config/Tests/Resource/DirectoryResourceTest.php +++ /dev/null @@ -1,181 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\DirectoryResource; - -class DirectoryResourceTest extends TestCase -{ - protected $directory; - - protected function setUp() - { - $this->directory = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'symfonyDirectoryIterator'; - if (!file_exists($this->directory)) { - mkdir($this->directory); - } - touch($this->directory.'/tmp.xml'); - } - - protected function tearDown() - { - if (!is_dir($this->directory)) { - return; - } - $this->removeDirectory($this->directory); - } - - protected function removeDirectory($directory) - { - $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($directory), \RecursiveIteratorIterator::CHILD_FIRST); - foreach ($iterator as $path) { - if (preg_match('#[/\\\\]\.\.?$#', $path->__toString())) { - continue; - } - if ($path->isDir()) { - rmdir($path->__toString()); - } else { - unlink($path->__toString()); - } - } - rmdir($directory); - } - - public function testGetResource() - { - $resource = new DirectoryResource($this->directory); - $this->assertSame(realpath($this->directory), $resource->getResource(), '->getResource() returns the path to the resource'); - } - - public function testGetPattern() - { - $resource = new DirectoryResource($this->directory, 'bar'); - $this->assertEquals('bar', $resource->getPattern()); - } - - public function testResourceDoesNotExist() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The directory ".*" does not exist./'); - new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999)); - } - - public function testIsFresh() - { - $resource = new DirectoryResource($this->directory); - $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if the resource has not changed'); - $this->assertFalse($resource->isFresh(time() - 86400), '->isFresh() returns false if the resource has been updated'); - } - - public function testIsFreshForDeletedResources() - { - $resource = new DirectoryResource($this->directory); - $this->removeDirectory($this->directory); - - $this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the resource does not exist'); - } - - public function testIsFreshUpdateFile() - { - $resource = new DirectoryResource($this->directory); - touch($this->directory.'/tmp.xml', time() + 20); - $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if an existing file is modified'); - } - - public function testIsFreshNewFile() - { - $resource = new DirectoryResource($this->directory); - touch($this->directory.'/new.xml', time() + 20); - $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a new file is added'); - } - - public function testIsFreshNewFileWithDifferentPattern() - { - $resource = new DirectoryResource($this->directory, '/.xml$/'); - touch($this->directory.'/new.yaml', time() + 20); - $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if a new file with a non-matching pattern is added'); - } - - public function testIsFreshDeleteFile() - { - $resource = new DirectoryResource($this->directory); - $time = time(); - sleep(1); - unlink($this->directory.'/tmp.xml'); - $this->assertFalse($resource->isFresh($time), '->isFresh() returns false if an existing file is removed'); - } - - public function testIsFreshDeleteDirectory() - { - $resource = new DirectoryResource($this->directory); - $this->removeDirectory($this->directory); - $this->assertFalse($resource->isFresh(time()), '->isFresh() returns false if the whole resource is removed'); - } - - public function testIsFreshCreateFileInSubdirectory() - { - $subdirectory = $this->directory.'/subdirectory'; - mkdir($subdirectory); - - $resource = new DirectoryResource($this->directory); - $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if an unmodified subdirectory exists'); - - touch($subdirectory.'/newfile.xml', time() + 20); - $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a new file in a subdirectory is added'); - } - - public function testIsFreshModifySubdirectory() - { - $resource = new DirectoryResource($this->directory); - - $subdirectory = $this->directory.'/subdirectory'; - mkdir($subdirectory); - touch($subdirectory, time() + 20); - - $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if a subdirectory is modified (e.g. a file gets deleted)'); - } - - public function testFilterRegexListNoMatch() - { - $resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/'); - - touch($this->directory.'/new.bar', time() + 20); - $this->assertTrue($resource->isFresh(time() + 10), '->isFresh() returns true if a new file not matching the filter regex is created'); - } - - public function testFilterRegexListMatch() - { - $resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/'); - - touch($this->directory.'/new.xml', time() + 20); - $this->assertFalse($resource->isFresh(time() + 10), '->isFresh() returns false if an new file matching the filter regex is created '); - } - - public function testSerializeUnserialize() - { - $resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/'); - - unserialize(serialize($resource)); - - $this->assertSame(realpath($this->directory), $resource->getResource()); - $this->assertSame('/\.(foo|xml)$/', $resource->getPattern()); - } - - public function testResourcesWithDifferentPatternsAreDifferent() - { - $resourceA = new DirectoryResource($this->directory, '/.xml$/'); - $resourceB = new DirectoryResource($this->directory, '/.yaml$/'); - - $this->assertCount(2, array_unique([$resourceA, $resourceB])); - } -} diff --git a/vendor/symfony/config/Tests/Resource/FileExistenceResourceTest.php b/vendor/symfony/config/Tests/Resource/FileExistenceResourceTest.php deleted file mode 100644 index ff7fc7b5..00000000 --- a/vendor/symfony/config/Tests/Resource/FileExistenceResourceTest.php +++ /dev/null @@ -1,71 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\FileExistenceResource; - -class FileExistenceResourceTest extends TestCase -{ - protected $resource; - protected $file; - protected $time; - - protected function setUp() - { - $this->file = realpath(sys_get_temp_dir()).'/tmp.xml'; - $this->time = time(); - $this->resource = new FileExistenceResource($this->file); - } - - protected function tearDown() - { - if (file_exists($this->file)) { - @unlink($this->file); - } - } - - public function testToString() - { - $this->assertSame($this->file, (string) $this->resource); - } - - public function testGetResource() - { - $this->assertSame($this->file, $this->resource->getResource(), '->getResource() returns the path to the resource'); - } - - public function testIsFreshWithExistingResource() - { - touch($this->file, $this->time); - $serialized = serialize(new FileExistenceResource($this->file)); - - $resource = unserialize($serialized); - $this->assertTrue($resource->isFresh($this->time), '->isFresh() returns true if the resource is still present'); - - unlink($this->file); - $resource = unserialize($serialized); - $this->assertFalse($resource->isFresh($this->time), '->isFresh() returns false if the resource has been deleted'); - } - - public function testIsFreshWithAbsentResource() - { - $serialized = serialize(new FileExistenceResource($this->file)); - - $resource = unserialize($serialized); - $this->assertTrue($resource->isFresh($this->time), '->isFresh() returns true if the resource is still absent'); - - touch($this->file, $this->time); - $resource = unserialize($serialized); - $this->assertFalse($resource->isFresh($this->time), '->isFresh() returns false if the resource has been created'); - } -} diff --git a/vendor/symfony/config/Tests/Resource/FileResourceTest.php b/vendor/symfony/config/Tests/Resource/FileResourceTest.php deleted file mode 100644 index a84faa95..00000000 --- a/vendor/symfony/config/Tests/Resource/FileResourceTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\FileResource; - -class FileResourceTest extends TestCase -{ - protected $resource; - protected $file; - protected $time; - - protected function setUp() - { - $this->file = sys_get_temp_dir().'/tmp.xml'; - $this->time = time(); - touch($this->file, $this->time); - $this->resource = new FileResource($this->file); - } - - protected function tearDown() - { - if (file_exists($this->file)) { - @unlink($this->file); - } - } - - public function testGetResource() - { - $this->assertSame(realpath($this->file), $this->resource->getResource(), '->getResource() returns the path to the resource'); - } - - public function testGetResourceWithScheme() - { - $resource = new FileResource('file://'.$this->file); - $this->assertSame('file://'.$this->file, $resource->getResource(), '->getResource() returns the path to the schemed resource'); - } - - public function testToString() - { - $this->assertSame(realpath($this->file), (string) $this->resource); - } - - public function testResourceDoesNotExist() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The file ".*" does not exist./'); - new FileResource('/____foo/foobar'.mt_rand(1, 999999)); - } - - public function testIsFresh() - { - $this->assertTrue($this->resource->isFresh($this->time), '->isFresh() returns true if the resource has not changed in same second'); - $this->assertTrue($this->resource->isFresh($this->time + 10), '->isFresh() returns true if the resource has not changed'); - $this->assertFalse($this->resource->isFresh($this->time - 86400), '->isFresh() returns false if the resource has been updated'); - } - - public function testIsFreshForDeletedResources() - { - unlink($this->file); - - $this->assertFalse($this->resource->isFresh($this->time), '->isFresh() returns false if the resource does not exist'); - } - - public function testSerializeUnserialize() - { - unserialize(serialize($this->resource)); - - $this->assertSame(realpath($this->file), $this->resource->getResource()); - } -} diff --git a/vendor/symfony/config/Tests/Resource/GlobResourceTest.php b/vendor/symfony/config/Tests/Resource/GlobResourceTest.php deleted file mode 100644 index cfbfd2b4..00000000 --- a/vendor/symfony/config/Tests/Resource/GlobResourceTest.php +++ /dev/null @@ -1,114 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\GlobResource; - -class GlobResourceTest extends TestCase -{ - protected function tearDown() - { - $dir = \dirname(__DIR__).'/Fixtures'; - @rmdir($dir.'/TmpGlob'); - @unlink($dir.'/TmpGlob'); - @unlink($dir.'/Resource/TmpGlob'); - touch($dir.'/Resource/.hiddenFile'); - } - - public function testIterator() - { - $dir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures'; - $resource = new GlobResource($dir, '/Resource', true); - - $paths = iterator_to_array($resource); - - $file = $dir.'/Resource'.\DIRECTORY_SEPARATOR.'ConditionalClass.php'; - $this->assertEquals([$file => new \SplFileInfo($file)], $paths); - $this->assertInstanceOf('SplFileInfo', current($paths)); - $this->assertSame($dir, $resource->getPrefix()); - - $resource = new GlobResource($dir, '/**/Resource', true); - - $paths = iterator_to_array($resource); - - $file = $dir.\DIRECTORY_SEPARATOR.'Resource'.\DIRECTORY_SEPARATOR.'ConditionalClass.php'; - $this->assertEquals([$file => $file], $paths); - $this->assertInstanceOf('SplFileInfo', current($paths)); - $this->assertSame($dir, $resource->getPrefix()); - } - - public function testIsFreshNonRecursiveDetectsNewFile() - { - $dir = \dirname(__DIR__).'/Fixtures'; - $resource = new GlobResource($dir, '/*', false); - - $this->assertTrue($resource->isFresh(0)); - - mkdir($dir.'/TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - - rmdir($dir.'/TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - - touch($dir.'/TmpGlob'); - $this->assertFalse($resource->isFresh(0)); - - unlink($dir.'/TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - } - - public function testIsFreshNonRecursiveDetectsRemovedFile() - { - $dir = \dirname(__DIR__).'/Fixtures'; - $resource = new GlobResource($dir, '/*', false); - - touch($dir.'/TmpGlob'); - touch($dir.'/.TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - - unlink($dir.'/.TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - - unlink($dir.'/TmpGlob'); - $this->assertFalse($resource->isFresh(0)); - } - - public function testIsFreshRecursiveDetectsRemovedFile() - { - $dir = \dirname(__DIR__).'/Fixtures'; - $resource = new GlobResource($dir, '/*', true); - - touch($dir.'/Resource/TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - - unlink($dir.'/Resource/TmpGlob'); - $this->assertFalse($resource->isFresh(0)); - - touch($dir.'/Resource/TmpGlob'); - $this->assertTrue($resource->isFresh(0)); - - unlink($dir.'/Resource/.hiddenFile'); - $this->assertTrue($resource->isFresh(0)); - } - - public function testIsFreshRecursiveDetectsNewFile() - { - $dir = \dirname(__DIR__).'/Fixtures'; - $resource = new GlobResource($dir, '/*', true); - - $this->assertTrue($resource->isFresh(0)); - - touch($dir.'/Resource/TmpGlob'); - $this->assertFalse($resource->isFresh(0)); - } -} diff --git a/vendor/symfony/config/Tests/Resource/ReflectionClassResourceTest.php b/vendor/symfony/config/Tests/Resource/ReflectionClassResourceTest.php deleted file mode 100644 index 74ed6b3e..00000000 --- a/vendor/symfony/config/Tests/Resource/ReflectionClassResourceTest.php +++ /dev/null @@ -1,223 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\ReflectionClassResource; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -class ReflectionClassResourceTest extends TestCase -{ - public function testToString() - { - $res = new ReflectionClassResource(new \ReflectionClass('ErrorException')); - - $this->assertSame('reflection.ErrorException', (string) $res); - } - - public function testSerializeUnserialize() - { - $res = new ReflectionClassResource(new \ReflectionClass(DummyInterface::class)); - $ser = unserialize(serialize($res)); - - $this->assertTrue($res->isFresh(0)); - $this->assertTrue($ser->isFresh(0)); - - $this->assertSame((string) $res, (string) $ser); - } - - public function testIsFresh() - { - $res = new ReflectionClassResource(new \ReflectionClass(__CLASS__)); - $mtime = filemtime(__FILE__); - - $this->assertTrue($res->isFresh($mtime), '->isFresh() returns true if the resource has not changed in same second'); - $this->assertTrue($res->isFresh($mtime + 10), '->isFresh() returns true if the resource has not changed'); - $this->assertTrue($res->isFresh($mtime - 86400), '->isFresh() returns true if the resource has not changed'); - } - - public function testIsFreshForDeletedResources() - { - $now = time(); - $tmp = sys_get_temp_dir().'/tmp.php'; - file_put_contents($tmp, 'assertTrue($res->isFresh($now)); - - unlink($tmp); - $this->assertFalse($res->isFresh($now), '->isFresh() returns false if the resource does not exist'); - } - - /** - * @dataProvider provideHashedSignature - */ - public function testHashedSignature($changeExpected, $changedLine, $changedCode, $setContext = null) - { - if ($setContext) { - $setContext(); - } - - $code = <<<'EOPHP' -/* 0*/ -/* 1*/ class %s extends ErrorException -/* 2*/ { -/* 3*/ const FOO = 123; -/* 4*/ -/* 5*/ public $pub = []; -/* 6*/ -/* 7*/ protected $prot; -/* 8*/ -/* 9*/ private $priv; -/*10*/ -/*11*/ public function pub($arg = null) {} -/*12*/ -/*13*/ protected function prot($a = []) {} -/*14*/ -/*15*/ private function priv() {} -/*16*/ -/*17*/ public function ccc($bar = A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC) {} -/*18*/ } -EOPHP; - - static $expectedSignature, $generateSignature; - - if (null === $expectedSignature) { - eval(sprintf($code, $class = 'Foo'.str_replace('.', '_', uniqid('', true)))); - $r = new \ReflectionClass(ReflectionClassResource::class); - $generateSignature = $r->getMethod('generateSignature'); - $generateSignature->setAccessible(true); - $generateSignature = $generateSignature->getClosure($r->newInstanceWithoutConstructor()); - $expectedSignature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class)))); - } - - $code = explode("\n", $code); - if (null !== $changedCode) { - $code[$changedLine] = $changedCode; - } - eval(sprintf(implode("\n", $code), $class = 'Foo'.str_replace('.', '_', uniqid('', true)))); - $signature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class)))); - - if ($changeExpected) { - $this->assertNotSame($expectedSignature, $signature); - } else { - $this->assertSame($expectedSignature, $signature); - } - } - - public function provideHashedSignature() - { - yield [0, 0, "// line change\n\n"]; - yield [1, 0, '/** class docblock */']; - yield [1, 1, 'abstract class %s']; - yield [1, 1, 'final class %s']; - yield [1, 1, 'class %s extends Exception']; - yield [1, 1, 'class %s implements '.DummyInterface::class]; - yield [1, 3, 'const FOO = 456;']; - yield [1, 3, 'const BAR = 123;']; - yield [1, 4, '/** pub docblock */']; - yield [1, 5, 'protected $pub = [];']; - yield [1, 5, 'public $pub = [123];']; - yield [1, 6, '/** prot docblock */']; - yield [1, 7, 'private $prot;']; - yield [0, 8, '/** priv docblock */']; - yield [0, 9, 'private $priv = 123;']; - yield [1, 10, '/** pub docblock */']; - if (\PHP_VERSION_ID >= 50600) { - yield [1, 11, 'public function pub(...$arg) {}']; - } - if (\PHP_VERSION_ID >= 70000) { - yield [1, 11, 'public function pub($arg = null): Foo {}']; - } - yield [0, 11, "public function pub(\$arg = null) {\nreturn 123;\n}"]; - yield [1, 12, '/** prot docblock */']; - yield [1, 13, 'protected function prot($a = [123]) {}']; - yield [0, 14, '/** priv docblock */']; - yield [0, 15, '']; - - if (\PHP_VERSION_ID >= 70400) { - // PHP7.4 typed properties without default value are - // undefined, make sure this doesn't throw an error - yield [1, 5, 'public array $pub;']; - yield [0, 7, 'protected int $prot;']; - yield [0, 9, 'private string $priv;']; - } - - yield [1, 17, 'public function ccc($bar = 187) {}']; - yield [1, 17, 'public function ccc($bar = ANOTHER_ONE_THAT_WILL_NEVER_BE_DEFINED_CCCCCCCCC) {}']; - yield [1, 17, null, static function () { \define('A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC', 'foo'); }]; - } - - public function testEventSubscriber() - { - $res = new ReflectionClassResource(new \ReflectionClass(TestEventSubscriber::class)); - $this->assertTrue($res->isFresh(0)); - - TestEventSubscriber::$subscribedEvents = [123]; - $this->assertFalse($res->isFresh(0)); - - $res = new ReflectionClassResource(new \ReflectionClass(TestEventSubscriber::class)); - $this->assertTrue($res->isFresh(0)); - } - - public function testServiceSubscriber() - { - $res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class)); - $this->assertTrue($res->isFresh(0)); - - TestServiceSubscriber::$subscribedServices = [123]; - $this->assertFalse($res->isFresh(0)); - - $res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class)); - $this->assertTrue($res->isFresh(0)); - } - - public function testIgnoresObjectsInSignature() - { - $res = new ReflectionClassResource(new \ReflectionClass(TestServiceWithStaticProperty::class)); - $this->assertTrue($res->isFresh(0)); - - TestServiceWithStaticProperty::$initializedObject = new TestServiceWithStaticProperty(); - $this->assertTrue($res->isFresh(0)); - } -} - -interface DummyInterface -{ -} - -class TestEventSubscriber implements EventSubscriberInterface -{ - public static $subscribedEvents = []; - - public static function getSubscribedEvents() - { - return self::$subscribedEvents; - } -} - -class TestServiceSubscriber implements ServiceSubscriberInterface -{ - public static $subscribedServices = []; - - public static function getSubscribedServices() - { - return self::$subscribedServices; - } -} - -class TestServiceWithStaticProperty -{ - public static $initializedObject; -} diff --git a/vendor/symfony/config/Tests/Resource/ResourceStub.php b/vendor/symfony/config/Tests/Resource/ResourceStub.php deleted file mode 100644 index b01729cb..00000000 --- a/vendor/symfony/config/Tests/Resource/ResourceStub.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Resource; - -use Symfony\Component\Config\Resource\SelfCheckingResourceInterface; - -class ResourceStub implements SelfCheckingResourceInterface -{ - private $fresh = true; - - public function setFresh($isFresh) - { - $this->fresh = $isFresh; - } - - public function __toString() - { - return 'stub'; - } - - public function isFresh($timestamp) - { - return $this->fresh; - } -} diff --git a/vendor/symfony/config/Tests/ResourceCheckerConfigCacheTest.php b/vendor/symfony/config/Tests/ResourceCheckerConfigCacheTest.php deleted file mode 100644 index 9be53196..00000000 --- a/vendor/symfony/config/Tests/ResourceCheckerConfigCacheTest.php +++ /dev/null @@ -1,150 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Resource\FileResource; -use Symfony\Component\Config\ResourceCheckerConfigCache; -use Symfony\Component\Config\Tests\Resource\ResourceStub; - -class ResourceCheckerConfigCacheTest extends TestCase -{ - private $cacheFile = null; - - protected function setUp() - { - $this->cacheFile = tempnam(sys_get_temp_dir(), 'config_'); - } - - protected function tearDown() - { - $files = [$this->cacheFile, "{$this->cacheFile}.meta"]; - - foreach ($files as $file) { - if (file_exists($file)) { - @unlink($file); - } - } - } - - public function testGetPath() - { - $cache = new ResourceCheckerConfigCache($this->cacheFile); - - $this->assertSame($this->cacheFile, $cache->getPath()); - } - - public function testCacheIsNotFreshIfEmpty() - { - $checker = $this->getMockBuilder('\Symfony\Component\Config\ResourceCheckerInterface')->getMock() - ->expects($this->never())->method('supports'); - - /* If there is nothing in the cache, it needs to be filled (and thus it's not fresh). - It does not matter if you provide checkers or not. */ - - unlink($this->cacheFile); // remove tempnam() side effect - $cache = new ResourceCheckerConfigCache($this->cacheFile, [$checker]); - - $this->assertFalse($cache->isFresh()); - } - - public function testCacheIsFreshIfNoCheckerProvided() - { - /* For example in prod mode, you may choose not to run any checkers - at all. In that case, the cache should always be considered fresh. */ - $cache = new ResourceCheckerConfigCache($this->cacheFile); - $this->assertTrue($cache->isFresh()); - } - - public function testCacheIsFreshIfEmptyCheckerIteratorProvided() - { - $cache = new ResourceCheckerConfigCache($this->cacheFile, new \ArrayIterator([])); - $this->assertTrue($cache->isFresh()); - } - - public function testResourcesWithoutcheckersAreIgnoredAndConsideredFresh() - { - /* As in the previous test, but this time we have a resource. */ - $cache = new ResourceCheckerConfigCache($this->cacheFile); - $cache->write('', [new ResourceStub()]); - - $this->assertTrue($cache->isFresh()); // no (matching) ResourceChecker passed - } - - public function testIsFreshWithchecker() - { - $checker = $this->getMockBuilder('\Symfony\Component\Config\ResourceCheckerInterface')->getMock(); - - $checker->expects($this->once()) - ->method('supports') - ->willReturn(true); - - $checker->expects($this->once()) - ->method('isFresh') - ->willReturn(true); - - $cache = new ResourceCheckerConfigCache($this->cacheFile, [$checker]); - $cache->write('', [new ResourceStub()]); - - $this->assertTrue($cache->isFresh()); - } - - public function testIsNotFreshWithchecker() - { - $checker = $this->getMockBuilder('\Symfony\Component\Config\ResourceCheckerInterface')->getMock(); - - $checker->expects($this->once()) - ->method('supports') - ->willReturn(true); - - $checker->expects($this->once()) - ->method('isFresh') - ->willReturn(false); - - $cache = new ResourceCheckerConfigCache($this->cacheFile, [$checker]); - $cache->write('', [new ResourceStub()]); - - $this->assertFalse($cache->isFresh()); - } - - public function testCacheIsNotFreshWhenUnserializeFails() - { - $checker = $this->getMockBuilder('\Symfony\Component\Config\ResourceCheckerInterface')->getMock(); - $cache = new ResourceCheckerConfigCache($this->cacheFile, [$checker]); - $cache->write('foo', [new FileResource(__FILE__)]); - - $metaFile = "{$this->cacheFile}.meta"; - file_put_contents($metaFile, str_replace('FileResource', 'ClassNotHere', file_get_contents($metaFile))); - - $this->assertFalse($cache->isFresh()); - } - - public function testCacheKeepsContent() - { - $cache = new ResourceCheckerConfigCache($this->cacheFile); - $cache->write('FOOBAR'); - - $this->assertSame('FOOBAR', file_get_contents($cache->getPath())); - } - - public function testCacheIsNotFreshIfNotExistsMetaFile() - { - $checker = $this->getMockBuilder('\Symfony\Component\Config\ResourceCheckerInterface')->getMock(); - $cache = new ResourceCheckerConfigCache($this->cacheFile, [$checker]); - $cache->write('foo', [new FileResource(__FILE__)]); - - $metaFile = "{$this->cacheFile}.meta"; - unlink($metaFile); - - $this->assertFalse($cache->isFresh()); - } -} diff --git a/vendor/symfony/config/Tests/Util/XmlUtilsTest.php b/vendor/symfony/config/Tests/Util/XmlUtilsTest.php deleted file mode 100644 index f0b77ae6..00000000 --- a/vendor/symfony/config/Tests/Util/XmlUtilsTest.php +++ /dev/null @@ -1,240 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Config\Tests\Util; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Util\XmlUtils; - -class XmlUtilsTest extends TestCase -{ - public function testLoadFile() - { - $fixtures = __DIR__.'/../Fixtures/Util/'; - - try { - XmlUtils::loadFile($fixtures); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertStringContainsString('is not a file', $e->getMessage()); - } - - try { - XmlUtils::loadFile($fixtures.'non_existing.xml'); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertStringContainsString('is not a file', $e->getMessage()); - } - - try { - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('chmod is not supported on Windows'); - } - chmod($fixtures.'not_readable.xml', 000); - XmlUtils::loadFile($fixtures.'not_readable.xml'); - $this->fail(); - } catch (\InvalidArgumentException $e) { - chmod($fixtures.'not_readable.xml', 0644); - $this->assertStringContainsString('is not readable', $e->getMessage()); - } - - try { - XmlUtils::loadFile($fixtures.'invalid.xml'); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertStringContainsString('ERROR ', $e->getMessage()); - } - - try { - XmlUtils::loadFile($fixtures.'document_type.xml'); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertStringContainsString('Document types are not allowed', $e->getMessage()); - } - - try { - XmlUtils::loadFile($fixtures.'invalid_schema.xml', $fixtures.'schema.xsd'); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertStringContainsString('ERROR 1845', $e->getMessage()); - } - - try { - XmlUtils::loadFile($fixtures.'invalid_schema.xml', 'invalid_callback_or_file'); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertStringContainsString('XSD file or callable', $e->getMessage()); - } - - $mock = $this->getMockBuilder(Validator::class)->getMock(); - $mock->expects($this->exactly(2))->method('validate')->will($this->onConsecutiveCalls(false, true)); - - try { - XmlUtils::loadFile($fixtures.'valid.xml', [$mock, 'validate']); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertMatchesRegularExpression('/The XML file ".+" is not valid\./', $e->getMessage()); - } - - $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', [$mock, 'validate'])); - $this->assertSame([], libxml_get_errors()); - } - - public function testParseWithInvalidValidatorCallable() - { - $this->expectException('Symfony\Component\Config\Util\Exception\InvalidXmlException'); - $this->expectExceptionMessage('The XML is not valid'); - $fixtures = __DIR__.'/../Fixtures/Util/'; - - $mock = $this->getMockBuilder(Validator::class)->getMock(); - $mock->expects($this->once())->method('validate')->willReturn(false); - - XmlUtils::parse(file_get_contents($fixtures.'valid.xml'), [$mock, 'validate']); - } - - public function testLoadFileWithInternalErrorsEnabled() - { - $internalErrors = libxml_use_internal_errors(true); - - $this->assertSame([], libxml_get_errors()); - $this->assertInstanceOf('DOMDocument', XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/invalid_schema.xml')); - $this->assertSame([], libxml_get_errors()); - - libxml_clear_errors(); - libxml_use_internal_errors($internalErrors); - } - - /** - * @dataProvider getDataForConvertDomToArray - */ - public function testConvertDomToArray($expected, $xml, $root = false, $checkPrefix = true) - { - $dom = new \DOMDocument(); - $dom->loadXML($root ? $xml : ''.$xml.''); - - $this->assertSame($expected, XmlUtils::convertDomElementToArray($dom->documentElement, $checkPrefix)); - } - - public function getDataForConvertDomToArray() - { - return [ - [null, ''], - ['bar', 'bar'], - [['bar' => 'foobar'], '', true], - [['foo' => null], ''], - [['foo' => 'bar'], 'bar'], - [['foo' => ['foo' => 'bar']], ''], - [['foo' => ['foo' => 0]], '0'], - [['foo' => ['foo' => 'bar']], 'bar'], - [['foo' => ['foo' => 'bar', 'value' => 'text']], 'text'], - [['foo' => ['attr' => 'bar', 'foo' => 'text']], 'text'], - [['foo' => ['bar', 'text']], 'bartext'], - [['foo' => [['foo' => 'bar'], ['foo' => 'text']]], ''], - [['foo' => ['foo' => ['bar', 'text']]], 'text'], - [['foo' => 'bar'], 'bar'], - [['foo' => 'text'], 'text'], - [['foo' => ['bar' => 'bar', 'value' => 'text']], 'text', false, false], - [['attr' => 1, 'b' => 'hello'], 'hello2', true], - ]; - } - - /** - * @dataProvider getDataForPhpize - */ - public function testPhpize($expected, $value) - { - $this->assertSame($expected, XmlUtils::phpize($value)); - } - - public function getDataForPhpize() - { - return [ - ['', ''], - [null, 'null'], - [true, 'true'], - [false, 'false'], - [null, 'Null'], - [true, 'True'], - [false, 'False'], - [0, '0'], - [1, '1'], - [-1, '-1'], - [0777, '0777'], - [255, '0xFF'], - [100.0, '1e2'], - [-120.0, '-1.2E2'], - [-10100.1, '-10100.1'], - ['-10,100.1', '-10,100.1'], - ['1234 5678 9101 1121 3141', '1234 5678 9101 1121 3141'], - ['1,2,3,4', '1,2,3,4'], - ['11,22,33,44', '11,22,33,44'], - ['11,222,333,4', '11,222,333,4'], - ['1,222,333,444', '1,222,333,444'], - ['11,222,333,444', '11,222,333,444'], - ['111,222,333,444', '111,222,333,444'], - ['1111,2222,3333,4444,5555', '1111,2222,3333,4444,5555'], - ['foo', 'foo'], - [6, '0b0110'], - ]; - } - - public function testLoadEmptyXmlFile() - { - $file = __DIR__.'/../Fixtures/foo.xml'; - - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage(sprintf('File "%s" does not contain valid XML, it is empty.', $file)); - - XmlUtils::loadFile($file); - } - - // test for issue https://github.com/symfony/symfony/issues/9731 - public function testLoadWrongEmptyXMLWithErrorHandler() - { - if (\LIBXML_VERSION < 20900) { - $originalDisableEntities = libxml_disable_entity_loader(false); - } - $errorReporting = error_reporting(-1); - - set_error_handler(function ($errno, $errstr) { - throw new \Exception($errstr, $errno); - }); - - $file = __DIR__.'/../Fixtures/foo.xml'; - try { - try { - XmlUtils::loadFile($file); - $this->fail('An exception should have been raised'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals(sprintf('File "%s" does not contain valid XML, it is empty.', $file), $e->getMessage()); - } - } finally { - restore_error_handler(); - error_reporting($errorReporting); - } - - if (\LIBXML_VERSION < 20900) { - $disableEntities = libxml_disable_entity_loader(true); - libxml_disable_entity_loader($disableEntities); - - libxml_disable_entity_loader($originalDisableEntities); - $this->assertFalse($disableEntities); - } - - // should not throw an exception - XmlUtils::loadFile(__DIR__.'/../Fixtures/Util/valid.xml', __DIR__.'/../Fixtures/Util/schema.xsd'); - } -} - -interface Validator -{ - public function validate(); -} diff --git a/vendor/symfony/config/Util/Exception/InvalidXmlException.php b/vendor/symfony/config/Util/Exception/InvalidXmlException.php index a335bbd2..155571ce 100644 --- a/vendor/symfony/config/Util/Exception/InvalidXmlException.php +++ b/vendor/symfony/config/Util/Exception/InvalidXmlException.php @@ -1,4 +1,5 @@ =7.0.8", - "symfony/filesystem": "~2.8|~3.0|~4.0", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.1.3", + "symfony/filesystem": "^3.4|^4.0|^5.0", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php80": "^1.16", + "symfony/polyfill-php81": "^1.22" }, "require-dev": { - "symfony/finder": "~3.3|~4.0", - "symfony/yaml": "~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/event-dispatcher": "~3.3|~4.0" + "symfony/event-dispatcher": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/messenger": "^4.1|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/yaml": "^3.4|^4.0|^5.0" }, "conflict": { - "symfony/finder": "<3.3", - "symfony/dependency-injection": "<3.3" + "symfony/finder": "<3.4" }, "suggest": { "symfony/yaml": "To use the yaml reference dumper" diff --git a/vendor/symfony/config/phpunit.xml.dist b/vendor/symfony/config/phpunit.xml.dist deleted file mode 100644 index 1cfdb3cd..00000000 --- a/vendor/symfony/config/phpunit.xml.dist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/debug/BufferingLogger.php b/vendor/symfony/debug/BufferingLogger.php index e7db3a4c..5280c33b 100644 --- a/vendor/symfony/debug/BufferingLogger.php +++ b/vendor/symfony/debug/BufferingLogger.php @@ -13,15 +13,22 @@ use Psr\Log\AbstractLogger; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', BufferingLogger::class, \Symfony\Component\ErrorHandler\BufferingLogger::class), \E_USER_DEPRECATED); + /** * A buffering logger that stacks logs for later. * * @author Nicolas Grekas + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\BufferingLogger instead. */ class BufferingLogger extends AbstractLogger { private $logs = []; + /** + * @return void + */ public function log($level, $message, array $context = []) { $this->logs[] = [$level, $message, $context]; diff --git a/vendor/symfony/debug/CHANGELOG.md b/vendor/symfony/debug/CHANGELOG.md index 31c67eb6..d49a82df 100644 --- a/vendor/symfony/debug/CHANGELOG.md +++ b/vendor/symfony/debug/CHANGELOG.md @@ -1,56 +1,75 @@ CHANGELOG ========= +4.4.0 +----- + + * deprecated `FlattenException`, use the `FlattenException` of the `ErrorHandler` component + * deprecated the whole component in favor of the `ErrorHandler` component + +4.3.0 +----- + + * made the `ErrorHandler` and `ExceptionHandler` classes final + * added `Exception\FlattenException::getAsString` and + `Exception\FlattenException::getTraceAsString` to increase compatibility to php + exception objects + +4.0.0 +----- + + * removed the symfony_debug extension + * removed `ContextErrorException` + 3.4.0 ----- -* deprecated `ErrorHandler::stackErrors()` and `ErrorHandler::unstackErrors()` + * deprecated `ErrorHandler::stackErrors()` and `ErrorHandler::unstackErrors()` 3.3.0 ----- -* deprecated the `ContextErrorException` class: use \ErrorException directly now + * deprecated the `ContextErrorException` class: use \ErrorException directly now 3.2.0 ----- -* `FlattenException::getTrace()` now returns additional type descriptions - `integer` and `float`. - + * `FlattenException::getTrace()` now returns additional type descriptions + `integer` and `float`. 3.0.0 ----- -* removed classes, methods and interfaces deprecated in 2.x + * removed classes, methods and interfaces deprecated in 2.x 2.8.0 ----- -* added BufferingLogger for errors that happen before a proper logger is configured -* allow throwing from `__toString()` with `return trigger_error($e, E_USER_ERROR);` -* deprecate ExceptionHandler::createResponse + * added BufferingLogger for errors that happen before a proper logger is configured + * allow throwing from `__toString()` with `return trigger_error($e, E_USER_ERROR);` + * deprecate ExceptionHandler::createResponse 2.7.0 ----- -* added deprecations checking for parent interfaces/classes to DebugClassLoader -* added ZTS support to symfony_debug extension -* added symfony_debug_backtrace() to symfony_debug extension - to track the backtrace of fatal errors + * added deprecations checking for parent interfaces/classes to DebugClassLoader + * added ZTS support to symfony_debug extension + * added symfony_debug_backtrace() to symfony_debug extension + to track the backtrace of fatal errors 2.6.0 ----- -* generalized ErrorHandler and ExceptionHandler, - with some new methods and others deprecated -* enhanced error messages for uncaught exceptions + * generalized ErrorHandler and ExceptionHandler, + with some new methods and others deprecated + * enhanced error messages for uncaught exceptions 2.5.0 ----- -* added ExceptionHandler::setHandler() -* added UndefinedMethodFatalErrorHandler -* deprecated DummyException + * added ExceptionHandler::setHandler() + * added UndefinedMethodFatalErrorHandler + * deprecated DummyException 2.4.0 ----- diff --git a/vendor/symfony/debug/Debug.php b/vendor/symfony/debug/Debug.php index 746f3290..99215cf3 100644 --- a/vendor/symfony/debug/Debug.php +++ b/vendor/symfony/debug/Debug.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Debug; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', Debug::class, \Symfony\Component\ErrorHandler\Debug::class), \E_USER_DEPRECATED); + /** * Registers all the debug tools. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Debug instead. */ class Debug { @@ -23,7 +27,7 @@ class Debug /** * Enables the debug tools. * - * This method registers an error handler, an exception handler and a special class loader. + * This method registers an error handler and an exception handler. * * @param int $errorReportingLevel The level of error reporting you want * @param bool $displayErrors Whether to display errors (for development) or just log them (for production) @@ -45,7 +49,7 @@ public static function enable($errorReportingLevel = \E_ALL, $displayErrors = tr if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { ini_set('display_errors', 0); ExceptionHandler::register(); - } elseif ($displayErrors && (!filter_var(ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || ini_get('error_log'))) { + } elseif ($displayErrors && (!filter_var(\ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || \ini_get('error_log'))) { // CLI - display errors only if they're not already logged to STDERR ini_set('display_errors', 1); } diff --git a/vendor/symfony/debug/DebugClassLoader.php b/vendor/symfony/debug/DebugClassLoader.php index f54d07af..6081c525 100644 --- a/vendor/symfony/debug/DebugClassLoader.php +++ b/vendor/symfony/debug/DebugClassLoader.php @@ -11,6 +11,10 @@ namespace Symfony\Component\Debug; +use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', DebugClassLoader::class, \Symfony\Component\ErrorHandler\DebugClassLoader::class), \E_USER_DEPRECATED); + /** * Autoloader checking if the class is really defined in the file found. * @@ -21,6 +25,9 @@ * @author Fabien Potencier * @author Christophe Coevoet * @author Nicolas Grekas + * @author Guilhem Niot + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\DebugClassLoader instead. */ class DebugClassLoader { @@ -34,8 +41,9 @@ class DebugClassLoader private static $deprecated = []; private static $internal = []; private static $internalMethods = []; - private static $php7Reserved = ['int' => 1, 'float' => 1, 'bool' => 1, 'string' => 1, 'true' => 1, 'false' => 1, 'null' => 1]; + private static $annotatedParameters = []; private static $darwinCache = ['/' => ['/', []]]; + private static $method = []; public function __construct(callable $classLoader) { @@ -82,8 +90,8 @@ public function getClassLoader() public static function enable() { // Ensures we don't hit https://bugs.php.net/42098 - class_exists('Symfony\Component\Debug\ErrorHandler'); - class_exists('Psr\Log\LogLevel'); + class_exists(\Symfony\Component\Debug\ErrorHandler::class); + class_exists(\Psr\Log\LogLevel::class); if (!\is_array($functions = spl_autoload_functions())) { return; @@ -156,7 +164,7 @@ public function loadClass($class) return; } } else { - \call_user_func($this->classLoader, $class); + ($this->classLoader)($class); $file = false; } } finally { @@ -166,7 +174,7 @@ public function loadClass($class) $this->checkClass($class, $file); } - private function checkClass($class, $file = null) + private function checkClass(string $class, string $file = null) { $exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); @@ -192,10 +200,6 @@ private function checkClass($class, $file = null) $deprecations = $this->checkAnnotations($refl, $name); - if (isset(self::$php7Reserved[strtolower($refl->getShortName())])) { - $deprecations[] = sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName()); - } - foreach ($deprecations as $message) { @trigger_error($message, \E_USER_DEPRECATED); } @@ -237,10 +241,28 @@ public function checkAnnotations(\ReflectionClass $refl, $class) self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : ''; } } + + if ($refl->isInterface() && false !== strpos($doc, 'method') && preg_match_all('#\n \* @method\s+(static\s+)?+(?:[\w\|&\[\]\\\]+\s+)?(\w+(?:\s*\([^\)]*\))?)+(.+?([[:punct:]]\s*)?)?(?=\r?\n \*(?: @|/$|\r?\n))#', $doc, $notice, \PREG_SET_ORDER)) { + foreach ($notice as $method) { + $static = '' !== $method[1]; + $name = $method[2]; + $description = $method[3] ?? null; + if (false === strpos($name, '(')) { + $name .= '()'; + } + if (null !== $description) { + $description = trim($description); + if (!isset($method[4])) { + $description .= '.'; + } + } + self::$method[$class][] = [$class, $name, $static, $description]; + } + } } $parent = get_parent_class($class); - $parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent); + $parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent ?: null); if ($parent) { $parentAndOwnInterfaces[$parent] = $parent; @@ -267,17 +289,40 @@ public function checkAnnotations(\ReflectionClass $refl, $class) if (isset(self::$internal[$use]) && strncmp($ns, str_replace('_', '\\', $use), $len)) { $deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $class); } + if (isset(self::$method[$use])) { + if ($refl->isAbstract()) { + if (isset(self::$method[$class])) { + self::$method[$class] = array_merge(self::$method[$class], self::$method[$use]); + } else { + self::$method[$class] = self::$method[$use]; + } + } elseif (!$refl->isInterface()) { + $hasCall = $refl->hasMethod('__call'); + $hasStaticCall = $refl->hasMethod('__callStatic'); + foreach (self::$method[$use] as $method) { + [$interface, $name, $static, $description] = $method; + if ($static ? $hasStaticCall : $hasCall) { + continue; + } + $realName = substr($name, 0, strpos($name, '(')); + if (!$refl->hasMethod($realName) || !($methodRefl = $refl->getMethod($realName))->isPublic() || ($static && !$methodRefl->isStatic()) || (!$static && $methodRefl->isStatic())) { + $deprecations[] = sprintf('Class "%s" should implement method "%s::%s"%s', $class, ($static ? 'static ' : '').$interface, $name, null == $description ? '.' : ': '.$description); + } + } + } + } } if (trait_exists($class)) { return $deprecations; } - // Inherit @final and @internal annotations for methods + // Inherit @final, @internal and @param annotations for methods self::$finalMethods[$class] = []; self::$internalMethods[$class] = []; + self::$annotatedParameters[$class] = []; foreach ($parentAndOwnInterfaces as $use) { - foreach (['finalMethods', 'internalMethods'] as $property) { + foreach (['finalMethods', 'internalMethods', 'annotatedParameters'] as $property) { if (isset(self::${$property}[$use])) { self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use]; } @@ -290,26 +335,63 @@ public function checkAnnotations(\ReflectionClass $refl, $class) } if ($parent && isset(self::$finalMethods[$parent][$method->name])) { - list($declaringClass, $message) = self::$finalMethods[$parent][$method->name]; + [$declaringClass, $message] = self::$finalMethods[$parent][$method->name]; $deprecations[] = sprintf('The "%s::%s()" method is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class); } if (isset(self::$internalMethods[$class][$method->name])) { - list($declaringClass, $message) = self::$internalMethods[$class][$method->name]; + [$declaringClass, $message] = self::$internalMethods[$class][$method->name]; if (strncmp($ns, $declaringClass, $len)) { $deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $class); } } - // Detect method annotations - if (false === $doc = $method->getDocComment()) { + // To read method annotations + $doc = $method->getDocComment(); + + if (isset(self::$annotatedParameters[$class][$method->name])) { + $definedParameters = []; + foreach ($method->getParameters() as $parameter) { + $definedParameters[$parameter->name] = true; + } + + foreach (self::$annotatedParameters[$class][$method->name] as $parameterName => $deprecation) { + if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\\\${$parameterName}\\b/", $doc))) { + $deprecations[] = sprintf($deprecation, $class); + } + } + } + + if (!$doc) { continue; } + $finalOrInternal = false; + foreach (['final', 'internal'] as $annotation) { if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) { $message = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : ''; self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message]; + $finalOrInternal = true; + } + } + + if ($finalOrInternal || $method->isConstructor() || false === strpos($doc, '@param') || StatelessInvocation::class === $class) { + continue; + } + if (!preg_match_all('#\n\s+\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\$([a-zA-Z0-9_\x7f-\xff]++)#', $doc, $matches, \PREG_SET_ORDER)) { + continue; + } + if (!isset(self::$annotatedParameters[$class][$method->name])) { + $definedParameters = []; + foreach ($method->getParameters() as $parameter) { + $definedParameters[$parameter->name] = true; + } + } + foreach ($matches as [, $parameterType, $parameterName]) { + if (!isset($definedParameters[$parameterName])) { + $parameterType = trim($parameterType); + self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its %s "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, interface_exists($class) ? 'interface' : 'parent class', $method->class); } } } @@ -362,7 +444,7 @@ public function checkCase(\ReflectionClass $refl, $file, $class) /** * `realpath` on MacOSX doesn't normalize the case of characters. */ - private function darwinRealpath($real) + private function darwinRealpath(string $real): string { $i = 1 + strrpos($real, '/'); $file = substr($real, $i); @@ -377,7 +459,11 @@ private function darwinRealpath($real) $real = self::$darwinCache[$kDir][0]; } else { $dir = getcwd(); - chdir($real); + + if (!@chdir($real)) { + return $real.$file; + } + $real = getcwd().'/'; chdir($dir); @@ -429,12 +515,9 @@ private function darwinRealpath($real) /** * `class_implements` includes interfaces from the parents so we have to manually exclude them. * - * @param string $class - * @param string|false $parent - * * @return string[] */ - private function getOwnInterfaces($class, $parent) + private function getOwnInterfaces(string $class, ?string $parent): array { $ownInterfaces = class_implements($class, false); diff --git a/vendor/symfony/debug/ErrorHandler.php b/vendor/symfony/debug/ErrorHandler.php index b8ec09e8..fe425e05 100644 --- a/vendor/symfony/debug/ErrorHandler.php +++ b/vendor/symfony/debug/ErrorHandler.php @@ -13,9 +13,9 @@ use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Symfony\Component\Debug\Exception\ContextErrorException; use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\FatalThrowableError; +use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\Debug\Exception\OutOfMemoryException; use Symfony\Component\Debug\Exception\SilencedErrorContext; use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler; @@ -23,6 +23,8 @@ use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler; use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ErrorHandler::class, \Symfony\Component\ErrorHandler\ErrorHandler::class), \E_USER_DEPRECATED); + /** * A generic ErrorHandler for the PHP engine. * @@ -45,6 +47,10 @@ * * @author Nicolas Grekas * @author Grégoire Pineau + * + * @final since Symfony 4.3 + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\ErrorHandler instead. */ class ErrorHandler { @@ -97,8 +103,6 @@ class ErrorHandler private $bootstrappingLogger; private static $reservedMemory; - private static $stackedErrors = []; - private static $stackedErrorLevels = []; private static $toStringException = null; private static $silencedErrorCache = []; private static $silencedErrorCount = 0; @@ -115,7 +119,7 @@ class ErrorHandler public static function register(self $handler = null, $replace = true) { if (null === self::$reservedMemory) { - self::$reservedMemory = str_repeat('x', 10240); + self::$reservedMemory = str_repeat('x', 32768); register_shutdown_function(__CLASS__.'::handleFatalError'); } @@ -165,16 +169,15 @@ public function __construct(BufferingLogger $bootstrappingLogger = null) $this->bootstrappingLogger = $bootstrappingLogger; $this->setDefaultLogger($bootstrappingLogger); } - $this->traceReflector = new \ReflectionProperty('Exception', 'trace'); + $this->traceReflector = new \ReflectionProperty(\Exception::class, 'trace'); $this->traceReflector->setAccessible(true); } /** * Sets a logger to non assigned errors levels. * - * @param LoggerInterface $logger A PSR-3 logger to put as default for the given levels - * @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants - * @param bool $replace Whether to replace or not any existing logger + * @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants + * @param bool $replace Whether to replace or not any existing logger */ public function setDefaultLogger(LoggerInterface $logger, $levels = \E_ALL, $replace = false) { @@ -349,10 +352,10 @@ public function screamAt($levels, $replace = false) /** * Re-registers as a PHP error handler if levels changed. */ - private function reRegister($prev) + private function reRegister(int $prev) { - if ($prev !== $this->thrownErrors | $this->loggedErrors) { - $handler = set_error_handler('var_dump'); + if ($prev !== ($this->thrownErrors | $this->loggedErrors)) { + $handler = set_error_handler('is_int'); $handler = \is_array($handler) ? $handler[0] : null; restore_error_handler(); if ($handler === $this) { @@ -400,38 +403,19 @@ public function handleError($type, $message, $file, $line) } $scope = $this->scopedErrors & $type; - if (4 < $numArgs = \func_num_args()) { - $context = func_get_arg(4) ?: []; - $backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM + if (false !== strpos($message, "@anonymous\0")) { + $logMessage = $this->levels[$type].': '.(new FlattenException())->setMessage($message)->getMessage(); } else { - $context = []; - $backtrace = null; - } - - if (isset($context['GLOBALS']) && $scope) { - $e = $context; // Whatever the signature of the method, - unset($e['GLOBALS'], $context); // $context is always a reference in 5.3 - $context = $e; - } - - if (null !== $backtrace && $type & \E_ERROR) { - // E_ERROR fatal errors are triggered on HHVM when - // hhvm.error_handling.call_user_handler_on_fatals=1 - // which is the way to get their backtrace. - $this->handleFatalError(compact('type', 'message', 'file', 'line', 'backtrace')); - - return true; + $logMessage = $this->levels[$type].': '.$message; } - $logMessage = $this->levels[$type].': '.$message; - if (null !== self::$toStringException) { $errorAsException = self::$toStringException; self::$toStringException = null; } elseif (!$throw && !($type & $level)) { if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) { - $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : []; - $errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace); + $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5), $type, $file, $line, false) : []; + $errorAsException = new SilencedErrorContext($type, $file, $line, isset($lightTrace[1]) ? [$lightTrace[0]] : $lightTrace); } elseif (isset(self::$silencedErrorCache[$id][$message])) { $lightTrace = null; $errorAsException = self::$silencedErrorCache[$id][$message]; @@ -452,19 +436,15 @@ public function handleError($type, $message, $file, $line) return true; } } else { - if ($scope) { - $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context); - } else { - $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); - } + $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); - // Clean the trace by removing function arguments and the first frames added by the error handler itself. if ($throw || $this->tracedErrors & $type) { - $backtrace = $backtrace ?: $errorAsException->getTrace(); + $backtrace = $errorAsException->getTrace(); $lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw); $this->traceReflector->setValue($errorAsException, $lightTrace); } else { $this->traceReflector->setValue($errorAsException, []); + $backtrace = []; } } @@ -478,32 +458,27 @@ public function handleError($type, $message, $file, $line) && ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function']) ) { // Here, we know trigger_error() has been called from __toString(). - // HHVM is fine with throwing from __toString() but PHP triggers a fatal error instead. + // PHP triggers a fatal error when throwing from __toString(). // A small convention allows working around the limitation: // given a caught $e exception in __toString(), quitting the method with // `return trigger_error($e, E_USER_ERROR);` allows this error handler // to make $e get through the __toString() barrier. + $context = 4 < \func_num_args() ? (func_get_arg(4) ?: []) : []; + foreach ($context as $e) { - if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) { - if (1 === $i) { - // On HHVM - $errorAsException = $e; - break; - } + if ($e instanceof \Throwable && $e->__toString() === $message) { self::$toStringException = $e; return true; } } - if (1 < $i) { - // On PHP (not on HHVM), display the original error message instead of the default one. - $this->handleException($errorAsException); + // Display the original error message instead of the default one. + $this->handleException($errorAsException); - // Stop the process by giving back the error to the native handler. - return false; - } + // Stop the process by giving back the error to the native handler. + return false; } } } @@ -513,16 +488,9 @@ public function handleError($type, $message, $file, $line) if ($this->isRecursive) { $log = 0; - } elseif (self::$stackedErrorLevels) { - self::$stackedErrors[] = [ - $this->loggers[$type][0], - ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, - $logMessage, - $errorAsException ? ['exception' => $errorAsException] : [], - ]; } else { - if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) { - $currentErrorHandler = set_error_handler('var_dump'); + if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) { + $currentErrorHandler = set_error_handler('is_int'); restore_error_handler(); } @@ -533,7 +501,7 @@ public function handleError($type, $message, $file, $line) } finally { $this->isRecursive = false; - if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404) && !\defined('HHVM_VERSION')) { + if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) { set_error_handler($currentErrorHandler); } } @@ -562,27 +530,29 @@ public function handleException($exception, array $error = null) $handlerException = null; if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) { + if (false !== strpos($message = $exception->getMessage(), "@anonymous\0")) { + $message = (new FlattenException())->setMessage($message)->getMessage(); + } if ($exception instanceof FatalErrorException) { if ($exception instanceof FatalThrowableError) { $error = [ 'type' => $type, - 'message' => $message = $exception->getMessage(), + 'message' => $message, 'file' => $exception->getFile(), 'line' => $exception->getLine(), ]; } else { - $message = 'Fatal '.$exception->getMessage(); + $message = 'Fatal '.$message; } } elseif ($exception instanceof \ErrorException) { - $message = 'Uncaught '.$exception->getMessage(); + $message = 'Uncaught '.$message; } else { - $message = 'Uncaught Exception: '.$exception->getMessage(); + $message = 'Uncaught Exception: '.$message; } } if ($this->loggedErrors & $type) { try { $this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]); - } catch (\Exception $handlerException) { } catch (\Throwable $handlerException) { } } @@ -603,7 +573,6 @@ public function handleException($exception, array $error = null) return; } $handlerException = $handlerException ?: $exception; - } catch (\Exception $handlerException) { } catch (\Throwable $handlerException) { } if ($exception === $handlerException) { @@ -632,7 +601,7 @@ public static function handleFatalError(array $error = null) $sameHandlerLimit = 10; while (!\is_array($handler) || !$handler[0] instanceof self) { - $handler = set_exception_handler('var_dump'); + $handler = set_exception_handler('is_int'); restore_exception_handler(); if (!$handler) { @@ -664,30 +633,22 @@ public static function handleFatalError(array $error = null) $error = error_get_last(); } - try { - while (self::$stackedErrorLevels) { - static::unstackErrors(); - } - } catch (\Exception $exception) { - // Handled below - } catch (\Throwable $exception) { - // Handled below - } - if ($error && $error['type'] &= \E_PARSE | \E_ERROR | \E_CORE_ERROR | \E_COMPILE_ERROR) { // Let's not throw anymore but keep logging $handler->throwAt(0, true); - $trace = isset($error['backtrace']) ? $error['backtrace'] : null; + $trace = $error['backtrace'] ?? null; if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) { $exception = new OutOfMemoryException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, false, $trace); } else { $exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace); } + } else { + $exception = null; } try { - if (isset($exception)) { + if (null !== $exception) { self::$exitCode = 255; $handler->handleException($exception, $error); } @@ -701,55 +662,6 @@ public static function handleFatalError(array $error = null) } } - /** - * Configures the error handler for delayed handling. - * Ensures also that non-catchable fatal errors are never silenced. - * - * As shown by http://bugs.php.net/42098 and http://bugs.php.net/60724 - * PHP has a compile stage where it behaves unusually. To workaround it, - * we plug an error handler that only stacks errors for later. - * - * The most important feature of this is to prevent - * autoloading until unstackErrors() is called. - * - * @deprecated since version 3.4, to be removed in 4.0. - */ - public static function stackErrors() - { - @trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', \E_USER_DEPRECATED); - - self::$stackedErrorLevels[] = error_reporting(error_reporting() | \E_PARSE | \E_ERROR | \E_CORE_ERROR | \E_COMPILE_ERROR); - } - - /** - * Unstacks stacked errors and forwards to the logger. - * - * @deprecated since version 3.4, to be removed in 4.0. - */ - public static function unstackErrors() - { - @trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', \E_USER_DEPRECATED); - - $level = array_pop(self::$stackedErrorLevels); - - if (null !== $level) { - $errorReportingLevel = error_reporting($level); - if ($errorReportingLevel !== ($level | \E_PARSE | \E_ERROR | \E_CORE_ERROR | \E_COMPILE_ERROR)) { - // If the user changed the error level, do not overwrite it - error_reporting($errorReportingLevel); - } - } - - if (empty(self::$stackedErrorLevels)) { - $errors = self::$stackedErrors; - self::$stackedErrors = []; - - foreach ($errors as $error) { - $error[0]->log($error[1], $error[2], $error[3]); - } - } - } - /** * Gets the fatal error handlers. * @@ -766,7 +678,10 @@ protected function getFatalErrorHandlers() ]; } - private function cleanTrace($backtrace, $type, $file, $line, $throw) + /** + * Cleans the trace by removing function arguments and the frames added by the error handler and DebugClassLoader. + */ + private function cleanTrace(array $backtrace, int $type, string $file, int $line, bool $throw): array { $lightTrace = $backtrace; @@ -776,6 +691,13 @@ private function cleanTrace($backtrace, $type, $file, $line, $throw) break; } } + if (class_exists(DebugClassLoader::class, false)) { + for ($i = \count($lightTrace) - 2; 0 < $i; --$i) { + if (DebugClassLoader::class === ($lightTrace[$i]['class'] ?? null)) { + array_splice($lightTrace, --$i, 2); + } + } + } if (!($throw || $this->scopedErrors & $type)) { for ($i = 0; isset($lightTrace[$i]); ++$i) { unset($lightTrace[$i]['args'], $lightTrace[$i]['object']); diff --git a/vendor/symfony/debug/Exception/ClassNotFoundException.php b/vendor/symfony/debug/Exception/ClassNotFoundException.php index de5c4564..998e4a98 100644 --- a/vendor/symfony/debug/Exception/ClassNotFoundException.php +++ b/vendor/symfony/debug/Exception/ClassNotFoundException.php @@ -11,14 +11,18 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ClassNotFoundException::class, \Symfony\Component\ErrorHandler\Error\ClassNotFoundError::class), \E_USER_DEPRECATED); + /** * Class (or Trait or Interface) Not Found Exception. * * @author Konstanton Myakshin + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\ClassNotFoundError instead. */ class ClassNotFoundException extends FatalErrorException { - public function __construct($message, \ErrorException $previous) + public function __construct(string $message, \ErrorException $previous) { parent::__construct( $message, diff --git a/vendor/symfony/debug/Exception/ContextErrorException.php b/vendor/symfony/debug/Exception/ContextErrorException.php deleted file mode 100644 index 4b49f0af..00000000 --- a/vendor/symfony/debug/Exception/ContextErrorException.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Exception; - -/** - * Error Exception with Variable Context. - * - * @author Christian Sciberras - * - * @deprecated since version 3.3. Instead, \ErrorException will be used directly in 4.0. - */ -class ContextErrorException extends \ErrorException -{ - private $context = []; - - public function __construct($message, $code, $severity, $filename, $lineno, $context = []) - { - parent::__construct($message, $code, $severity, $filename, $lineno); - $this->context = $context; - } - - /** - * @return array Array of variables that existed when the exception occurred - */ - public function getContext() - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), \E_USER_DEPRECATED); - - return $this->context; - } -} diff --git a/vendor/symfony/debug/Exception/FatalErrorException.php b/vendor/symfony/debug/Exception/FatalErrorException.php index 0f70ef92..fbdad4c5 100644 --- a/vendor/symfony/debug/Exception/FatalErrorException.php +++ b/vendor/symfony/debug/Exception/FatalErrorException.php @@ -11,14 +11,18 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalErrorException::class, \Symfony\Component\ErrorHandler\Error\FatalError::class), \E_USER_DEPRECATED); + /** * Fatal Error Exception. * * @author Konstanton Myakshin + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\FatalError instead. */ class FatalErrorException extends \ErrorException { - public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null) + public function __construct(string $message, int $code, int $severity, string $filename, int $lineno, int $traceOffset = null, bool $traceArgs = true, array $trace = null, \Throwable $previous = null) { parent::__construct($message, $code, $severity, $filename, $lineno, $previous); @@ -31,8 +35,7 @@ public function __construct($message, $code, $severity, $filename, $lineno, $tra $this->setTrace($trace); } elseif (null !== $traceOffset) { - if (\function_exists('xdebug_get_function_stack')) { - $trace = xdebug_get_function_stack(); + if (\function_exists('xdebug_get_function_stack') && $trace = @xdebug_get_function_stack()) { if (0 < $traceOffset) { array_splice($trace, -$traceOffset); } @@ -60,11 +63,6 @@ public function __construct($message, $code, $severity, $filename, $lineno, $tra unset($frame); $trace = array_reverse($trace); - } elseif (\function_exists('symfony_debug_backtrace')) { - $trace = symfony_debug_backtrace(); - if (0 < $traceOffset) { - array_splice($trace, 0, $traceOffset); - } } else { $trace = []; } @@ -75,7 +73,7 @@ public function __construct($message, $code, $severity, $filename, $lineno, $tra protected function setTrace($trace) { - $traceReflector = new \ReflectionProperty('Exception', 'trace'); + $traceReflector = new \ReflectionProperty(\Exception::class, 'trace'); $traceReflector->setAccessible(true); $traceReflector->setValue($this, $trace); } diff --git a/vendor/symfony/debug/Exception/FatalThrowableError.php b/vendor/symfony/debug/Exception/FatalThrowableError.php index a44f65f0..6c9ecb85 100644 --- a/vendor/symfony/debug/Exception/FatalThrowableError.php +++ b/vendor/symfony/debug/Exception/FatalThrowableError.php @@ -11,28 +11,33 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4.', FatalThrowableError::class), \E_USER_DEPRECATED); + /** * Fatal Throwable Error. * * @author Nicolas Grekas + * + * @deprecated since Symfony 4.4 */ class FatalThrowableError extends FatalErrorException { + private $originalClassName; + public function __construct(\Throwable $e) { + $this->originalClassName = \get_class($e); + if ($e instanceof \ParseError) { - $message = 'Parse error: '.$e->getMessage(); $severity = \E_PARSE; } elseif ($e instanceof \TypeError) { - $message = 'Type error: '.$e->getMessage(); $severity = \E_RECOVERABLE_ERROR; } else { - $message = $e->getMessage(); $severity = \E_ERROR; } \ErrorException::__construct( - $message, + $e->getMessage(), $e->getCode(), $severity, $e->getFile(), @@ -42,4 +47,9 @@ public function __construct(\Throwable $e) $this->setTrace($e->getTrace()); } + + public function getOriginalClassName(): string + { + return $this->originalClassName; + } } diff --git a/vendor/symfony/debug/Exception/FlattenException.php b/vendor/symfony/debug/Exception/FlattenException.php index 9514bdc5..dbf0ed8f 100644 --- a/vendor/symfony/debug/Exception/FlattenException.php +++ b/vendor/symfony/debug/Exception/FlattenException.php @@ -15,11 +15,13 @@ use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; /** - * FlattenException wraps a PHP Exception to be able to serialize it. + * FlattenException wraps a PHP Error or Exception to be able to serialize it. * * Basically, this class removes all objects from the trace. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\FlattenException instead. */ class FlattenException { @@ -27,13 +29,25 @@ class FlattenException private $code; private $previous; private $trace; + private $traceAsString; private $class; private $statusCode; private $headers; private $file; private $line; + /** + * @return static + */ public static function create(\Exception $exception, $statusCode = null, array $headers = []) + { + return static::createFromThrowable($exception, $statusCode, $headers); + } + + /** + * @return static + */ + public static function createFromThrowable(\Throwable $exception, int $statusCode = null, array $headers = []) { $e = new static(); $e->setMessage($exception->getMessage()); @@ -52,17 +66,15 @@ public static function create(\Exception $exception, $statusCode = null, array $ $e->setStatusCode($statusCode); $e->setHeaders($headers); - $e->setTraceFromException($exception); - $e->setClass(\get_class($exception)); + $e->setTraceFromThrowable($exception); + $e->setClass($exception instanceof FatalThrowableError ? $exception->getOriginalClassName() : \get_class($exception)); $e->setFile($exception->getFile()); $e->setLine($exception->getLine()); $previous = $exception->getPrevious(); - if ($previous instanceof \Exception) { - $e->setPrevious(static::create($previous)); - } elseif ($previous instanceof \Throwable) { - $e->setPrevious(static::create(new FatalThrowableError($previous))); + if ($previous instanceof \Throwable) { + $e->setPrevious(static::createFromThrowable($previous)); } return $e; @@ -87,9 +99,14 @@ public function getStatusCode() return $this->statusCode; } + /** + * @return $this + */ public function setStatusCode($code) { $this->statusCode = $code; + + return $this; } public function getHeaders() @@ -97,9 +114,14 @@ public function getHeaders() return $this->headers; } + /** + * @return $this + */ public function setHeaders(array $headers) { $this->headers = $headers; + + return $this; } public function getClass() @@ -107,9 +129,14 @@ public function getClass() return $this->class; } + /** + * @return $this + */ public function setClass($class) { - $this->class = $class; + $this->class = false !== strpos($class, "@anonymous\0") ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' : $class; + + return $this; } public function getFile() @@ -117,9 +144,14 @@ public function getFile() return $this->file; } + /** + * @return $this + */ public function setFile($file) { $this->file = $file; + + return $this; } public function getLine() @@ -127,9 +159,14 @@ public function getLine() return $this->line; } + /** + * @return $this + */ public function setLine($line) { $this->line = $line; + + return $this; } public function getMessage() @@ -137,9 +174,20 @@ public function getMessage() return $this->message; } + /** + * @return $this + */ public function setMessage($message) { + if (false !== strpos($message, "@anonymous\0")) { + $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $message); + } + $this->message = $message; + + return $this; } public function getCode() @@ -147,9 +195,14 @@ public function getCode() return $this->code; } + /** + * @return $this + */ public function setCode($code) { $this->code = $code; + + return $this; } public function getPrevious() @@ -157,9 +210,14 @@ public function getPrevious() return $this->previous; } + /** + * @return $this + */ public function setPrevious(self $previous) { $this->previous = $previous; + + return $this; } public function getAllPrevious() @@ -178,11 +236,26 @@ public function getTrace() return $this->trace; } + /** + * @deprecated since 4.1, use {@see setTraceFromThrowable()} instead. + */ public function setTraceFromException(\Exception $exception) { - $this->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine()); + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED); + + $this->setTraceFromThrowable($exception); + } + + public function setTraceFromThrowable(\Throwable $throwable) + { + $this->traceAsString = $throwable->getTraceAsString(); + + return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine()); } + /** + * @return $this + */ public function setTrace($trace, $file, $line) { $this->trace = []; @@ -208,17 +281,19 @@ public function setTrace($trace, $file, $line) $this->trace[] = [ 'namespace' => $namespace, 'short_class' => $class, - 'class' => isset($entry['class']) ? $entry['class'] : '', - 'type' => isset($entry['type']) ? $entry['type'] : '', - 'function' => isset($entry['function']) ? $entry['function'] : null, - 'file' => isset($entry['file']) ? $entry['file'] : null, - 'line' => isset($entry['line']) ? $entry['line'] : null, + 'class' => $entry['class'] ?? '', + 'type' => $entry['type'] ?? '', + 'function' => $entry['function'] ?? null, + 'file' => $entry['file'] ?? null, + 'line' => $entry['line'] ?? null, 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : [], ]; } + + return $this; } - private function flattenArgs($args, $level = 0, &$count = 0) + private function flattenArgs(array $args, int $level = 0, int &$count = 0): array { $result = []; foreach ($args as $key => $value) { @@ -254,10 +329,39 @@ private function flattenArgs($args, $level = 0, &$count = 0) return $result; } - private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value) + private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value): string { $array = new \ArrayObject($value); return $array['__PHP_Incomplete_Class_Name']; } + + public function getTraceAsString() + { + return $this->traceAsString; + } + + public function getAsString() + { + $message = ''; + $next = false; + + foreach (array_reverse(array_merge([$this], $this->getAllPrevious())) as $exception) { + if ($next) { + $message .= 'Next '; + } else { + $next = true; + } + $message .= $exception->getClass(); + + if ('' != $exception->getMessage()) { + $message .= ': '.$exception->getMessage(); + } + + $message .= ' in '.$exception->getFile().':'.$exception->getLine(). + "\nStack trace:\n".$exception->getTraceAsString()."\n\n"; + } + + return rtrim($message); + } } diff --git a/vendor/symfony/debug/Exception/OutOfMemoryException.php b/vendor/symfony/debug/Exception/OutOfMemoryException.php index fec19798..b1dc0ef4 100644 --- a/vendor/symfony/debug/Exception/OutOfMemoryException.php +++ b/vendor/symfony/debug/Exception/OutOfMemoryException.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', OutOfMemoryException::class, \Symfony\Component\ErrorHandler\Error\OutOfMemoryError::class), \E_USER_DEPRECATED); + /** * Out of memory exception. * * @author Nicolas Grekas + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\OutOfMemoryError instead. */ class OutOfMemoryException extends FatalErrorException { diff --git a/vendor/symfony/debug/Exception/SilencedErrorContext.php b/vendor/symfony/debug/Exception/SilencedErrorContext.php index 2bacfd5c..03e2fb30 100644 --- a/vendor/symfony/debug/Exception/SilencedErrorContext.php +++ b/vendor/symfony/debug/Exception/SilencedErrorContext.php @@ -11,10 +11,14 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', SilencedErrorContext::class, \Symfony\Component\ErrorHandler\Exception\SilencedErrorContext::class), \E_USER_DEPRECATED); + /** * Data Object that represents a Silenced Error. * * @author Grégoire Pineau + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext instead. */ class SilencedErrorContext implements \JsonSerializable { @@ -25,7 +29,7 @@ class SilencedErrorContext implements \JsonSerializable private $line; private $trace; - public function __construct($severity, $file, $line, array $trace = [], $count = 1) + public function __construct(int $severity, string $file, int $line, array $trace = [], int $count = 1) { $this->severity = $severity; $this->file = $file; diff --git a/vendor/symfony/debug/Exception/UndefinedFunctionException.php b/vendor/symfony/debug/Exception/UndefinedFunctionException.php index 8f5f454e..42ab2ec9 100644 --- a/vendor/symfony/debug/Exception/UndefinedFunctionException.php +++ b/vendor/symfony/debug/Exception/UndefinedFunctionException.php @@ -11,14 +11,18 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedFunctionException::class, \Symfony\Component\ErrorHandler\Error\UndefinedFunctionError::class), \E_USER_DEPRECATED); + /** * Undefined Function Exception. * * @author Konstanton Myakshin + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\UndefinedFunctionError instead. */ class UndefinedFunctionException extends FatalErrorException { - public function __construct($message, \ErrorException $previous) + public function __construct(string $message, \ErrorException $previous) { parent::__construct( $message, diff --git a/vendor/symfony/debug/Exception/UndefinedMethodException.php b/vendor/symfony/debug/Exception/UndefinedMethodException.php index f7e340ba..d72046f3 100644 --- a/vendor/symfony/debug/Exception/UndefinedMethodException.php +++ b/vendor/symfony/debug/Exception/UndefinedMethodException.php @@ -11,14 +11,18 @@ namespace Symfony\Component\Debug\Exception; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedMethodException::class, \Symfony\Component\ErrorHandler\Error\UndefinedMethodError::class), \E_USER_DEPRECATED); + /** * Undefined Method Exception. * * @author Grégoire Pineau + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\Error\UndefinedMethodError instead. */ class UndefinedMethodException extends FatalErrorException { - public function __construct($message, \ErrorException $previous) + public function __construct(string $message, \ErrorException $previous) { parent::__construct( $message, diff --git a/vendor/symfony/debug/ExceptionHandler.php b/vendor/symfony/debug/ExceptionHandler.php index 7cf3f2a6..fd8a7fd5 100644 --- a/vendor/symfony/debug/ExceptionHandler.php +++ b/vendor/symfony/debug/ExceptionHandler.php @@ -15,6 +15,8 @@ use Symfony\Component\Debug\Exception\OutOfMemoryException; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ExceptionHandler::class, \Symfony\Component\ErrorHandler\ErrorHandler::class), \E_USER_DEPRECATED); + /** * ExceptionHandler converts an exception to a Response object. * @@ -26,9 +28,23 @@ * * @author Fabien Potencier * @author Nicolas Grekas + * + * @final since Symfony 4.3 + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\ErrorHandler instead. */ class ExceptionHandler { + private const GHOST_ADDONS = [ + '02-14' => self::GHOST_HEART, + '02-29' => self::GHOST_PLUS, + '10-18' => self::GHOST_GIFT, + ]; + + private const GHOST_GIFT = 'M124.005 5.36c.396-.715 1.119-1.648-.124-1.873-.346-.177-.692-.492-1.038-.141-.769.303-1.435.728-.627 1.523.36.514.685 1.634 1.092 1.758.242-.417.47-.842.697-1.266zm-1.699 1.977c-.706-1.26-1.274-2.612-2.138-3.774-1.051-1.123-3.122-.622-3.593.825-.625 1.431.724 3.14 2.251 2.96 1.159.02 2.324.072 3.48-.011zm5.867.043c1.502-.202 2.365-2.092 1.51-3.347-.757-1.34-2.937-1.387-3.698-.025-.659 1.1-1.23 2.25-1.835 3.38 1.336.077 2.686.06 4.023-.008zm2.487 1.611c.512-.45 2.494-.981.993-1.409-.372-.105-.805-.59-1.14-.457-.726.902-1.842 1.432-3.007 1.376-.228.075-1.391-.114-1.077.1.822.47 1.623.979 2.474 1.395.595-.317 1.173-.667 1.757-1.005zm-11.696.255l1.314-.765c-1.338-.066-2.87.127-3.881-.95-.285-.319-.559-.684-.954-.282-.473.326-1.929.66-.808 1.058.976.576 1.945 1.167 2.946 1.701.476-.223.926-.503 1.383-.762zm6.416 2.846c.567-.456 1.942-.89 1.987-1.38-1.282-.737-2.527-1.56-3.87-2.183-.461-.175-.835.094-1.207.328-1.1.654-2.225 1.267-3.288 1.978 1.39.86 2.798 1.695 4.219 2.504.725-.407 1.44-.83 2.16-1.247zm5.692 1.423l1.765-1.114c-.005-1.244.015-2.488-.019-3.732a77.306 77.306 0 0 0-3.51 2.084c-.126 1.282-.062 2.586-.034 3.876.607-.358 1.2-.741 1.798-1.114zm-13.804-.784c.06-1.06.19-2.269-1.09-2.583-.807-.376-1.926-1.341-2.548-1.332-.02 1.195-.01 2.39-.011 3.585 1.192.744 2.364 1.524 3.582 2.226.119-.616.041-1.269.067-1.896zm8.541 4.105l2.117-1.336c-.003-1.284.05-2.57-.008-3.853-.776.223-1.662.91-2.48 1.337l-1.834 1.075c.012 1.37-.033 2.744.044 4.113.732-.427 1.443-.887 2.161-1.336zm-2.957-.72v-2.057c-1.416-.828-2.828-1.664-4.25-2.482-.078 1.311-.033 2.627-.045 3.94 1.416.887 2.817 1.798 4.25 2.655.057-.683.036-1.372.045-2.057zm8.255 2.755l1.731-1.153c-.024-1.218.06-2.453-.062-3.658-1.2.685-2.358 1.464-3.537 2.195.028 1.261-.058 2.536.072 3.786.609-.373 1.2-.777 1.796-1.17zm-13.851-.683l-.014-1.916c-1.193-.746-2.37-1.517-3.58-2.234-.076 1.224-.033 2.453-.044 3.679 1.203.796 2.392 1.614 3.61 2.385.048-.636.024-1.276.028-1.914zm8.584 4.199l2.102-1.396c-.002-1.298.024-2.596-.01-3.893-1.427.88-2.843 1.775-4.25 2.686-.158 1.253-.055 2.545-.056 3.811.437.266 1.553-.912 2.214-1.208zm-2.988-.556c-.085-.894.365-2.154-.773-2.5-1.146-.727-2.288-1.46-3.45-2.163-.17 1.228.008 2.508-.122 3.751a79.399 79.399 0 0 0 4.278 2.885c.117-.641.044-1.32.067-1.973zm-4.872-.236l-5.087-3.396c.002-3.493-.047-6.988.015-10.48.85-.524 1.753-.954 2.627-1.434-.564-1.616.25-3.58 1.887-4.184 1.372-.563 3.025-.055 3.9 1.13l1.906-.978 1.916.987c.915-1.086 2.483-1.706 3.842-1.097 1.631.573 2.52 2.532 1.936 4.145.88.497 1.837.886 2.644 1.492.036 3.473 0 6.946-.003 10.419-3.374 2.233-6.693 4.55-10.122 6.699-.997 0-1.858-1.083-2.783-1.522a735.316 735.316 0 0 1-2.678-1.781z'; + private const GHOST_HEART = 'M125.914 8.305c3.036-8.71 14.933 0 0 11.2-14.932-11.2-3.036-19.91 0-11.2z'; + private const GHOST_PLUS = 'M111.368 8.97h7.324V1.645h7.512v7.323h7.324v7.513h-7.324v7.323h-7.512v-7.323h-7.324z'; + private $debug; private $charset; private $handler; @@ -36,10 +52,10 @@ class ExceptionHandler private $caughtLength; private $fileLinkFormat; - public function __construct($debug = true, $charset = null, $fileLinkFormat = null) + public function __construct(bool $debug = true, string $charset = null, $fileLinkFormat = null) { $this->debug = $debug; - $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8'; + $this->charset = $charset ?: \ini_get('default_charset') ?: 'UTF-8'; $this->fileLinkFormat = $fileLinkFormat; } @@ -142,7 +158,7 @@ public function handle(\Exception $exception) $this->caughtBuffer = null; try { - \call_user_func($this->handler, $exception); + ($this->handler)($exception); $this->caughtLength = $caughtLength; } catch (\Exception $e) { if (!$caughtLength) { @@ -158,12 +174,12 @@ public function handle(\Exception $exception) * This method uses plain PHP functions like header() and echo to output * the response. * - * @param \Exception|FlattenException $exception An \Exception or FlattenException instance + * @param \Throwable|FlattenException $exception A \Throwable or FlattenException instance */ public function sendPhpResponse($exception) { - if (!$exception instanceof FlattenException) { - $exception = FlattenException::create($exception); + if ($exception instanceof \Throwable) { + $exception = FlattenException::createFromThrowable($exception); } if (!headers_sent()) { @@ -205,7 +221,7 @@ public function getContent(FlattenException $exception) $title = 'Sorry, the page you are looking for could not be found.'; break; default: - $title = 'Whoops, looks like something went wrong.'; + $title = $this->debug ? $this->escapeHtml($exception->getMessage()) : 'Whoops, looks like something went wrong.'; } if (!$this->debug) { @@ -240,7 +256,11 @@ public function getContent(FlattenException $exception) foreach ($e['trace'] as $trace) { $content .= ''; if ($trace['function']) { - $content .= sprintf('at %s%s%s(%s)', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args'])); + $content .= sprintf('at %s%s%s', $this->formatClass($trace['class']), $trace['type'], $trace['function']); + + if (isset($trace['args'])) { + $content .= sprintf('(%s)', $this->formatArgs($trace['args'])); + } } if (isset($trace['file']) && isset($trace['line'])) { $content .= $this->formatPath($trace['file'], $trace['line']); @@ -253,7 +273,8 @@ public function getContent(FlattenException $exception) } catch (\Exception $e) { // something nasty happened and we cannot throw an exception anymore if ($this->debug) { - $title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage())); + $e = FlattenException::create($e); + $title = sprintf('Exception thrown when handling an exception (%s: %s)', $e->getClass(), $this->escapeHtml($e->getMessage())); } else { $title = 'Whoops, looks like something went wrong.'; } @@ -342,7 +363,7 @@ public function getStylesheet(FlattenException $exception) EOF; } - private function decorate($content, $css) + private function decorate(string $content, string $css): string { return << @@ -359,17 +380,17 @@ private function decorate($content, $css) EOF; } - private function formatClass($class) + private function formatClass(string $class): string { $parts = explode('\\', $class); return sprintf('%s', $class, array_pop($parts)); } - private function formatPath($path, $line) + private function formatPath(string $path, int $line): string { $file = $this->escapeHtml(preg_match('#[^/\\\\]*+$#', $path, $file) ? $file[0] : $path); - $fmt = $this->fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); + $fmt = $this->fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); if (!$fmt) { return sprintf('in %s%s', $this->escapeHtml($path), $file, 0 < $line ? ' line '.$line : ''); @@ -400,12 +421,8 @@ private function formatPath($path, $line) /** * Formats an array as a string. - * - * @param array $args The argument array - * - * @return string */ - private function formatArgs(array $args) + private function formatArgs(array $args): string { $result = []; foreach ($args as $key => $item) { @@ -432,13 +449,22 @@ private function formatArgs(array $args) /** * HTML-encodes a string. */ - private function escapeHtml($str) + private function escapeHtml(string $str): string { return htmlspecialchars($str, \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset); } - private function getSymfonyGhostAsSvg() + private function getSymfonyGhostAsSvg(): string { - return ''; + return ''.$this->addElementToGhost().''; + } + + private function addElementToGhost(): string + { + if (!isset(self::GHOST_ADDONS[date('m-d')])) { + return ''; + } + + return ''; } } diff --git a/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php index b1216fe7..64d75513 100644 --- a/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php @@ -17,10 +17,14 @@ use Symfony\Component\Debug\Exception\ClassNotFoundException; use Symfony\Component\Debug\Exception\FatalErrorException; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', ClassNotFoundFatalErrorHandler::class, \Symfony\Component\ErrorHandler\FatalErrorHandler\ClassNotFoundFatalErrorHandler::class), \E_USER_DEPRECATED); + /** * ErrorHandler for classes that do not exist. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\FatalErrorHandler\ClassNotFoundFatalErrorHandler instead. */ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface { @@ -69,7 +73,7 @@ public function handleError(array $error, FatalErrorException $exception) * * @return array An array of possible fully qualified class names */ - private function getClassCandidates($class) + private function getClassCandidates(string $class): array { if (!\is_array($functions = spl_autoload_functions())) { return []; @@ -110,14 +114,7 @@ private function getClassCandidates($class) return array_unique($classes); } - /** - * @param string $path - * @param string $class - * @param string $prefix - * - * @return array - */ - private function findClassInPath($path, $class, $prefix) + private function findClassInPath(string $path, string $class, string $prefix): array { if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) { return []; @@ -134,14 +131,7 @@ private function findClassInPath($path, $class, $prefix) return $classes; } - /** - * @param string $path - * @param string $file - * @param string $prefix - * - * @return string|null - */ - private function convertFileToClass($path, $file, $prefix) + private function convertFileToClass(string $path, string $file, string $prefix): ?string { $candidates = [ // namespaced class @@ -186,12 +176,7 @@ private function convertFileToClass($path, $file, $prefix) return null; } - /** - * @param string $class - * - * @return bool - */ - private function classExists($class) + private function classExists(string $class): bool { return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); } diff --git a/vendor/symfony/debug/FatalErrorHandler/FatalErrorHandlerInterface.php b/vendor/symfony/debug/FatalErrorHandler/FatalErrorHandlerInterface.php index 6b87eb30..cc7a0ffa 100644 --- a/vendor/symfony/debug/FatalErrorHandler/FatalErrorHandlerInterface.php +++ b/vendor/symfony/debug/FatalErrorHandler/FatalErrorHandlerInterface.php @@ -13,18 +13,21 @@ use Symfony\Component\Debug\Exception\FatalErrorException; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', FatalErrorHandlerInterface::class, \Symfony\Component\ErrorHandler\FatalErrorHandler\FatalErrorHandlerInterface::class), \E_USER_DEPRECATED); + /** * Attempts to convert fatal errors to exceptions. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\FatalErrorHandler\FatalErrorHandlerInterface instead. */ interface FatalErrorHandlerInterface { /** * Attempts to convert an error into an exception. * - * @param array $error An array as returned by error_get_last() - * @param FatalErrorException $exception A FatalErrorException instance + * @param array $error An array as returned by error_get_last() * * @return FatalErrorException|null A FatalErrorException instance if the class is able to convert the error, null otherwise */ diff --git a/vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php b/vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php index 77fc7aa2..95096a9c 100644 --- a/vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php +++ b/vendor/symfony/debug/FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php @@ -14,10 +14,14 @@ use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\UndefinedFunctionException; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedFunctionFatalErrorHandler::class, \Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer::class), \E_USER_DEPRECATED); + /** * ErrorHandler for undefined functions. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer instead. */ class UndefinedFunctionFatalErrorHandler implements FatalErrorHandlerInterface { diff --git a/vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php b/vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php index ff2843b6..4f622dee 100644 --- a/vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php +++ b/vendor/symfony/debug/FatalErrorHandler/UndefinedMethodFatalErrorHandler.php @@ -14,10 +14,14 @@ use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\UndefinedMethodException; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "%s" instead.', UndefinedMethodFatalErrorHandler::class, \Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer::class), \E_USER_DEPRECATED); + /** * ErrorHandler for undefined methods. * * @author Grégoire Pineau + * + * @deprecated since Symfony 4.4, use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer instead. */ class UndefinedMethodFatalErrorHandler implements FatalErrorHandlerInterface { @@ -36,7 +40,7 @@ public function handleError(array $error, FatalErrorException $exception) $message = sprintf('Attempted to call an undefined method named "%s" of class "%s".', $methodName, $className); - if (!class_exists($className) || null === $methods = get_class_methods($className)) { + if ('' === $methodName || !class_exists($className) || null === $methods = get_class_methods($className)) { // failed to get the class or its methods on which an unknown method was called (for example on an anonymous class) return new UndefinedMethodException($message, $exception); } diff --git a/vendor/symfony/debug/LICENSE b/vendor/symfony/debug/LICENSE index 9e936ec0..88bf75bb 100644 --- a/vendor/symfony/debug/LICENSE +++ b/vendor/symfony/debug/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/debug/README.md b/vendor/symfony/debug/README.md index f0878df3..31a82406 100644 --- a/vendor/symfony/debug/README.md +++ b/vendor/symfony/debug/README.md @@ -1,13 +1,18 @@ Debug Component =============== +**CAUTION**: this component is deprecated since Symfony 4.4. Instead, use the +[ErrorHandler component](https://github.com/symfony/symfony/tree/master/src/Symfony/Component/ErrorHandler). + +----- + The Debug component provides tools to ease debugging PHP code. Getting Started --------------- ``` -$ composer install symfony/debug +$ composer require symfony/debug ``` ```php @@ -19,7 +24,7 @@ Debug::enable(); Resources --------- - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/debug/Resources/ext/README.md b/vendor/symfony/debug/Resources/ext/README.md deleted file mode 100644 index 2df00ecd..00000000 --- a/vendor/symfony/debug/Resources/ext/README.md +++ /dev/null @@ -1,134 +0,0 @@ -Symfony Debug Extension for PHP 5 -================================= - -This extension publishes several functions to help building powerful debugging tools. -It is compatible with PHP 5.3, 5.4, 5.5 and 5.6; with ZTS and non-ZTS modes. -It is not required thus not provided for PHP 7. - -symfony_zval_info() -------------------- - -- exposes zval_hash/refcounts, allowing e.g. efficient exploration of arbitrary structures in PHP, -- does work with references, preventing memory copying. - -Its behavior is about the same as: - -```php - gettype($array[$key]), - 'zval_hash' => /* hashed memory address of $array[$key] */, - 'zval_refcount' => /* internal zval refcount of $array[$key] */, - 'zval_isref' => /* is_ref status of $array[$key] */, - ]; - - switch ($info['type']) { - case 'object': - $info += [ - 'object_class' => get_class($array[$key]), - 'object_refcount' => /* internal object refcount of $array[$key] */, - 'object_hash' => spl_object_hash($array[$key]), - 'object_handle' => /* internal object handle $array[$key] */, - ]; - break; - - case 'resource': - $info += [ - 'resource_handle' => (int) $array[$key], - 'resource_type' => get_resource_type($array[$key]), - 'resource_refcount' => /* internal resource refcount of $array[$key] */, - ]; - break; - - case 'array': - $info += [ - 'array_count' => count($array[$key]), - ]; - break; - - case 'string': - $info += [ - 'strlen' => strlen($array[$key]), - ]; - break; - } - - return $info; -} -``` - -symfony_debug_backtrace() -------------------------- - -This function works like debug_backtrace(), except that it can fetch the full backtrace in case of fatal errors: - -```php -function foo() { fatal(); } -function bar() { foo(); } - -function sd() { var_dump(symfony_debug_backtrace()); } - -register_shutdown_function('sd'); - -bar(); - -/* Will output -Fatal error: Call to undefined function fatal() in foo.php on line 42 -array(3) { - [0]=> - array(2) { - ["function"]=> - string(2) "sd" - ["args"]=> - array(0) { - } - } - [1]=> - array(4) { - ["file"]=> - string(7) "foo.php" - ["line"]=> - int(1) - ["function"]=> - string(3) "foo" - ["args"]=> - array(0) { - } - } - [2]=> - array(4) { - ["file"]=> - string(102) "foo.php" - ["line"]=> - int(2) - ["function"]=> - string(3) "bar" - ["args"]=> - array(0) { - } - } -} -*/ -``` - -Usage ------ - -To enable the extension from source, run: - -``` - phpize - ./configure - make - sudo make install -``` diff --git a/vendor/symfony/debug/Resources/ext/config.m4 b/vendor/symfony/debug/Resources/ext/config.m4 deleted file mode 100644 index 3c560471..00000000 --- a/vendor/symfony/debug/Resources/ext/config.m4 +++ /dev/null @@ -1,63 +0,0 @@ -dnl $Id$ -dnl config.m4 for extension symfony_debug - -dnl Comments in this file start with the string 'dnl'. -dnl Remove where necessary. This file will not work -dnl without editing. - -dnl If your extension references something external, use with: - -dnl PHP_ARG_WITH(symfony_debug, for symfony_debug support, -dnl Make sure that the comment is aligned: -dnl [ --with-symfony_debug Include symfony_debug support]) - -dnl Otherwise use enable: - -PHP_ARG_ENABLE(symfony_debug, whether to enable symfony_debug support, -dnl Make sure that the comment is aligned: -[ --enable-symfony_debug Enable symfony_debug support]) - -if test "$PHP_SYMFONY_DEBUG" != "no"; then - dnl Write more examples of tests here... - - dnl # --with-symfony_debug -> check with-path - dnl SEARCH_PATH="/usr/local /usr" # you might want to change this - dnl SEARCH_FOR="/include/symfony_debug.h" # you most likely want to change this - dnl if test -r $PHP_SYMFONY_DEBUG/$SEARCH_FOR; then # path given as parameter - dnl SYMFONY_DEBUG_DIR=$PHP_SYMFONY_DEBUG - dnl else # search default path list - dnl AC_MSG_CHECKING([for symfony_debug files in default path]) - dnl for i in $SEARCH_PATH ; do - dnl if test -r $i/$SEARCH_FOR; then - dnl SYMFONY_DEBUG_DIR=$i - dnl AC_MSG_RESULT(found in $i) - dnl fi - dnl done - dnl fi - dnl - dnl if test -z "$SYMFONY_DEBUG_DIR"; then - dnl AC_MSG_RESULT([not found]) - dnl AC_MSG_ERROR([Please reinstall the symfony_debug distribution]) - dnl fi - - dnl # --with-symfony_debug -> add include path - dnl PHP_ADD_INCLUDE($SYMFONY_DEBUG_DIR/include) - - dnl # --with-symfony_debug -> check for lib and symbol presence - dnl LIBNAME=symfony_debug # you may want to change this - dnl LIBSYMBOL=symfony_debug # you most likely want to change this - - dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, - dnl [ - dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SYMFONY_DEBUG_DIR/lib, SYMFONY_DEBUG_SHARED_LIBADD) - dnl AC_DEFINE(HAVE_SYMFONY_DEBUGLIB,1,[ ]) - dnl ],[ - dnl AC_MSG_ERROR([wrong symfony_debug lib version or lib not found]) - dnl ],[ - dnl -L$SYMFONY_DEBUG_DIR/lib -lm - dnl ]) - dnl - dnl PHP_SUBST(SYMFONY_DEBUG_SHARED_LIBADD) - - PHP_NEW_EXTENSION(symfony_debug, symfony_debug.c, $ext_shared) -fi diff --git a/vendor/symfony/debug/Resources/ext/config.w32 b/vendor/symfony/debug/Resources/ext/config.w32 deleted file mode 100644 index 487e6913..00000000 --- a/vendor/symfony/debug/Resources/ext/config.w32 +++ /dev/null @@ -1,13 +0,0 @@ -// $Id$ -// vim:ft=javascript - -// If your extension references something external, use ARG_WITH -// ARG_WITH("symfony_debug", "for symfony_debug support", "no"); - -// Otherwise, use ARG_ENABLE -// ARG_ENABLE("symfony_debug", "enable symfony_debug support", "no"); - -if (PHP_SYMFONY_DEBUG != "no") { - EXTENSION("symfony_debug", "symfony_debug.c"); -} - diff --git a/vendor/symfony/debug/Resources/ext/php_symfony_debug.h b/vendor/symfony/debug/Resources/ext/php_symfony_debug.h deleted file mode 100644 index 26d0e8c0..00000000 --- a/vendor/symfony/debug/Resources/ext/php_symfony_debug.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifndef PHP_SYMFONY_DEBUG_H -#define PHP_SYMFONY_DEBUG_H - -extern zend_module_entry symfony_debug_module_entry; -#define phpext_symfony_debug_ptr &symfony_debug_module_entry - -#define PHP_SYMFONY_DEBUG_VERSION "2.7" - -#ifdef PHP_WIN32 -# define PHP_SYMFONY_DEBUG_API __declspec(dllexport) -#elif defined(__GNUC__) && __GNUC__ >= 4 -# define PHP_SYMFONY_DEBUG_API __attribute__ ((visibility("default"))) -#else -# define PHP_SYMFONY_DEBUG_API -#endif - -#ifdef ZTS -#include "TSRM.h" -#endif - -ZEND_BEGIN_MODULE_GLOBALS(symfony_debug) - intptr_t req_rand_init; - void (*old_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); - zval *debug_bt; -ZEND_END_MODULE_GLOBALS(symfony_debug) - -PHP_MINIT_FUNCTION(symfony_debug); -PHP_MSHUTDOWN_FUNCTION(symfony_debug); -PHP_RINIT_FUNCTION(symfony_debug); -PHP_RSHUTDOWN_FUNCTION(symfony_debug); -PHP_MINFO_FUNCTION(symfony_debug); -PHP_GINIT_FUNCTION(symfony_debug); -PHP_GSHUTDOWN_FUNCTION(symfony_debug); - -PHP_FUNCTION(symfony_zval_info); -PHP_FUNCTION(symfony_debug_backtrace); - -static char *_symfony_debug_memory_address_hash(void * TSRMLS_DC); -static const char *_symfony_debug_zval_type(zval *); -static const char* _symfony_debug_get_resource_type(long TSRMLS_DC); -static int _symfony_debug_get_resource_refcount(long TSRMLS_DC); - -void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); - -#ifdef ZTS -#define SYMFONY_DEBUG_G(v) TSRMG(symfony_debug_globals_id, zend_symfony_debug_globals *, v) -#else -#define SYMFONY_DEBUG_G(v) (symfony_debug_globals.v) -#endif - -#endif /* PHP_SYMFONY_DEBUG_H */ diff --git a/vendor/symfony/debug/Resources/ext/symfony_debug.c b/vendor/symfony/debug/Resources/ext/symfony_debug.c deleted file mode 100644 index 0d7cb602..00000000 --- a/vendor/symfony/debug/Resources/ext/symfony_debug.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#ifdef ZTS -#include "TSRM.h" -#endif -#include "php_ini.h" -#include "ext/standard/info.h" -#include "php_symfony_debug.h" -#include "ext/standard/php_rand.h" -#include "ext/standard/php_lcg.h" -#include "ext/spl/php_spl.h" -#include "Zend/zend_gc.h" -#include "Zend/zend_builtin_functions.h" -#include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */ -#include "ext/standard/php_array.h" -#include "Zend/zend_interfaces.h" -#include "SAPI.h" - -#define IS_PHP_53 ZEND_EXTENSION_API_NO == 220090626 - -ZEND_DECLARE_MODULE_GLOBALS(symfony_debug) - -ZEND_BEGIN_ARG_INFO_EX(symfony_zval_arginfo, 0, 0, 2) - ZEND_ARG_INFO(0, key) - ZEND_ARG_ARRAY_INFO(0, array, 0) - ZEND_ARG_INFO(0, options) -ZEND_END_ARG_INFO() - -const zend_function_entry symfony_debug_functions[] = { - PHP_FE(symfony_zval_info, symfony_zval_arginfo) - PHP_FE(symfony_debug_backtrace, NULL) - PHP_FE_END -}; - -PHP_FUNCTION(symfony_debug_backtrace) -{ - if (zend_parse_parameters_none() == FAILURE) { - return; - } -#if IS_PHP_53 - zend_fetch_debug_backtrace(return_value, 1, 0 TSRMLS_CC); -#else - zend_fetch_debug_backtrace(return_value, 1, 0, 0 TSRMLS_CC); -#endif - - if (!SYMFONY_DEBUG_G(debug_bt)) { - return; - } - - php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(SYMFONY_DEBUG_G(debug_bt)), 0 TSRMLS_CC); -} - -PHP_FUNCTION(symfony_zval_info) -{ - zval *key = NULL, *arg = NULL; - zval **data = NULL; - HashTable *array = NULL; - long options = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zh|l", &key, &array, &options) == FAILURE) { - return; - } - - switch (Z_TYPE_P(key)) { - case IS_STRING: - if (zend_symtable_find(array, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&data) == FAILURE) { - return; - } - break; - case IS_LONG: - if (zend_hash_index_find(array, Z_LVAL_P(key), (void **)&data)) { - return; - } - break; - } - - arg = *data; - - array_init(return_value); - - add_assoc_string(return_value, "type", (char *)_symfony_debug_zval_type(arg), 1); - add_assoc_stringl(return_value, "zval_hash", _symfony_debug_memory_address_hash((void *)arg TSRMLS_CC), 16, 0); - add_assoc_long(return_value, "zval_refcount", Z_REFCOUNT_P(arg)); - add_assoc_bool(return_value, "zval_isref", (zend_bool)Z_ISREF_P(arg)); - - if (Z_TYPE_P(arg) == IS_OBJECT) { - char hash[33] = {0}; - - php_spl_object_hash(arg, (char *)hash TSRMLS_CC); - add_assoc_stringl(return_value, "object_class", (char *)Z_OBJCE_P(arg)->name, Z_OBJCE_P(arg)->name_length, 1); - add_assoc_long(return_value, "object_refcount", EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(arg)].bucket.obj.refcount); - add_assoc_string(return_value, "object_hash", hash, 1); - add_assoc_long(return_value, "object_handle", Z_OBJ_HANDLE_P(arg)); - } else if (Z_TYPE_P(arg) == IS_ARRAY) { - add_assoc_long(return_value, "array_count", zend_hash_num_elements(Z_ARRVAL_P(arg))); - } else if(Z_TYPE_P(arg) == IS_RESOURCE) { - add_assoc_long(return_value, "resource_handle", Z_LVAL_P(arg)); - add_assoc_string(return_value, "resource_type", (char *)_symfony_debug_get_resource_type(Z_LVAL_P(arg) TSRMLS_CC), 1); - add_assoc_long(return_value, "resource_refcount", _symfony_debug_get_resource_refcount(Z_LVAL_P(arg) TSRMLS_CC)); - } else if (Z_TYPE_P(arg) == IS_STRING) { - add_assoc_long(return_value, "strlen", Z_STRLEN_P(arg)); - } -} - -void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) -{ - TSRMLS_FETCH(); - zval *retval; - - switch (type) { - case E_ERROR: - case E_PARSE: - case E_CORE_ERROR: - case E_CORE_WARNING: - case E_COMPILE_ERROR: - case E_COMPILE_WARNING: - ALLOC_INIT_ZVAL(retval); -#if IS_PHP_53 - zend_fetch_debug_backtrace(retval, 1, 0 TSRMLS_CC); -#else - zend_fetch_debug_backtrace(retval, 1, 0, 0 TSRMLS_CC); -#endif - SYMFONY_DEBUG_G(debug_bt) = retval; - } - - SYMFONY_DEBUG_G(old_error_cb)(type, error_filename, error_lineno, format, args); -} - -static const char* _symfony_debug_get_resource_type(long rsid TSRMLS_DC) -{ - const char *res_type; - res_type = zend_rsrc_list_get_rsrc_type(rsid TSRMLS_CC); - - if (!res_type) { - return "Unknown"; - } - - return res_type; -} - -static int _symfony_debug_get_resource_refcount(long rsid TSRMLS_DC) -{ - zend_rsrc_list_entry *le; - - if (zend_hash_index_find(&EG(regular_list), rsid, (void **) &le)==SUCCESS) { - return le->refcount; - } - - return 0; -} - -static char *_symfony_debug_memory_address_hash(void *address TSRMLS_DC) -{ - char *result = NULL; - intptr_t address_rand; - - if (!SYMFONY_DEBUG_G(req_rand_init)) { - if (!BG(mt_rand_is_seeded)) { - php_mt_srand(GENERATE_SEED() TSRMLS_CC); - } - SYMFONY_DEBUG_G(req_rand_init) = (intptr_t)php_mt_rand(TSRMLS_C); - } - - address_rand = (intptr_t)address ^ SYMFONY_DEBUG_G(req_rand_init); - - spprintf(&result, 17, "%016zx", address_rand); - - return result; -} - -static const char *_symfony_debug_zval_type(zval *zv) -{ - switch (Z_TYPE_P(zv)) { - case IS_NULL: - return "NULL"; - break; - - case IS_BOOL: - return "boolean"; - break; - - case IS_LONG: - return "integer"; - break; - - case IS_DOUBLE: - return "double"; - break; - - case IS_STRING: - return "string"; - break; - - case IS_ARRAY: - return "array"; - break; - - case IS_OBJECT: - return "object"; - - case IS_RESOURCE: - return "resource"; - - default: - return "unknown type"; - } -} - -zend_module_entry symfony_debug_module_entry = { - STANDARD_MODULE_HEADER, - "symfony_debug", - symfony_debug_functions, - PHP_MINIT(symfony_debug), - PHP_MSHUTDOWN(symfony_debug), - PHP_RINIT(symfony_debug), - PHP_RSHUTDOWN(symfony_debug), - PHP_MINFO(symfony_debug), - PHP_SYMFONY_DEBUG_VERSION, - PHP_MODULE_GLOBALS(symfony_debug), - PHP_GINIT(symfony_debug), - PHP_GSHUTDOWN(symfony_debug), - NULL, - STANDARD_MODULE_PROPERTIES_EX -}; - -#ifdef COMPILE_DL_SYMFONY_DEBUG -ZEND_GET_MODULE(symfony_debug) -#endif - -PHP_GINIT_FUNCTION(symfony_debug) -{ - memset(symfony_debug_globals, 0 , sizeof(*symfony_debug_globals)); -} - -PHP_GSHUTDOWN_FUNCTION(symfony_debug) -{ - -} - -PHP_MINIT_FUNCTION(symfony_debug) -{ - SYMFONY_DEBUG_G(old_error_cb) = zend_error_cb; - zend_error_cb = symfony_debug_error_cb; - - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(symfony_debug) -{ - zend_error_cb = SYMFONY_DEBUG_G(old_error_cb); - - return SUCCESS; -} - -PHP_RINIT_FUNCTION(symfony_debug) -{ - return SUCCESS; -} - -PHP_RSHUTDOWN_FUNCTION(symfony_debug) -{ - return SUCCESS; -} - -PHP_MINFO_FUNCTION(symfony_debug) -{ - php_info_print_table_start(); - php_info_print_table_header(2, "Symfony Debug support", "enabled"); - php_info_print_table_header(2, "Symfony Debug version", PHP_SYMFONY_DEBUG_VERSION); - php_info_print_table_end(); -} diff --git a/vendor/symfony/debug/Resources/ext/tests/001.phpt b/vendor/symfony/debug/Resources/ext/tests/001.phpt deleted file mode 100644 index 86a9427c..00000000 --- a/vendor/symfony/debug/Resources/ext/tests/001.phpt +++ /dev/null @@ -1,155 +0,0 @@ ---TEST-- -Test symfony_zval_info API ---SKIPIF-- - ---FILE-- - $int, - 'float' => $float, - 'str' => $str, - 'object' => $object, - 'array' => $array, - 'resource' => $resource, - 'null' => $null, - 'bool' => $bool, - 'refcount' => &$refcount2, -]; - -var_dump(symfony_zval_info('int', $var)); -var_dump(symfony_zval_info('float', $var)); -var_dump(symfony_zval_info('str', $var)); -var_dump(symfony_zval_info('object', $var)); -var_dump(symfony_zval_info('array', $var)); -var_dump(symfony_zval_info('resource', $var)); -var_dump(symfony_zval_info('null', $var)); -var_dump(symfony_zval_info('bool', $var)); - -var_dump(symfony_zval_info('refcount', $var)); -var_dump(symfony_zval_info('not-exist', $var)); -?> ---EXPECTF-- -array(4) { - ["type"]=> - string(7) "integer" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(4) { - ["type"]=> - string(6) "double" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(5) { - ["type"]=> - string(6) "string" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["strlen"]=> - int(6) -} -array(8) { - ["type"]=> - string(6) "object" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["object_class"]=> - string(8) "stdClass" - ["object_refcount"]=> - int(1) - ["object_hash"]=> - string(32) "%s" - ["object_handle"]=> - int(%d) -} -array(5) { - ["type"]=> - string(5) "array" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["array_count"]=> - int(2) -} -array(7) { - ["type"]=> - string(8) "resource" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["resource_handle"]=> - int(%d) - ["resource_type"]=> - string(6) "stream" - ["resource_refcount"]=> - int(1) -} -array(4) { - ["type"]=> - string(4) "NULL" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(4) { - ["type"]=> - string(7) "boolean" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(4) { - ["type"]=> - string(7) "integer" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(3) - ["zval_isref"]=> - bool(true) -} -NULL diff --git a/vendor/symfony/debug/Resources/ext/tests/002.phpt b/vendor/symfony/debug/Resources/ext/tests/002.phpt deleted file mode 100644 index afc7bb49..00000000 --- a/vendor/symfony/debug/Resources/ext/tests/002.phpt +++ /dev/null @@ -1,65 +0,0 @@ ---TEST-- -Test symfony_debug_backtrace in case of fatal error ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -Fatal error: Call to undefined function notexist() in %s on line %d -Array -( - [0] => Array - ( - [function] => bt - [args] => Array - ( - ) - - ) - - [1] => Array - ( - [file] => %s - [line] => %d - [function] => foo - [args] => Array - ( - ) - - ) - - [2] => Array - ( - [file] => %s - [line] => %d - [function] => bar - [args] => Array - ( - ) - - ) - -) diff --git a/vendor/symfony/debug/Resources/ext/tests/002_1.phpt b/vendor/symfony/debug/Resources/ext/tests/002_1.phpt deleted file mode 100644 index 86de3e17..00000000 --- a/vendor/symfony/debug/Resources/ext/tests/002_1.phpt +++ /dev/null @@ -1,48 +0,0 @@ ---TEST-- -Test symfony_debug_backtrace in case of non fatal error ---SKIPIF-- - ---FILE-- - ---EXPECTF-- -Array -( - [0] => Array - ( - [file] => %s - [line] => %d - [function] => bt - [args] => Array - ( - ) - - ) - - [1] => Array - ( - [file] => %s - [line] => %d - [function] => bar - [args] => Array - ( - ) - - ) - -) diff --git a/vendor/symfony/debug/Resources/ext/tests/003.phpt b/vendor/symfony/debug/Resources/ext/tests/003.phpt deleted file mode 100644 index 4e764503..00000000 --- a/vendor/symfony/debug/Resources/ext/tests/003.phpt +++ /dev/null @@ -1,87 +0,0 @@ ---TEST-- -Test ErrorHandler in case of fatal error ---SKIPIF-- - ---FILE-- -setExceptionHandler('print_r'); - -if (\function_exists('xdebug_disable')) { - xdebug_disable(); -} - -bar(); -?> ---EXPECTF-- -Fatal error: Call to undefined function Symfony\Component\Debug\notexist() in %s on line %d -Symfony\Component\Debug\Exception\UndefinedFunctionException Object -( - [message:protected] => Attempted to call function "notexist" from namespace "Symfony\Component\Debug". - [string:Exception:private] => - [code:protected] => 0 - [file:protected] => %s - [line:protected] => %d - [trace:Exception:private] => Array - ( - [0] => Array - ( -%A [function] => Symfony\Component\Debug\foo -%A [args] => Array - ( - ) - - ) - - [1] => Array - ( -%A [function] => Symfony\Component\Debug\bar -%A [args] => Array - ( - ) - - ) -%A - ) - - [previous:Exception:private] => - [severity:protected] => 1 -) diff --git a/vendor/symfony/debug/Tests/DebugClassLoaderTest.php b/vendor/symfony/debug/Tests/DebugClassLoaderTest.php deleted file mode 100644 index f117759b..00000000 --- a/vendor/symfony/debug/Tests/DebugClassLoaderTest.php +++ /dev/null @@ -1,448 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\DebugClassLoader; -use Symfony\Component\Debug\ErrorHandler; - -class DebugClassLoaderTest extends TestCase -{ - /** - * @var int Error reporting level before running tests - */ - private $errorReporting; - - private $loader; - - protected function setUp() - { - $this->errorReporting = error_reporting(E_ALL); - $this->loader = new ClassLoader(); - spl_autoload_register([$this->loader, 'loadClass'], true, true); - DebugClassLoader::enable(); - } - - protected function tearDown() - { - DebugClassLoader::disable(); - spl_autoload_unregister([$this->loader, 'loadClass']); - error_reporting($this->errorReporting); - } - - public function testIdempotence() - { - DebugClassLoader::enable(); - - $functions = spl_autoload_functions(); - foreach ($functions as $function) { - if (\is_array($function) && $function[0] instanceof DebugClassLoader) { - $reflClass = new \ReflectionClass($function[0]); - $reflProp = $reflClass->getProperty('classLoader'); - $reflProp->setAccessible(true); - - $this->assertNotInstanceOf('Symfony\Component\Debug\DebugClassLoader', $reflProp->getValue($function[0])); - - return; - } - } - - $this->fail('DebugClassLoader did not register'); - } - - public function testThrowingClass() - { - $this->expectException('Exception'); - $this->expectExceptionMessage('boo'); - try { - class_exists(Fixtures\Throwing::class); - $this->fail('Exception expected'); - } catch (\Exception $e) { - $this->assertSame('boo', $e->getMessage()); - } - - // the second call also should throw - class_exists(Fixtures\Throwing::class); - } - - public function testUnsilencing() - { - if (\PHP_VERSION_ID >= 70000) { - $this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.'); - } - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM is not handled in this test case.'); - } - - ob_start(); - - $this->iniSet('log_errors', 0); - $this->iniSet('display_errors', 1); - - // See below: this will fail with parse error - // but this should not be @-silenced. - @class_exists(TestingUnsilencing::class, true); - - $output = ob_get_clean(); - - $this->assertStringMatchesFormat('%aParse error%a', $output); - } - - /** - * @requires PHP < 8.0 - */ - public function testStacking() - { - // the ContextErrorException must not be loaded to test the workaround - // for https://bugs.php.net/65322. - if (class_exists('Symfony\Component\Debug\Exception\ContextErrorException', false)) { - $this->markTestSkipped('The ContextErrorException class is already loaded.'); - } - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM is not handled in this test case.'); - } - - ErrorHandler::register(); - - try { - // Trigger autoloading + E_STRICT at compile time - // which in turn triggers $errorHandler->handle() - // that again triggers autoloading for ContextErrorException. - // Error stacking works around the bug above and everything is fine. - - eval(' - namespace '.__NAMESPACE__.'; - class ChildTestingStacking extends TestingStacking { function foo($bar) {} } - '); - $this->fail('ContextErrorException expected'); - } catch (\ErrorException $exception) { - // if an exception is thrown, the test passed - $this->assertStringStartsWith(__FILE__, $exception->getFile()); - if (\PHP_VERSION_ID < 70000) { - $this->assertMatchesRegularExpression('/^Runtime Notice: Declaration/', $exception->getMessage()); - $this->assertEquals(E_STRICT, $exception->getSeverity()); - } else { - $this->assertMatchesRegularExpression('/^Warning: Declaration/', $exception->getMessage()); - $this->assertEquals(E_WARNING, $exception->getSeverity()); - } - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - public function testNameCaseMismatch() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('Case mismatch between loaded and declared class names'); - class_exists(TestingCaseMismatch::class, true); - } - - public function testFileCaseMismatch() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('Case mismatch between class and real file names'); - if (!file_exists(__DIR__.'/Fixtures/CaseMismatch.php')) { - $this->markTestSkipped('Can only be run on case insensitive filesystems'); - } - - class_exists(Fixtures\CaseMismatch::class, true); - } - - public function testPsr4CaseMismatch() - { - $this->expectException('RuntimeException'); - $this->expectExceptionMessage('Case mismatch between loaded and declared class names'); - class_exists(__NAMESPACE__.'\Fixtures\Psr4CaseMismatch', true); - } - - public function testNotPsr0() - { - $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\NotPSR0', true)); - } - - public function testNotPsr0Bis() - { - $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\NotPSR0bis', true)); - } - - public function testClassAlias() - { - $this->assertTrue(class_exists(Fixtures\ClassAlias::class, true)); - } - - /** - * @dataProvider provideDeprecatedSuper - */ - public function testDeprecatedSuper($class, $super, $type) - { - set_error_handler(function () { return false; }); - $e = error_reporting(0); - @trigger_error('', E_USER_DEPRECATED); - - class_exists('Test\\'.__NAMESPACE__.'\\'.$class, true); - - error_reporting($e); - restore_error_handler(); - - $lastError = error_get_last(); - unset($lastError['file'], $lastError['line']); - - $xError = [ - 'type' => E_USER_DEPRECATED, - 'message' => 'The "Test\Symfony\Component\Debug\Tests\\'.$class.'" class '.$type.' "Symfony\Component\Debug\Tests\Fixtures\\'.$super.'" that is deprecated but this is a test deprecation notice.', - ]; - - $this->assertSame($xError, $lastError); - } - - public function provideDeprecatedSuper() - { - return [ - ['DeprecatedInterfaceClass', 'DeprecatedInterface', 'implements'], - ['DeprecatedParentClass', 'DeprecatedClass', 'extends'], - ]; - } - - public function testInterfaceExtendsDeprecatedInterface() - { - set_error_handler(function () { return false; }); - $e = error_reporting(0); - trigger_error('', E_USER_NOTICE); - - class_exists('Test\\'.NonDeprecatedInterfaceClass::class, true); - - error_reporting($e); - restore_error_handler(); - - $lastError = error_get_last(); - unset($lastError['file'], $lastError['line']); - - $xError = [ - 'type' => E_USER_NOTICE, - 'message' => '', - ]; - - $this->assertSame($xError, $lastError); - } - - public function testDeprecatedSuperInSameNamespace() - { - set_error_handler(function () { return false; }); - $e = error_reporting(0); - trigger_error('', E_USER_NOTICE); - - class_exists('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent', true); - - error_reporting($e); - restore_error_handler(); - - $lastError = error_get_last(); - unset($lastError['file'], $lastError['line']); - - $xError = [ - 'type' => E_USER_NOTICE, - 'message' => '', - ]; - - $this->assertSame($xError, $lastError); - } - - public function testReservedForPhp7() - { - if (\PHP_VERSION_ID >= 70000) { - $this->markTestSkipped('PHP7 already prevents using reserved names.'); - } - - set_error_handler(function () { return false; }); - $e = error_reporting(0); - trigger_error('', E_USER_NOTICE); - - class_exists('Test\\'.Float::class, true); - - error_reporting($e); - restore_error_handler(); - - $lastError = error_get_last(); - unset($lastError['file'], $lastError['line']); - - $xError = [ - 'type' => E_USER_DEPRECATED, - 'message' => 'The "Test\Symfony\Component\Debug\Tests\Float" class uses the reserved name "Float", it will break on PHP 7 and higher', - ]; - - $this->assertSame($xError, $lastError); - } - - public function testExtendedFinalClass() - { - $deprecations = []; - set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); - $e = error_reporting(E_USER_DEPRECATED); - - require __DIR__.'/Fixtures/FinalClasses.php'; - - $i = 1; - while (class_exists($finalClass = Fixtures\FinalClass::class.$i++, false)) { - spl_autoload_call($finalClass); - class_exists('Test\\'.__NAMESPACE__.'\\Extends'.substr($finalClass, strrpos($finalClass, '\\') + 1), true); - } - - error_reporting($e); - restore_error_handler(); - - $this->assertSame([ - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass1" class is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass1".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass2" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass2".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass3" class is considered final comment with @@@ and ***. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass3".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass4" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass4".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass5" class is considered final multiline comment. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass5".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass6" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass6".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass7" class is considered final another multiline comment... It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass7".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass8" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass8".', - ], $deprecations); - } - - public function testExtendedFinalMethod() - { - $deprecations = []; - set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); - $e = error_reporting(E_USER_DEPRECATED); - - class_exists(Fixtures\ExtendedFinalMethod::class, true); - - error_reporting($e); - restore_error_handler(); - - $xError = [ - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".', - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".', - ]; - - $this->assertSame($xError, $deprecations); - } - - public function testExtendedDeprecatedMethodDoesntTriggerAnyNotice() - { - set_error_handler(function () { return false; }); - $e = error_reporting(0); - trigger_error('', E_USER_NOTICE); - - class_exists('Test\\'.ExtendsAnnotatedClass::class, true); - - error_reporting($e); - restore_error_handler(); - - $lastError = error_get_last(); - unset($lastError['file'], $lastError['line']); - - $this->assertSame(['type' => E_USER_NOTICE, 'message' => ''], $lastError); - } - - public function testInternalsUse() - { - $deprecations = []; - set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); - $e = error_reporting(E_USER_DEPRECATED); - - class_exists('Test\\'.ExtendsInternals::class, true); - - error_reporting($e); - restore_error_handler(); - - $this->assertSame($deprecations, [ - 'The "Symfony\Component\Debug\Tests\Fixtures\InternalInterface" interface is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".', - 'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass" class is considered internal since version 3.4. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".', - 'The "Symfony\Component\Debug\Tests\Fixtures\InternalTrait" trait is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".', - 'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass::internalMethod()" method is considered internal since version 3.4. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".', - ]); - } - - public function testUseTraitWithInternalMethod() - { - $deprecations = []; - set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); - $e = error_reporting(E_USER_DEPRECATED); - - class_exists('Test\\'.UseTraitWithInternalMethod::class, true); - - error_reporting($e); - restore_error_handler(); - - $this->assertSame([], $deprecations); - } - - public function testEvaluatedCode() - { - $this->assertTrue(class_exists(Fixtures\DefinitionInEvaluatedCode::class, true)); - } -} - -class ClassLoader -{ - public function loadClass($class) - { - } - - public function getClassMap() - { - return [__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__.'/Fixtures/notPsr0Bis.php']; - } - - public function findFile($class) - { - $fixtureDir = __DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR; - - if (TestingUnsilencing::class === $class) { - eval('-- parse error --'); - } elseif (TestingStacking::class === $class) { - eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }'); - } elseif (TestingCaseMismatch::class === $class) { - eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}'); - } elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) { - return $fixtureDir.'psr4'.\DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php'; - } elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) { - return $fixtureDir.'reallyNotPsr0.php'; - } elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) { - return $fixtureDir.'notPsr0Bis.php'; - } elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) { - eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}'); - } elseif ('Test\\'.DeprecatedParentClass::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedParentClass extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}'); - } elseif ('Test\\'.DeprecatedInterfaceClass::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\DeprecatedInterface {}'); - } elseif ('Test\\'.NonDeprecatedInterfaceClass::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}'); - } elseif ('Test\\'.Float::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class Float {}'); - } elseif (0 === strpos($class, 'Test\\'.ExtendsFinalClass::class)) { - $classShortName = substr($class, strrpos($class, '\\') + 1); - eval('namespace Test\\'.__NAMESPACE__.'; class '.$classShortName.' extends \\'.__NAMESPACE__.'\Fixtures\\'.substr($classShortName, 7).' {}'); - } elseif ('Test\\'.ExtendsAnnotatedClass::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsAnnotatedClass extends \\'.__NAMESPACE__.'\Fixtures\AnnotatedClass { - public function deprecatedMethod() { } - }'); - } elseif ('Test\\'.ExtendsInternals::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternals extends ExtendsInternalsParent { - use \\'.__NAMESPACE__.'\Fixtures\InternalTrait; - - public function internalMethod() { } - }'); - } elseif ('Test\\'.ExtendsInternalsParent::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }'); - } elseif ('Test\\'.UseTraitWithInternalMethod::class === $class) { - eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }'); - } - - return null; - } -} diff --git a/vendor/symfony/debug/Tests/ErrorHandlerTest.php b/vendor/symfony/debug/Tests/ErrorHandlerTest.php deleted file mode 100644 index 12083d3f..00000000 --- a/vendor/symfony/debug/Tests/ErrorHandlerTest.php +++ /dev/null @@ -1,664 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests; - -use PHPUnit\Framework\TestCase; -use Psr\Log\LogLevel; -use Psr\Log\NullLogger; -use Symfony\Component\Debug\BufferingLogger; -use Symfony\Component\Debug\ErrorHandler; -use Symfony\Component\Debug\Exception\SilencedErrorContext; -use Symfony\Component\Debug\Tests\Fixtures\ErrorHandlerThatUsesThePreviousOne; -use Symfony\Component\Debug\Tests\Fixtures\LoggerThatSetAnErrorHandler; - -/** - * ErrorHandlerTest. - * - * @author Robert Schönthal - * @author Nicolas Grekas - */ -class ErrorHandlerTest extends TestCase -{ - public function testRegister() - { - $handler = ErrorHandler::register(); - - try { - $this->assertInstanceOf('Symfony\Component\Debug\ErrorHandler', $handler); - $this->assertSame($handler, ErrorHandler::register()); - - $newHandler = new ErrorHandler(); - - $this->assertSame($handler, ErrorHandler::register($newHandler, false)); - $h = set_error_handler('var_dump'); - restore_error_handler(); - $this->assertSame([$handler, 'handleError'], $h); - - try { - $this->assertSame($newHandler, ErrorHandler::register($newHandler, true)); - $h = set_error_handler('var_dump'); - restore_error_handler(); - $this->assertSame([$newHandler, 'handleError'], $h); - } catch (\Exception $e) { - } - - restore_error_handler(); - restore_exception_handler(); - - if (isset($e)) { - throw $e; - } - } catch (\Exception $e) { - } - - restore_error_handler(); - restore_exception_handler(); - - if (isset($e)) { - throw $e; - } - } - - public function testErrorGetLast() - { - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $handler = ErrorHandler::register(); - $handler->setDefaultLogger($logger); - $handler->screamAt(\E_ALL); - - try { - @trigger_error('Hello', \E_USER_WARNING); - $expected = [ - 'type' => \E_USER_WARNING, - 'message' => 'Hello', - 'file' => __FILE__, - 'line' => __LINE__ - 5, - ]; - $this->assertSame($expected, error_get_last()); - } catch (\Exception $e) { - restore_error_handler(); - restore_exception_handler(); - - throw $e; - } - } - - public function testNotice() - { - ErrorHandler::register(); - - try { - self::triggerNotice($this); - $this->fail('ErrorException expected'); - } catch (\ErrorException $exception) { - // if an exception is thrown, the test passed - if (\PHP_VERSION_ID < 80000) { - $this->assertEquals(\E_NOTICE, $exception->getSeverity()); - $this->assertMatchesRegularExpression('/^Notice: Undefined variable: (foo|bar)/', $exception->getMessage()); - } else { - $this->assertEquals(\E_WARNING, $exception->getSeverity()); - $this->assertMatchesRegularExpression('/^Warning: Undefined variable \$(foo|bar)/', $exception->getMessage()); - } - $this->assertEquals(__FILE__, $exception->getFile()); - - $trace = $exception->getTrace(); - - $this->assertEquals(__FILE__, $trace[0]['file']); - $this->assertEquals(__CLASS__, $trace[0]['class']); - $this->assertEquals('triggerNotice', $trace[0]['function']); - $this->assertEquals('::', $trace[0]['type']); - - $this->assertEquals(__FILE__, $trace[0]['file']); - $this->assertEquals(__CLASS__, $trace[1]['class']); - $this->assertEquals(__FUNCTION__, $trace[1]['function']); - $this->assertEquals('->', $trace[1]['type']); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - // dummy function to test trace in error handler. - private static function triggerNotice($that) - { - $that->assertSame('', $foo.$foo.$bar); - } - - public function testConstruct() - { - try { - $handler = ErrorHandler::register(); - $handler->throwAt(3, true); - $this->assertEquals(3 | \E_RECOVERABLE_ERROR | \E_USER_ERROR, $handler->throwAt(0)); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - public function testDefaultLogger() - { - try { - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $handler = ErrorHandler::register(); - - $handler->setDefaultLogger($logger, \E_NOTICE); - $handler->setDefaultLogger($logger, [\E_USER_NOTICE => LogLevel::CRITICAL]); - - $loggers = [ - \E_DEPRECATED => [null, LogLevel::INFO], - \E_USER_DEPRECATED => [null, LogLevel::INFO], - \E_NOTICE => [$logger, LogLevel::WARNING], - \E_USER_NOTICE => [$logger, LogLevel::CRITICAL], - \E_STRICT => [null, LogLevel::WARNING], - \E_WARNING => [null, LogLevel::WARNING], - \E_USER_WARNING => [null, LogLevel::WARNING], - \E_COMPILE_WARNING => [null, LogLevel::WARNING], - \E_CORE_WARNING => [null, LogLevel::WARNING], - \E_USER_ERROR => [null, LogLevel::CRITICAL], - \E_RECOVERABLE_ERROR => [null, LogLevel::CRITICAL], - \E_COMPILE_ERROR => [null, LogLevel::CRITICAL], - \E_PARSE => [null, LogLevel::CRITICAL], - \E_ERROR => [null, LogLevel::CRITICAL], - \E_CORE_ERROR => [null, LogLevel::CRITICAL], - ]; - $this->assertSame($loggers, $handler->setLoggers([])); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - public function testHandleError() - { - try { - $handler = ErrorHandler::register(); - $handler->throwAt(0, true); - $this->assertFalse($handler->handleError(0, 'foo', 'foo.php', 12, [])); - - restore_error_handler(); - restore_exception_handler(); - - $handler = ErrorHandler::register(); - $handler->throwAt(3, true); - $this->assertFalse($handler->handleError(4, 'foo', 'foo.php', 12, [])); - - restore_error_handler(); - restore_exception_handler(); - - $handler = ErrorHandler::register(); - $handler->throwAt(3, true); - try { - $handler->handleError(4, 'foo', 'foo.php', 12, []); - } catch (\ErrorException $e) { - $this->assertSame('Parse Error: foo', $e->getMessage()); - $this->assertSame(4, $e->getSeverity()); - $this->assertSame('foo.php', $e->getFile()); - $this->assertSame(12, $e->getLine()); - } - - restore_error_handler(); - restore_exception_handler(); - - $handler = ErrorHandler::register(); - $handler->throwAt(\E_USER_DEPRECATED, true); - $this->assertFalse($handler->handleError(\E_USER_DEPRECATED, 'foo', 'foo.php', 12, [])); - - restore_error_handler(); - restore_exception_handler(); - - $handler = ErrorHandler::register(); - $handler->throwAt(\E_DEPRECATED, true); - $this->assertFalse($handler->handleError(\E_DEPRECATED, 'foo', 'foo.php', 12, [])); - - restore_error_handler(); - restore_exception_handler(); - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - - $warnArgCheck = function ($logLevel, $message, $context) { - $this->assertEquals('info', $logLevel); - $this->assertEquals('User Deprecated: foo', $message); - $this->assertArrayHasKey('exception', $context); - $exception = $context['exception']; - $this->assertInstanceOf(\ErrorException::class, $exception); - $this->assertSame('User Deprecated: foo', $exception->getMessage()); - $this->assertSame(\E_USER_DEPRECATED, $exception->getSeverity()); - }; - - $logger - ->expects($this->once()) - ->method('log') - ->willReturnCallback($warnArgCheck) - ; - - $handler = ErrorHandler::register(); - $handler->setDefaultLogger($logger, \E_USER_DEPRECATED); - $this->assertTrue($handler->handleError(\E_USER_DEPRECATED, 'foo', 'foo.php', 12, [])); - - restore_error_handler(); - restore_exception_handler(); - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - - $line = null; - $logArgCheck = function ($level, $message, $context) use (&$line) { - $this->assertArrayHasKey('exception', $context); - $exception = $context['exception']; - - if (\PHP_VERSION_ID < 80000) { - $this->assertEquals('Notice: Undefined variable: undefVar', $message); - $this->assertSame(\E_NOTICE, $exception->getSeverity()); - } else { - $this->assertEquals('Warning: Undefined variable $undefVar', $message); - $this->assertSame(\E_WARNING, $exception->getSeverity()); - } - $this->assertInstanceOf(SilencedErrorContext::class, $exception); - $this->assertSame(__FILE__, $exception->getFile()); - $this->assertSame($line, $exception->getLine()); - $this->assertNotEmpty($exception->getTrace()); - $this->assertSame(1, $exception->count); - }; - - $logger - ->expects($this->once()) - ->method('log') - ->willReturnCallback($logArgCheck) - ; - - $handler = ErrorHandler::register(); - if (\PHP_VERSION_ID < 80000) { - $handler->setDefaultLogger($logger, \E_NOTICE); - $handler->screamAt(\E_NOTICE); - } else { - $handler->setDefaultLogger($logger, \E_WARNING); - $handler->screamAt(\E_WARNING); - } - unset($undefVar); - $line = __LINE__ + 1; - @$undefVar++; - - restore_error_handler(); - restore_exception_handler(); - } catch (\Exception $e) { - restore_error_handler(); - restore_exception_handler(); - - throw $e; - } - } - - public function testHandleUserError() - { - if (\PHP_VERSION_ID >= 70400) { - $this->markTestSkipped('PHP 7.4 allows __toString to throw exceptions'); - } - - try { - $handler = ErrorHandler::register(); - $handler->throwAt(0, true); - - $e = null; - $x = new \Exception('Foo'); - - try { - $f = new Fixtures\ToStringThrower($x); - $f .= ''; // Trigger $f->__toString() - } catch (\Exception $e) { - } - - $this->assertSame($x, $e); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - public function testHandleDeprecation() - { - $logArgCheck = function ($level, $message, $context) { - $this->assertEquals(LogLevel::INFO, $level); - $this->assertArrayHasKey('exception', $context); - $exception = $context['exception']; - $this->assertInstanceOf(\ErrorException::class, $exception); - $this->assertSame('User Deprecated: Foo deprecation', $exception->getMessage()); - }; - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $logger - ->expects($this->once()) - ->method('log') - ->willReturnCallback($logArgCheck) - ; - - $handler = new ErrorHandler(); - $handler->setDefaultLogger($logger); - @$handler->handleError(\E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, []); - } - - /** - * @group no-hhvm - */ - public function testHandleException() - { - try { - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $handler = ErrorHandler::register(); - - $exception = new \Exception('foo'); - - $logArgCheck = function ($level, $message, $context) { - $this->assertSame('Uncaught Exception: foo', $message); - $this->assertArrayHasKey('exception', $context); - $this->assertInstanceOf(\Exception::class, $context['exception']); - }; - - $logger - ->expects($this->exactly(2)) - ->method('log') - ->willReturnCallback($logArgCheck) - ; - - $handler->setDefaultLogger($logger, \E_ERROR); - - try { - $handler->handleException($exception); - $this->fail('Exception expected'); - } catch (\Exception $e) { - $this->assertSame($exception, $e); - } - - $handler->setExceptionHandler(function ($e) use ($exception) { - $this->assertSame($exception, $e); - }); - - $handler->handleException($exception); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - /** - * @group legacy - */ - public function testErrorStacking() - { - try { - $handler = ErrorHandler::register(); - $handler->screamAt(\E_USER_WARNING); - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - - $logger - ->expects($this->exactly(2)) - ->method('log') - ->withConsecutive( - [$this->equalTo(LogLevel::WARNING), $this->equalTo('Dummy log')], - [$this->equalTo(LogLevel::DEBUG), $this->equalTo('User Warning: Silenced warning')] - ) - ; - - $handler->setDefaultLogger($logger, [\E_USER_WARNING => LogLevel::WARNING]); - - ErrorHandler::stackErrors(); - @trigger_error('Silenced warning', \E_USER_WARNING); - $logger->log(LogLevel::WARNING, 'Dummy log'); - ErrorHandler::unstackErrors(); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - public function testBootstrappingLogger() - { - $bootLogger = new BufferingLogger(); - $handler = new ErrorHandler($bootLogger); - - $loggers = [ - \E_DEPRECATED => [$bootLogger, LogLevel::INFO], - \E_USER_DEPRECATED => [$bootLogger, LogLevel::INFO], - \E_NOTICE => [$bootLogger, LogLevel::WARNING], - \E_USER_NOTICE => [$bootLogger, LogLevel::WARNING], - \E_STRICT => [$bootLogger, LogLevel::WARNING], - \E_WARNING => [$bootLogger, LogLevel::WARNING], - \E_USER_WARNING => [$bootLogger, LogLevel::WARNING], - \E_COMPILE_WARNING => [$bootLogger, LogLevel::WARNING], - \E_CORE_WARNING => [$bootLogger, LogLevel::WARNING], - \E_USER_ERROR => [$bootLogger, LogLevel::CRITICAL], - \E_RECOVERABLE_ERROR => [$bootLogger, LogLevel::CRITICAL], - \E_COMPILE_ERROR => [$bootLogger, LogLevel::CRITICAL], - \E_PARSE => [$bootLogger, LogLevel::CRITICAL], - \E_ERROR => [$bootLogger, LogLevel::CRITICAL], - \E_CORE_ERROR => [$bootLogger, LogLevel::CRITICAL], - ]; - - $this->assertSame($loggers, $handler->setLoggers([])); - - $handler->handleError(\E_DEPRECATED, 'Foo message', __FILE__, 123, []); - - $logs = $bootLogger->cleanLogs(); - - $this->assertCount(1, $logs); - $log = $logs[0]; - $this->assertSame('info', $log[0]); - $this->assertSame('Deprecated: Foo message', $log[1]); - $this->assertArrayHasKey('exception', $log[2]); - $exception = $log[2]['exception']; - $this->assertInstanceOf(\ErrorException::class, $exception); - $this->assertSame('Deprecated: Foo message', $exception->getMessage()); - $this->assertSame(__FILE__, $exception->getFile()); - $this->assertSame(123, $exception->getLine()); - $this->assertSame(\E_DEPRECATED, $exception->getSeverity()); - - $bootLogger->log(LogLevel::WARNING, 'Foo message', ['exception' => $exception]); - - $mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $mockLogger->expects($this->once()) - ->method('log') - ->with(LogLevel::WARNING, 'Foo message', ['exception' => $exception]); - - $handler->setLoggers([\E_DEPRECATED => [$mockLogger, LogLevel::WARNING]]); - } - - /** - * @group no-hhvm - */ - public function testSettingLoggerWhenExceptionIsBuffered() - { - $bootLogger = new BufferingLogger(); - $handler = new ErrorHandler($bootLogger); - - $exception = new \Exception('Foo message'); - - $mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $mockLogger->expects($this->once()) - ->method('log') - ->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', ['exception' => $exception]); - - $handler->setExceptionHandler(function () use ($handler, $mockLogger) { - $handler->setDefaultLogger($mockLogger); - }); - - $handler->handleException($exception); - } - - /** - * @group no-hhvm - */ - public function testHandleFatalError() - { - try { - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $handler = ErrorHandler::register(); - - $error = [ - 'type' => \E_PARSE, - 'message' => 'foo', - 'file' => 'bar', - 'line' => 123, - ]; - - $logArgCheck = function ($level, $message, $context) { - $this->assertEquals('Fatal Parse Error: foo', $message); - $this->assertArrayHasKey('exception', $context); - $this->assertInstanceOf(\Exception::class, $context['exception']); - }; - - $logger - ->expects($this->once()) - ->method('log') - ->willReturnCallback($logArgCheck) - ; - - $handler->setDefaultLogger($logger, \E_PARSE); - - $handler->handleFatalError($error); - - restore_error_handler(); - restore_exception_handler(); - } catch (\Exception $e) { - restore_error_handler(); - restore_exception_handler(); - - throw $e; - } - } - - /** - * @requires PHP 7 - */ - public function testHandleErrorException() - { - $exception = new \Error("Class 'IReallyReallyDoNotExistAnywhereInTheRepositoryISwear' not found"); - - $handler = new ErrorHandler(); - $handler->setExceptionHandler(function () use (&$args) { - $args = \func_get_args(); - }); - - $handler->handleException($exception); - - $this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $args[0]); - $this->assertStringStartsWith("Attempted to load class \"IReallyReallyDoNotExistAnywhereInTheRepositoryISwear\" from the global namespace.\nDid you forget a \"use\" statement", $args[0]->getMessage()); - } - - /** - * @group no-hhvm - */ - public function testHandleFatalErrorOnHHVM() - { - if (!\defined('HHVM_VERSION')) { - $this->markTestSkipped('This test requires HHVM.'); - } - - try { - $handler = ErrorHandler::register(); - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $logger - ->expects($this->once()) - ->method('log') - ->with( - $this->equalTo(LogLevel::CRITICAL), - $this->equalTo('Fatal Error: foo') - ) - ; - - $handler->setDefaultLogger($logger, \E_ERROR); - - $error = [ - 'type' => \E_ERROR + 0x1000000, // This error level is used by HHVM for fatal errors - 'message' => 'foo', - 'file' => 'bar', - 'line' => 123, - 'context' => [123], - 'backtrace' => [456], - ]; - - \call_user_func_array([$handler, 'handleError'], $error); - $handler->handleFatalError($error); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - /** - * @group no-hhvm - */ - public function testCustomExceptionHandler() - { - $this->expectException('Exception'); - $handler = new ErrorHandler(); - $handler->setExceptionHandler(function ($e) use ($handler) { - $handler->handleException($e); - }); - - $handler->handleException(new \Exception()); - } - - /** - * @dataProvider errorHandlerWhenLoggingProvider - */ - public function testErrorHandlerWhenLogging($previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined) - { - try { - if ($previousHandlerWasDefined) { - set_error_handler('count'); - } - - $logger = $loggerSetsAnotherHandler ? new LoggerThatSetAnErrorHandler() : new NullLogger(); - - $handler = ErrorHandler::register(); - $handler->setDefaultLogger($logger); - - if ($nextHandlerIsDefined) { - $handler = ErrorHandlerThatUsesThePreviousOne::register(); - } - - @trigger_error('foo', \E_USER_DEPRECATED); - @trigger_error('bar', \E_USER_DEPRECATED); - - $this->assertSame([$handler, 'handleError'], set_error_handler('var_dump')); - - if ($logger instanceof LoggerThatSetAnErrorHandler) { - $this->assertCount(2, $logger->cleanLogs()); - } - - restore_error_handler(); - - if ($previousHandlerWasDefined) { - restore_error_handler(); - } - - if ($nextHandlerIsDefined) { - restore_error_handler(); - } - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - public function errorHandlerWhenLoggingProvider() - { - foreach ([false, true] as $previousHandlerWasDefined) { - foreach ([false, true] as $loggerSetsAnotherHandler) { - foreach ([false, true] as $nextHandlerIsDefined) { - yield [$previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined]; - } - } - } - } -} diff --git a/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php b/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php deleted file mode 100644 index 7143e5d7..00000000 --- a/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php +++ /dev/null @@ -1,314 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests\Exception; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\Exception\FlattenException; -use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; -use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; -use Symfony\Component\HttpKernel\Exception\ConflictHttpException; -use Symfony\Component\HttpKernel\Exception\GoneHttpException; -use Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException; -use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; -use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException; -use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException; -use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException; -use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; -use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; -use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException; - -class FlattenExceptionTest extends TestCase -{ - public function testStatusCode() - { - $flattened = FlattenException::create(new \RuntimeException(), 403); - $this->assertEquals('403', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new \RuntimeException()); - $this->assertEquals('500', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new NotFoundHttpException()); - $this->assertEquals('404', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new UnauthorizedHttpException('Basic realm="My Realm"')); - $this->assertEquals('401', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new BadRequestHttpException()); - $this->assertEquals('400', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new NotAcceptableHttpException()); - $this->assertEquals('406', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new ConflictHttpException()); - $this->assertEquals('409', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new MethodNotAllowedHttpException(['POST'])); - $this->assertEquals('405', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new AccessDeniedHttpException()); - $this->assertEquals('403', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new GoneHttpException()); - $this->assertEquals('410', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new LengthRequiredHttpException()); - $this->assertEquals('411', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new PreconditionFailedHttpException()); - $this->assertEquals('412', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new PreconditionRequiredHttpException()); - $this->assertEquals('428', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new ServiceUnavailableHttpException()); - $this->assertEquals('503', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new TooManyRequestsHttpException()); - $this->assertEquals('429', $flattened->getStatusCode()); - - $flattened = FlattenException::create(new UnsupportedMediaTypeHttpException()); - $this->assertEquals('415', $flattened->getStatusCode()); - - if (class_exists(SuspiciousOperationException::class)) { - $flattened = FlattenException::create(new SuspiciousOperationException()); - $this->assertEquals('400', $flattened->getStatusCode()); - } - } - - public function testHeadersForHttpException() - { - $flattened = FlattenException::create(new MethodNotAllowedHttpException(['POST'])); - $this->assertEquals(['Allow' => 'POST'], $flattened->getHeaders()); - - $flattened = FlattenException::create(new UnauthorizedHttpException('Basic realm="My Realm"')); - $this->assertEquals(['WWW-Authenticate' => 'Basic realm="My Realm"'], $flattened->getHeaders()); - - $flattened = FlattenException::create(new ServiceUnavailableHttpException('Fri, 31 Dec 1999 23:59:59 GMT')); - $this->assertEquals(['Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'], $flattened->getHeaders()); - - $flattened = FlattenException::create(new ServiceUnavailableHttpException(120)); - $this->assertEquals(['Retry-After' => 120], $flattened->getHeaders()); - - $flattened = FlattenException::create(new TooManyRequestsHttpException('Fri, 31 Dec 1999 23:59:59 GMT')); - $this->assertEquals(['Retry-After' => 'Fri, 31 Dec 1999 23:59:59 GMT'], $flattened->getHeaders()); - - $flattened = FlattenException::create(new TooManyRequestsHttpException(120)); - $this->assertEquals(['Retry-After' => 120], $flattened->getHeaders()); - } - - /** - * @dataProvider flattenDataProvider - */ - public function testFlattenHttpException(\Exception $exception) - { - $flattened = FlattenException::create($exception); - $flattened2 = FlattenException::create($exception); - - $flattened->setPrevious($flattened2); - - $this->assertEquals($exception->getMessage(), $flattened->getMessage(), 'The message is copied from the original exception.'); - $this->assertEquals($exception->getCode(), $flattened->getCode(), 'The code is copied from the original exception.'); - $this->assertInstanceOf($flattened->getClass(), $exception, 'The class is set to the class of the original exception'); - } - - /** - * @dataProvider flattenDataProvider - */ - public function testPrevious(\Exception $exception) - { - $flattened = FlattenException::create($exception); - $flattened2 = FlattenException::create($exception); - - $flattened->setPrevious($flattened2); - - $this->assertSame($flattened2, $flattened->getPrevious()); - - $this->assertSame([$flattened2], $flattened->getAllPrevious()); - } - - /** - * @requires PHP 7.0 - */ - public function testPreviousError() - { - $exception = new \Exception('test', 123, new \ParseError('Oh noes!', 42)); - - $flattened = FlattenException::create($exception)->getPrevious(); - - $this->assertEquals('Parse error: Oh noes!', $flattened->getMessage(), 'The message is copied from the original exception.'); - $this->assertEquals(42, $flattened->getCode(), 'The code is copied from the original exception.'); - $this->assertEquals('Symfony\Component\Debug\Exception\FatalThrowableError', $flattened->getClass(), 'The class is set to the class of the original exception'); - } - - /** - * @dataProvider flattenDataProvider - */ - public function testLine(\Exception $exception) - { - $flattened = FlattenException::create($exception); - $this->assertSame($exception->getLine(), $flattened->getLine()); - } - - /** - * @dataProvider flattenDataProvider - */ - public function testFile(\Exception $exception) - { - $flattened = FlattenException::create($exception); - $this->assertSame($exception->getFile(), $flattened->getFile()); - } - - /** - * @dataProvider flattenDataProvider - */ - public function testToArray(\Exception $exception) - { - $flattened = FlattenException::create($exception); - $flattened->setTrace([], 'foo.php', 123); - - $this->assertEquals([ - [ - 'message' => 'test', - 'class' => 'Exception', - 'trace' => [[ - 'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123, - 'args' => [], - ]], - ], - ], $flattened->toArray()); - } - - public function flattenDataProvider() - { - return [ - [new \Exception('test', 123)], - ]; - } - - public function testArguments() - { - if (\PHP_VERSION_ID >= 70400) { - $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); - } - - $dh = opendir(__DIR__); - $fh = tmpfile(); - - $incomplete = unserialize('O:14:"BogusTestClass":0:{}'); - - $exception = $this->createException([ - (object) ['foo' => 1], - new NotFoundHttpException(), - $incomplete, - $dh, - $fh, - function () {}, - [1, 2], - ['foo' => 123], - null, - true, - false, - 0, - 0.0, - '0', - '', - \INF, - \NAN, - ]); - - $flattened = FlattenException::create($exception); - $trace = $flattened->getTrace(); - $args = $trace[1]['args']; - $array = $args[0][1]; - - closedir($dh); - fclose($fh); - - $i = 0; - $this->assertSame(['object', 'stdClass'], $array[$i++]); - $this->assertSame(['object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'], $array[$i++]); - $this->assertSame(['incomplete-object', 'BogusTestClass'], $array[$i++]); - $this->assertSame(['resource', \defined('HHVM_VERSION') ? 'Directory' : 'stream'], $array[$i++]); - $this->assertSame(['resource', 'stream'], $array[$i++]); - - $args = $array[$i++]; - $this->assertSame($args[0], 'object'); - $this->assertTrue('Closure' === $args[1] || is_subclass_of($args[1], '\Closure'), 'Expect object class name to be Closure or a subclass of Closure.'); - - $this->assertSame(['array', [['integer', 1], ['integer', 2]]], $array[$i++]); - $this->assertSame(['array', ['foo' => ['integer', 123]]], $array[$i++]); - $this->assertSame(['null', null], $array[$i++]); - $this->assertSame(['boolean', true], $array[$i++]); - $this->assertSame(['boolean', false], $array[$i++]); - $this->assertSame(['integer', 0], $array[$i++]); - $this->assertSame(['float', 0.0], $array[$i++]); - $this->assertSame(['string', '0'], $array[$i++]); - $this->assertSame(['string', ''], $array[$i++]); - $this->assertSame(['float', \INF], $array[$i++]); - - // assertEquals() does not like NAN values. - $this->assertEquals('float', $array[$i][0]); - $this->assertNan($array[$i][1]); - } - - public function testRecursionInArguments() - { - if (\PHP_VERSION_ID >= 70400) { - $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); - } - - $a = null; - $a = ['foo', [2, &$a]]; - $exception = $this->createException($a); - - $flattened = FlattenException::create($exception); - $trace = $flattened->getTrace(); - $this->assertStringContainsString('*DEEP NESTED ARRAY*', serialize($trace)); - } - - public function testTooBigArray() - { - if (\PHP_VERSION_ID >= 70400) { - $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); - } - - $a = []; - for ($i = 0; $i < 20; ++$i) { - for ($j = 0; $j < 50; ++$j) { - for ($k = 0; $k < 10; ++$k) { - $a[$i][$j][$k] = 'value'; - } - } - } - $a[20] = 'value'; - $a[21] = 'value1'; - $exception = $this->createException($a); - - $flattened = FlattenException::create($exception); - $trace = $flattened->getTrace(); - - $this->assertSame($trace[1]['args'][0], ['array', ['array', '*SKIPPED over 10000 entries*']]); - - $serializeTrace = serialize($trace); - - $this->assertStringContainsString('*SKIPPED over 10000 entries*', $serializeTrace); - $this->assertStringNotContainsString('*value1*', $serializeTrace); - } - - private function createException($foo) - { - return new \Exception(); - } -} diff --git a/vendor/symfony/debug/Tests/ExceptionHandlerTest.php b/vendor/symfony/debug/Tests/ExceptionHandlerTest.php deleted file mode 100644 index 3ed3cfa5..00000000 --- a/vendor/symfony/debug/Tests/ExceptionHandlerTest.php +++ /dev/null @@ -1,163 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\Exception\OutOfMemoryException; -use Symfony\Component\Debug\ExceptionHandler; -use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; - -require_once __DIR__.'/HeaderMock.php'; - -class ExceptionHandlerTest extends TestCase -{ - protected function setUp() - { - testHeader(); - } - - protected function tearDown() - { - testHeader(); - } - - public function testDebug() - { - $handler = new ExceptionHandler(false); - - ob_start(); - $handler->sendPhpResponse(new \RuntimeException('Foo')); - $response = ob_get_clean(); - - $this->assertStringContainsString('Whoops, looks like something went wrong.', $response); - $this->assertStringNotContainsString('
', $response); - - $handler = new ExceptionHandler(true); - - ob_start(); - $handler->sendPhpResponse(new \RuntimeException('Foo')); - $response = ob_get_clean(); - - $this->assertStringContainsString('Whoops, looks like something went wrong.', $response); - $this->assertStringContainsString('
', $response); - } - - public function testStatusCode() - { - $handler = new ExceptionHandler(false, 'iso8859-1'); - - ob_start(); - $handler->sendPhpResponse(new NotFoundHttpException('Foo')); - $response = ob_get_clean(); - - $this->assertStringContainsString('Sorry, the page you are looking for could not be found.', $response); - - $expectedHeaders = [ - ['HTTP/1.0 404', true, null], - ['Content-Type: text/html; charset=iso8859-1', true, null], - ]; - - $this->assertSame($expectedHeaders, testHeader()); - } - - public function testHeaders() - { - $handler = new ExceptionHandler(false, 'iso8859-1'); - - ob_start(); - $handler->sendPhpResponse(new MethodNotAllowedHttpException(['POST'])); - ob_get_clean(); - - $expectedHeaders = [ - ['HTTP/1.0 405', true, null], - ['Allow: POST', false, null], - ['Content-Type: text/html; charset=iso8859-1', true, null], - ]; - - $this->assertSame($expectedHeaders, testHeader()); - } - - public function testNestedExceptions() - { - $handler = new ExceptionHandler(true); - ob_start(); - $handler->sendPhpResponse(new \RuntimeException('Foo', 0, new \RuntimeException('Bar'))); - $response = ob_get_clean(); - - $this->assertStringMatchesFormat('%A

Foo

%A

Bar

%A', $response); - } - - public function testHandle() - { - $handler = new ExceptionHandler(true); - ob_start(); - - $handler->handle(new \Exception('foo')); - - $this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'foo'); - } - - public function testHandleWithACustomHandlerThatOutputsSomething() - { - $handler = new ExceptionHandler(true); - ob_start(); - $handler->setHandler(function () { - echo 'ccc'; - }); - - $handler->handle(new \Exception()); - ob_end_flush(); // Necessary because of this PHP bug : https://bugs.php.net/76563 - $this->assertSame('ccc', ob_get_clean()); - } - - public function testHandleWithACustomHandlerThatOutputsNothing() - { - $handler = new ExceptionHandler(true); - $handler->setHandler(function () {}); - - $handler->handle(new \Exception('ccc')); - - $this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc'); - } - - public function testHandleWithACustomHandlerThatFails() - { - $handler = new ExceptionHandler(true); - $handler->setHandler(function () { - throw new \RuntimeException(); - }); - - $handler->handle(new \Exception('ccc')); - - $this->assertThatTheExceptionWasOutput(ob_get_clean(), \Exception::class, 'Exception', 'ccc'); - } - - public function testHandleOutOfMemoryException() - { - $handler = new ExceptionHandler(true); - ob_start(); - $handler->setHandler(function () { - $this->fail('OutOfMemoryException should bypass the handler'); - }); - - $handler->handle(new OutOfMemoryException('foo', 0, \E_ERROR, __FILE__, __LINE__)); - - $this->assertThatTheExceptionWasOutput(ob_get_clean(), OutOfMemoryException::class, 'OutOfMemoryException', 'foo'); - } - - private function assertThatTheExceptionWasOutput($content, $expectedClass, $expectedTitle, $expectedMessage) - { - $this->assertStringContainsString(sprintf('%s', $expectedClass, $expectedTitle), $content); - $this->assertStringContainsString(sprintf('

%s

', $expectedMessage), $content); - } -} diff --git a/vendor/symfony/debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php b/vendor/symfony/debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php deleted file mode 100644 index 2b8a8678..00000000 --- a/vendor/symfony/debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php +++ /dev/null @@ -1,220 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests\FatalErrorHandler; - -use Composer\Autoload\ClassLoader as ComposerClassLoader; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\DebugClassLoader; -use Symfony\Component\Debug\Exception\FatalErrorException; -use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler; - -class ClassNotFoundFatalErrorHandlerTest extends TestCase -{ - public static function setUpBeforeClass() - { - foreach (spl_autoload_functions() as $function) { - if (!\is_array($function)) { - continue; - } - - // get class loaders wrapped by DebugClassLoader - if ($function[0] instanceof DebugClassLoader) { - $function = $function[0]->getClassLoader(); - - if (!\is_array($function)) { - continue; - } - } - - if ($function[0] instanceof ComposerClassLoader) { - $function[0]->add('Symfony_Component_Debug_Tests_Fixtures', \dirname(\dirname(\dirname(\dirname(\dirname(__DIR__)))))); - break; - } - } - } - - /** - * @dataProvider provideClassNotFoundData - */ - public function testHandleClassNotFound($error, $translatedMessage, $autoloader = null) - { - if ($autoloader) { - // Unregister all autoloaders to ensure the custom provided - // autoloader is the only one to be used during the test run. - $autoloaders = spl_autoload_functions(); - array_map('spl_autoload_unregister', $autoloaders); - spl_autoload_register($autoloader); - } - - $handler = new ClassNotFoundFatalErrorHandler(); - - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - if ($autoloader) { - spl_autoload_unregister($autoloader); - array_map('spl_autoload_register', $autoloaders); - } - - $this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception); - $this->assertMatchesRegularExpression($translatedMessage, $exception->getMessage()); - $this->assertSame($error['type'], $exception->getSeverity()); - $this->assertSame($error['file'], $exception->getFile()); - $this->assertSame($error['line'], $exception->getLine()); - } - - public function provideClassNotFoundData() - { - $autoloader = new ComposerClassLoader(); - $autoloader->add('Symfony\Component\Debug\Exception\\', realpath(__DIR__.'/../../Exception')); - $autoloader->add('Symfony_Component_Debug_Tests_Fixtures', realpath(__DIR__.'/../../Tests/Fixtures')); - - $debugClassLoader = new DebugClassLoader([$autoloader, 'loadClass']); - - return [ - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class "WhizBangFactory" not found', - ], - "/^Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement\?$/", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'WhizBangFactory\' not found', - ], - "/^Attempted to load class \"WhizBangFactory\" from the global namespace.\nDid you forget a \"use\" statement\?$/", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\WhizBangFactory\' not found', - ], - "/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class "Foo\\Bar\\WhizBangFactory" not found', - ], - "/^Attempted to load class \"WhizBangFactory\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Interface "Foo\\Bar\\WhizBangInterface" not found', - ], - "/^Attempted to load interface \"WhizBangInterface\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Trait "Foo\\Bar\\WhizBangTrait" not found', - ], - "/^Attempted to load trait \"WhizBangTrait\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'UndefinedFunctionException\' not found', - ], - "/^Attempted to load class \"UndefinedFunctionException\" from the global namespace.\nDid you forget a \"use\" statement for .*\"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'PEARClass\' not found', - ], - "/^Attempted to load class \"PEARClass\" from the global namespace.\nDid you forget a \"use\" statement for \"Symfony_Component_Debug_Tests_Fixtures_PEARClass\"\?$/", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for .*\"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for \"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?$/", - [$autoloader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for \"Symfony\\\\Component\\\\Debug\\\\Exception\\\\UndefinedFunctionException\"\?/", - [$debugClassLoader, 'loadClass'], - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\UndefinedFunctionException\' not found', - ], - "/^Attempted to load class \"UndefinedFunctionException\" from namespace \"Foo\\\\Bar\".\nDid you forget a \"use\" statement for another namespace\?$/", - function ($className) { /* do nothing here */ }, - ], - ]; - } - - public function testCannotRedeclareClass() - { - if (!file_exists(__DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP')) { - $this->markTestSkipped('Can only be run on case insensitive filesystems'); - } - - require_once __DIR__.'/../FIXTURES2/REQUIREDTWICE.PHP'; - - $error = [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Class \'Foo\\Bar\\RequiredTwice\' not found', - ]; - - $handler = new ClassNotFoundFatalErrorHandler(); - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - $this->assertInstanceOf('Symfony\Component\Debug\Exception\ClassNotFoundException', $exception); - } -} diff --git a/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php b/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php deleted file mode 100644 index 2de44a25..00000000 --- a/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests\FatalErrorHandler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\Exception\FatalErrorException; -use Symfony\Component\Debug\FatalErrorHandler\UndefinedFunctionFatalErrorHandler; - -class UndefinedFunctionFatalErrorHandlerTest extends TestCase -{ - /** - * @dataProvider provideUndefinedFunctionData - */ - public function testUndefinedFunction($error, $translatedMessage) - { - $handler = new UndefinedFunctionFatalErrorHandler(); - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - $this->assertInstanceOf('Symfony\Component\Debug\Exception\UndefinedFunctionException', $exception); - // class names are case insensitive and PHP/HHVM do not return the same - $this->assertSame(strtolower($translatedMessage), strtolower($exception->getMessage())); - $this->assertSame($error['type'], $exception->getSeverity()); - $this->assertSame($error['file'], $exception->getFile()); - $this->assertSame($error['line'], $exception->getLine()); - } - - public function provideUndefinedFunctionData() - { - return [ - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function test_namespaced_function()', - ], - "Attempted to call function \"test_namespaced_function\" from the global namespace.\nDid you mean to call \"\\symfony\\component\\debug\\tests\\fatalerrorhandler\\test_namespaced_function\"?", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function Foo\\Bar\\Baz\\test_namespaced_function()', - ], - "Attempted to call function \"test_namespaced_function\" from namespace \"Foo\\Bar\\Baz\".\nDid you mean to call \"\\symfony\\component\\debug\\tests\\fatalerrorhandler\\test_namespaced_function\"?", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function foo()', - ], - 'Attempted to call function "foo" from the global namespace.', - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined function Foo\\Bar\\Baz\\foo()', - ], - 'Attempted to call function "foo" from namespace "Foo\Bar\Baz".', - ], - ]; - } -} - -function test_namespaced_function() -{ -} diff --git a/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php b/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php deleted file mode 100644 index 268a8413..00000000 --- a/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedMethodFatalErrorHandlerTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug\Tests\FatalErrorHandler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\Exception\FatalErrorException; -use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler; - -class UndefinedMethodFatalErrorHandlerTest extends TestCase -{ - /** - * @dataProvider provideUndefinedMethodData - */ - public function testUndefinedMethod($error, $translatedMessage) - { - $handler = new UndefinedMethodFatalErrorHandler(); - $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); - - $this->assertInstanceOf('Symfony\Component\Debug\Exception\UndefinedMethodException', $exception); - $this->assertSame($translatedMessage, $exception->getMessage()); - $this->assertSame($error['type'], $exception->getSeverity()); - $this->assertSame($error['file'], $exception->getFile()); - $this->assertSame($error['line'], $exception->getLine()); - } - - public function provideUndefinedMethodData() - { - return [ - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined method SplObjectStorage::what()', - ], - 'Attempted to call an undefined method named "what" of class "SplObjectStorage".', - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined method SplObjectStorage::walid()', - ], - "Attempted to call an undefined method named \"walid\" of class \"SplObjectStorage\".\nDid you mean to call \"valid\"?", - ], - [ - [ - 'type' => 1, - 'line' => 12, - 'file' => 'foo.php', - 'message' => 'Call to undefined method SplObjectStorage::offsetFet()', - ], - "Attempted to call an undefined method named \"offsetFet\" of class \"SplObjectStorage\".\nDid you mean to call e.g. \"offsetGet\", \"offsetSet\" or \"offsetUnset\"?", - ], - [ - [ - 'type' => 1, - 'message' => 'Call to undefined method class@anonymous::test()', - 'file' => '/home/possum/work/symfony/test.php', - 'line' => 11, - ], - 'Attempted to call an undefined method named "test" of class "class@anonymous".', - ], - ]; - } -} diff --git a/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php b/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php deleted file mode 100644 index dff9517d..00000000 --- a/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php +++ /dev/null @@ -1,13 +0,0 @@ -exception = $e; - } - - public function __toString() - { - try { - throw $this->exception; - } catch (\Exception $e) { - // Using user_error() here is on purpose so we do not forget - // that this alias also should work alongside with trigger_error(). - return trigger_error($e, E_USER_ERROR); - } - } -} diff --git a/vendor/symfony/debug/Tests/Fixtures/TraitWithInternalMethod.php b/vendor/symfony/debug/Tests/Fixtures/TraitWithInternalMethod.php deleted file mode 100644 index 4c3dae37..00000000 --- a/vendor/symfony/debug/Tests/Fixtures/TraitWithInternalMethod.php +++ /dev/null @@ -1,13 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Debug; - -function headers_sent() -{ - return false; -} - -function header($str, $replace = true, $status = null) -{ - Tests\testHeader($str, $replace, $status); -} - -namespace Symfony\Component\Debug\Tests; - -function testHeader() -{ - static $headers = []; - - if (!$h = \func_get_args()) { - $h = $headers; - $headers = []; - - return $h; - } - - $headers[] = \func_get_args(); -} diff --git a/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt b/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt deleted file mode 100644 index 26b3abf4..00000000 --- a/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -Test DebugClassLoader with previously loaded parents ---FILE-- - ---EXPECTF-- -The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod". -The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod". diff --git a/vendor/symfony/debug/Tests/phpt/decorate_exception_hander.phpt b/vendor/symfony/debug/Tests/phpt/decorate_exception_hander.phpt deleted file mode 100644 index 9cd44388..00000000 --- a/vendor/symfony/debug/Tests/phpt/decorate_exception_hander.phpt +++ /dev/null @@ -1,47 +0,0 @@ ---TEST-- -Test catching fatal errors when handlers are nested ---INI-- -display_errors=0 ---FILE-- - ---EXPECTF-- -object(Symfony\Component\Debug\Exception\ClassNotFoundException)#%d (8) { - ["message":protected]=> - string(131) "Attempted to load class "missing" from namespace "Symfony\Component\Debug". -Did you forget a "use" statement for another namespace?" - ["string":"Exception":private]=> - string(0) "" - ["code":protected]=> - int(0) - ["file":protected]=> - string(%d) "%s" - ["line":protected]=> - int(%d) - ["trace":"Exception":private]=> - array(%d) {%A} - ["previous":"Exception":private]=> - NULL - ["severity":protected]=> - int(1) -} diff --git a/vendor/symfony/debug/Tests/phpt/exception_rethrown.phpt b/vendor/symfony/debug/Tests/phpt/exception_rethrown.phpt deleted file mode 100644 index b743d93a..00000000 --- a/vendor/symfony/debug/Tests/phpt/exception_rethrown.phpt +++ /dev/null @@ -1,35 +0,0 @@ ---TEST-- -Test rethrowing in custom exception handler ---FILE-- -setDefaultLogger(new TestLogger()); -ini_set('display_errors', 1); - -throw new \Exception('foo'); -?> ---EXPECTF-- -Uncaught Exception: foo -123 -Fatal error: Uncaught %s:25 -Stack trace: -%a diff --git a/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt b/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt deleted file mode 100644 index b3f0e0eb..00000000 --- a/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -Test catching fatal errors when handlers are nested ---FILE-- -setExceptionHandler('print_r'); - -if (true) { - class Broken implements \Serializable - { - } -} - -?> ---EXPECTF-- -array(1) { - [0]=> - string(37) "Error and exception handlers do match" -} -object(Symfony\Component\Debug\Exception\FatalErrorException)#%d (%d) { - ["message":protected]=> - string(199) "Error: Class Symfony\Component\Debug\Broken contains 2 abstract methods and must therefore be declared abstract or implement the remaining methods (Serializable::serialize, Serializable::unserialize)" -%a -} diff --git a/vendor/symfony/debug/composer.json b/vendor/symfony/debug/composer.json index 223d2bab..01e8f783 100644 --- a/vendor/symfony/debug/composer.json +++ b/vendor/symfony/debug/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/debug", "type": "library", - "description": "Symfony Debug Component", + "description": "Provides tools to ease debugging PHP code", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,14 +16,14 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "psr/log": "~1.0" + "php": ">=7.1.3", + "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "symfony/http-kernel": "^3.4|^4.0|^5.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Debug\\": "" }, diff --git a/vendor/symfony/debug/phpunit.xml.dist b/vendor/symfony/debug/phpunit.xml.dist deleted file mode 100644 index a51bbff9..00000000 --- a/vendor/symfony/debug/phpunit.xml.dist +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - ./Tests/ - - - ./Resources/ext/tests/ - - - - - - ./ - - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/dependency-injection/Alias.php b/vendor/symfony/dependency-injection/Alias.php index de14c5ea..248eeefa 100644 --- a/vendor/symfony/dependency-injection/Alias.php +++ b/vendor/symfony/dependency-injection/Alias.php @@ -11,21 +11,24 @@ namespace Symfony\Component\DependencyInjection; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; + class Alias { + private const DEFAULT_DEPRECATION_TEMPLATE = 'The "%alias_id%" service alias is deprecated. You should stop using it, as it will be removed in the future.'; + private $id; private $public; private $private; + private $deprecated; + private $deprecationTemplate; - /** - * @param string $id Alias identifier - * @param bool $public If this alias is public - */ - public function __construct($id, $public = true) + public function __construct(string $id, bool $public = true) { - $this->id = (string) $id; + $this->id = $id; $this->public = $public; $this->private = 2 > \func_num_args(); + $this->deprecated = false; } /** @@ -82,6 +85,46 @@ public function isPrivate() return $this->private; } + /** + * Whether this alias is deprecated, that means it should not be referenced + * anymore. + * + * @param bool $status Whether this alias is deprecated, defaults to true + * @param string $template Optional template message to use if the alias is deprecated + * + * @return $this + * + * @throws InvalidArgumentException when the message template is invalid + */ + public function setDeprecated($status = true, $template = null) + { + if (null !== $template) { + if (preg_match('#[\r\n]|\*/#', $template)) { + throw new InvalidArgumentException('Invalid characters found in deprecation template.'); + } + + if (!str_contains($template, '%alias_id%')) { + throw new InvalidArgumentException('The deprecation template must contain the "%alias_id%" placeholder.'); + } + + $this->deprecationTemplate = $template; + } + + $this->deprecated = (bool) $status; + + return $this; + } + + public function isDeprecated(): bool + { + return $this->deprecated; + } + + public function getDeprecationMessage(string $id): string + { + return str_replace('%alias_id%', $id, $this->deprecationTemplate ?: self::DEFAULT_DEPRECATION_TEMPLATE); + } + /** * Returns the Id of this alias. * diff --git a/vendor/symfony/dependency-injection/Argument/BoundArgument.php b/vendor/symfony/dependency-injection/Argument/BoundArgument.php index a2069844..c2afe2cf 100644 --- a/vendor/symfony/dependency-injection/Argument/BoundArgument.php +++ b/vendor/symfony/dependency-injection/Argument/BoundArgument.php @@ -16,24 +16,36 @@ */ final class BoundArgument implements ArgumentInterface { + public const SERVICE_BINDING = 0; + public const DEFAULTS_BINDING = 1; + public const INSTANCEOF_BINDING = 2; + private static $sequence = 0; private $value; private $identifier; private $used; + private $type; + private $file; - public function __construct($value) + public function __construct($value, bool $trackUsage = true, int $type = 0, string $file = null) { $this->value = $value; - $this->identifier = ++self::$sequence; + if ($trackUsage) { + $this->identifier = ++self::$sequence; + } else { + $this->used = true; + } + $this->type = $type; + $this->file = $file; } /** * {@inheritdoc} */ - public function getValues() + public function getValues(): array { - return [$this->value, $this->identifier, $this->used]; + return [$this->value, $this->identifier, $this->used, $this->type, $this->file]; } /** @@ -41,6 +53,10 @@ public function getValues() */ public function setValues(array $values) { - list($this->value, $this->identifier, $this->used) = $values; + if (5 === \count($values)) { + [$this->value, $this->identifier, $this->used, $this->type, $this->file] = $values; + } else { + [$this->value, $this->identifier, $this->used] = $values; + } } } diff --git a/vendor/symfony/dependency-injection/Argument/IteratorArgument.php b/vendor/symfony/dependency-injection/Argument/IteratorArgument.php index 2d796d2d..d413678a 100644 --- a/vendor/symfony/dependency-injection/Argument/IteratorArgument.php +++ b/vendor/symfony/dependency-injection/Argument/IteratorArgument.php @@ -11,9 +11,6 @@ namespace Symfony\Component\DependencyInjection\Argument; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; -use Symfony\Component\DependencyInjection\Reference; - /** * Represents a collection of values to lazily iterate over. * @@ -21,35 +18,5 @@ */ class IteratorArgument implements ArgumentInterface { - private $values; - - /** - * @param Reference[] $values - */ - public function __construct(array $values) - { - $this->setValues($values); - } - - /** - * @return array The values to lazily iterate over - */ - public function getValues() - { - return $this->values; - } - - /** - * @param Reference[] $values The service references to lazily iterate over - */ - public function setValues(array $values) - { - foreach ($values as $k => $v) { - if (null !== $v && !$v instanceof Reference) { - throw new InvalidArgumentException(sprintf('An IteratorArgument must hold only Reference instances, "%s" given.', \is_object($v) ? \get_class($v) : \gettype($v))); - } - } - - $this->values = $values; - } + use ReferenceSetArgumentTrait; } diff --git a/vendor/symfony/dependency-injection/Argument/ReferenceSetArgumentTrait.php b/vendor/symfony/dependency-injection/Argument/ReferenceSetArgumentTrait.php new file mode 100644 index 00000000..e3946ab3 --- /dev/null +++ b/vendor/symfony/dependency-injection/Argument/ReferenceSetArgumentTrait.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Argument; + +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Titouan Galopin + * @author Nicolas Grekas + */ +trait ReferenceSetArgumentTrait +{ + private $values; + + /** + * @param Reference[] $values + */ + public function __construct(array $values) + { + $this->setValues($values); + } + + /** + * @return Reference[] The values in the set + */ + public function getValues() + { + return $this->values; + } + + /** + * @param Reference[] $values The service references to put in the set + */ + public function setValues(array $values) + { + foreach ($values as $k => $v) { + if (null !== $v && !$v instanceof Reference) { + throw new InvalidArgumentException(sprintf('A "%s" must hold only Reference instances, "%s" given.', __CLASS__, \is_object($v) ? \get_class($v) : \gettype($v))); + } + } + + $this->values = $values; + } +} diff --git a/vendor/symfony/dependency-injection/Argument/RewindableGenerator.php b/vendor/symfony/dependency-injection/Argument/RewindableGenerator.php index b00a36c3..41fec786 100644 --- a/vendor/symfony/dependency-injection/Argument/RewindableGenerator.php +++ b/vendor/symfony/dependency-injection/Argument/RewindableGenerator.php @@ -28,14 +28,14 @@ public function __construct(callable $generator, $count) $this->count = $count; } - public function getIterator() + public function getIterator(): \Traversable { $g = $this->generator; return $g(); } - public function count() + public function count(): int { if (\is_callable($count = $this->count)) { $this->count = $count(); diff --git a/vendor/symfony/dependency-injection/Argument/ServiceLocator.php b/vendor/symfony/dependency-injection/Argument/ServiceLocator.php new file mode 100644 index 00000000..4f3c19eb --- /dev/null +++ b/vendor/symfony/dependency-injection/Argument/ServiceLocator.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Argument; + +use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class ServiceLocator extends BaseServiceLocator +{ + private $factory; + private $serviceMap; + private $serviceTypes; + + public function __construct(\Closure $factory, array $serviceMap, array $serviceTypes = null) + { + $this->factory = $factory; + $this->serviceMap = $serviceMap; + $this->serviceTypes = $serviceTypes; + parent::__construct($serviceMap); + } + + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get($id) + { + return isset($this->serviceMap[$id]) ? ($this->factory)(...$this->serviceMap[$id]) : parent::get($id); + } + + /** + * {@inheritdoc} + */ + public function getProvidedServices(): array + { + return $this->serviceTypes ?? $this->serviceTypes = array_map(function () { return '?'; }, $this->serviceMap); + } +} diff --git a/vendor/symfony/dependency-injection/Argument/ServiceLocatorArgument.php b/vendor/symfony/dependency-injection/Argument/ServiceLocatorArgument.php new file mode 100644 index 00000000..fcbf478c --- /dev/null +++ b/vendor/symfony/dependency-injection/Argument/ServiceLocatorArgument.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Argument; + +use Symfony\Component\DependencyInjection\Reference; + +/** + * Represents a closure acting as a service locator. + * + * @author Nicolas Grekas + */ +class ServiceLocatorArgument implements ArgumentInterface +{ + use ReferenceSetArgumentTrait; + + private $taggedIteratorArgument; + + /** + * @param Reference[]|TaggedIteratorArgument $values + */ + public function __construct($values = []) + { + if ($values instanceof TaggedIteratorArgument) { + $this->taggedIteratorArgument = $values; + $this->values = []; + } else { + $this->setValues($values); + } + } + + public function getTaggedIteratorArgument(): ?TaggedIteratorArgument + { + return $this->taggedIteratorArgument; + } +} diff --git a/vendor/symfony/dependency-injection/Argument/TaggedIteratorArgument.php b/vendor/symfony/dependency-injection/Argument/TaggedIteratorArgument.php index f00e5339..1ba8de79 100644 --- a/vendor/symfony/dependency-injection/Argument/TaggedIteratorArgument.php +++ b/vendor/symfony/dependency-injection/Argument/TaggedIteratorArgument.php @@ -19,19 +19,55 @@ class TaggedIteratorArgument extends IteratorArgument { private $tag; + private $indexAttribute; + private $defaultIndexMethod; + private $defaultPriorityMethod; + private $needsIndexes = false; /** - * @param string $tag + * @param string $tag The name of the tag identifying the target services + * @param string|null $indexAttribute The name of the attribute that defines the key referencing each service in the tagged collection + * @param string|null $defaultIndexMethod The static method that should be called to get each service's key when their tag doesn't define the previous attribute + * @param bool $needsIndexes Whether indexes are required and should be generated when computing the map + * @param string|null $defaultPriorityMethod The static method that should be called to get each service's priority when their tag doesn't define the "priority" attribute */ - public function __construct($tag) + public function __construct(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, bool $needsIndexes = false, string $defaultPriorityMethod = null) { parent::__construct([]); - $this->tag = (string) $tag; + if (null === $indexAttribute && $needsIndexes) { + $indexAttribute = preg_match('/[^.]++$/', $tag, $m) ? $m[0] : $tag; + } + + $this->tag = $tag; + $this->indexAttribute = $indexAttribute; + $this->defaultIndexMethod = $defaultIndexMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Name' : null); + $this->needsIndexes = $needsIndexes; + $this->defaultPriorityMethod = $defaultPriorityMethod ?: ($indexAttribute ? 'getDefault'.str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $indexAttribute))).'Priority' : null); } public function getTag() { return $this->tag; } + + public function getIndexAttribute(): ?string + { + return $this->indexAttribute; + } + + public function getDefaultIndexMethod(): ?string + { + return $this->defaultIndexMethod; + } + + public function needsIndexes(): bool + { + return $this->needsIndexes; + } + + public function getDefaultPriorityMethod(): ?string + { + return $this->defaultPriorityMethod; + } } diff --git a/vendor/symfony/dependency-injection/CHANGELOG.md b/vendor/symfony/dependency-injection/CHANGELOG.md index a004161b..ee8583b2 100644 --- a/vendor/symfony/dependency-injection/CHANGELOG.md +++ b/vendor/symfony/dependency-injection/CHANGELOG.md @@ -1,6 +1,126 @@ CHANGELOG ========= +4.4.0 +----- + + * added `CheckTypeDeclarationsPass` to check injected parameters type during compilation + * added support for opcache.preload by generating a preloading script in the cache folder + * added support for dumping the container in one file instead of many files + * deprecated support for short factories and short configurators in Yaml + * added `tagged_iterator` alias for `tagged` which might be deprecated in a future version + * deprecated passing an instance of `Symfony\Component\DependencyInjection\Parameter` as class name to `Symfony\Component\DependencyInjection\Definition` + * added support for binding iterable and tagged services + * made singly-implemented interfaces detection be scoped by file + * added ability to define a static priority method for tagged service + * added support for improved syntax to define method calls in Yaml + * made the `%env(base64:...)%` processor able to decode base64url + * added ability to choose behavior of decorations on non existent decorated services + +4.3.0 +----- + + * added `%env(trim:...)%` processor to trim a string value + * added `%env(default:param_name:...)%` processor to fallback to a parameter or to null when using `%env(default::...)%` + * added `%env(url:...)%` processor to convert an URL or DNS into an array of components + * added `%env(query_string:...)%` processor to convert a query string into an array of key values + * added support for deprecating aliases + * made `ContainerParametersResource` final and not implement `Serializable` anymore + * added `ReverseContainer`: a container that turns services back to their ids + * added ability to define an index for a tagged collection + * added ability to define an index for services in an injected service locator argument + * made `ServiceLocator` implement `ServiceProviderInterface` + * deprecated support for non-string default env() parameters + * added `%env(require:...)%` processor to `require()` a PHP file and use the value returned from it + +4.2.0 +----- + + * added `ContainerBuilder::registerAliasForArgument()` to support autowiring by type+name + * added support for binding by type+name + * added `ServiceSubscriberTrait` to ease implementing `ServiceSubscriberInterface` using methods' return types + * added `ServiceLocatorArgument` and `!service_locator` config tag for creating optimized service-locators + * added support for autoconfiguring bindings + * added `%env(key:...)%` processor to fetch a specific key from an array + * deprecated `ServiceSubscriberInterface`, use the same interface from the `Symfony\Contracts\Service` namespace instead + * deprecated `ResettableContainerInterface`, use `Symfony\Contracts\Service\ResetInterface` instead + +4.1.0 +----- + + * added support for variadics in named arguments + * added PSR-11 `ContainerBagInterface` and its `ContainerBag` implementation to access parameters as-a-service + * added support for service's decorators autowiring + * deprecated the `TypedReference::canBeAutoregistered()` and `TypedReference::getRequiringClass()` methods + * environment variables are validated when used in extension configuration + * deprecated support for auto-discovered extension configuration class which does not implement `ConfigurationInterface` + +4.0.0 +----- + + * Relying on service auto-registration while autowiring is not supported anymore. + Explicitly inject your dependencies or create services whose ids are + their fully-qualified class name. + + Before: + + ```php + namespace App\Controller; + + use App\Mailer; + + class DefaultController + { + public function __construct(Mailer $mailer) { + // ... + } + + // ... + } + ``` + ```yml + services: + App\Controller\DefaultController: + autowire: true + ``` + + After: + + ```php + // same PHP code + ``` + ```yml + services: + App\Controller\DefaultController: + autowire: true + + # or + # App\Controller\DefaultController: + # arguments: { $mailer: "@App\Mailer" } + + App\Mailer: + autowire: true + ``` + * removed autowiring services based on the types they implement + * added a third `$methodName` argument to the `getProxyFactoryCode()` method + of the `DumperInterface` + * removed support for autowiring types + * removed `Container::isFrozen` + * removed support for dumping an ucompiled container in `PhpDumper` + * removed support for generating a dumped `Container` without populating the method map + * removed support for case insensitive service identifiers + * removed the `DefinitionDecorator` class, replaced by `ChildDefinition` + * removed the `AutowireServiceResource` class and related `AutowirePass::createResourceForClass()` method + * removed `LoggingFormatter`, `Compiler::getLoggingFormatter()` and `addLogMessage()` class and methods, use the `ContainerBuilder::log()` method instead + * removed `FactoryReturnTypePass` + * removed `ContainerBuilder::addClassResource()`, use the `addObjectResource()` or the `getReflectionClass()` method instead. + * removed support for top-level anonymous services + * removed silent behavior for unused attributes and elements + * removed support for setting and accessing private services in `Container` + * removed support for setting pre-defined services in `Container` + * removed support for case insensitivity of parameter names + * removed `AutowireExceptionPass` and `AutowirePass::getAutowiringExceptions()`, use `Definition::addError()` and the `DefinitionErrorExceptionPass` instead + 3.4.0 ----- @@ -16,7 +136,6 @@ CHANGELOG * added `TaggedIteratorArgument` with YAML (`!tagged foo`) and XML (``) support * deprecated `AutowireExceptionPass` and `AutowirePass::getAutowiringExceptions()`, use `Definition::addError()` and the `DefinitionErrorExceptionPass` instead - 3.3.0 ----- @@ -85,8 +204,8 @@ CHANGELOG 2.5.0 ----- -* added DecoratorServicePass and a way to override a service definition (Definition::setDecoratedService()) -* deprecated SimpleXMLElement class. + * added DecoratorServicePass and a way to override a service definition (Definition::setDecoratedService()) + * deprecated SimpleXMLElement class. 2.4.0 ----- diff --git a/vendor/symfony/dependency-injection/ChildDefinition.php b/vendor/symfony/dependency-injection/ChildDefinition.php index 123b3874..5aefec64 100644 --- a/vendor/symfony/dependency-injection/ChildDefinition.php +++ b/vendor/symfony/dependency-injection/ChildDefinition.php @@ -27,7 +27,7 @@ class ChildDefinition extends Definition /** * @param string $parent The id of Definition instance to decorate */ - public function __construct($parent) + public function __construct(string $parent) { $this->parent = $parent; $this->setPrivate(false); @@ -97,7 +97,7 @@ public function replaceArgument($index, $value) { if (\is_int($index)) { $this->arguments['index_'.$index] = $value; - } elseif (0 === strpos($index, '$')) { + } elseif (str_starts_with($index, '$')) { $this->arguments[$index] = $value; } else { throw new InvalidArgumentException('The argument must be an existing index or the name of a constructor\'s parameter.'); @@ -109,7 +109,7 @@ public function replaceArgument($index, $value) /** * @internal */ - public function setAutoconfigured($autoconfigured) + public function setAutoconfigured($autoconfigured): self { throw new BadMethodCallException('A ChildDefinition cannot be autoconfigured.'); } @@ -117,10 +117,8 @@ public function setAutoconfigured($autoconfigured) /** * @internal */ - public function setInstanceofConditionals(array $instanceof) + public function setInstanceofConditionals(array $instanceof): self { throw new BadMethodCallException('A ChildDefinition cannot have instanceof conditionals set on it.'); } } - -class_alias(ChildDefinition::class, DefinitionDecorator::class); diff --git a/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php b/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php index 863bab47..4fb467d9 100644 --- a/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php +++ b/vendor/symfony/dependency-injection/Compiler/AbstractRecursivePass.php @@ -12,10 +12,14 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\ExpressionLanguage; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\ExpressionLanguage\Expression; /** * @author Nicolas Grekas @@ -28,6 +32,10 @@ abstract class AbstractRecursivePass implements CompilerPassInterface protected $container; protected $currentId; + private $processExpressions = false; + private $expressionLanguage; + private $inExpression = false; + /** * {@inheritdoc} */ @@ -42,6 +50,21 @@ public function process(ContainerBuilder $container) } } + protected function enableExpressionProcessing() + { + $this->processExpressions = true; + } + + protected function inExpression(bool $reset = true): bool + { + $inExpression = $this->inExpression; + if ($reset) { + $this->inExpression = false; + } + + return $inExpression; + } + /** * Processes a value found in a definition tree. * @@ -63,6 +86,8 @@ protected function processValue($value, $isRoot = false) } } elseif ($value instanceof ArgumentInterface) { $value->setValues($this->processValue($value->getValues())); + } elseif ($value instanceof Expression && $this->processExpressions) { + $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']); } elseif ($value instanceof Definition) { $value->setArguments($this->processValue($value->getArguments())); $value->setProperties($this->processValue($value->getProperties())); @@ -106,23 +131,36 @@ protected function getConstructor(Definition $definition, $required) } if ($factory) { - list($class, $method) = $factory; + [$class, $method] = $factory; + + if ('__construct' === $method) { + throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId)); + } + if ($class instanceof Reference) { - $class = $this->container->findDefinition((string) $class)->getClass(); + $factoryDefinition = $this->container->findDefinition((string) $class); + while ((null === $class = $factoryDefinition->getClass()) && $factoryDefinition instanceof ChildDefinition) { + $factoryDefinition = $this->container->findDefinition($factoryDefinition->getParent()); + } + } elseif ($class instanceof Definition) { + $class = $class->getClass(); } elseif (null === $class) { $class = $definition->getClass(); } - if ('__construct' === $method) { - throw new RuntimeException(sprintf('Invalid service "%s": "__construct()" cannot be used as a factory method.', $this->currentId)); - } return $this->getReflectionMethod(new Definition($class), $method); } - $class = $definition->getClass(); + while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) { + $definition = $this->container->findDefinition($definition->getParent()); + } try { if (!$r = $this->container->getReflectionClass($class)) { + if (null === $class) { + throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId)); + } + throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class)); } } catch (\ReflectionException $e) { @@ -152,7 +190,11 @@ protected function getReflectionMethod(Definition $definition, $method) return $this->getConstructor($definition, true); } - if (!$class = $definition->getClass()) { + while ((null === $class = $definition->getClass()) && $definition instanceof ChildDefinition) { + $definition = $this->container->findDefinition($definition->getParent()); + } + + if (null === $class) { throw new RuntimeException(sprintf('Invalid service "%s": the class is not set.', $this->currentId)); } @@ -161,6 +203,10 @@ protected function getReflectionMethod(Definition $definition, $method) } if (!$r->hasMethod($method)) { + if ($r->hasMethod('__call') && ($r = $r->getMethod('__call')) && $r->isPublic()) { + return new \ReflectionMethod(static function (...$arguments) {}, '__invoke'); + } + throw new RuntimeException(sprintf('Invalid service "%s": method "%s()" does not exist.', $this->currentId, $class !== $this->currentId ? $class.'::'.$method : $method)); } @@ -171,4 +217,31 @@ protected function getReflectionMethod(Definition $definition, $method) return $r; } + + private function getExpressionLanguage(): ExpressionLanguage + { + if (null === $this->expressionLanguage) { + if (!class_exists(ExpressionLanguage::class)) { + throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); + } + + $providers = $this->container->getExpressionLanguageProviders(); + $this->expressionLanguage = new ExpressionLanguage(null, $providers, function (string $arg): string { + if ('""' === substr_replace($arg, '', 1, -1)) { + $id = stripcslashes(substr($arg, 1, -1)); + $this->inExpression = true; + $arg = $this->processValue(new Reference($id)); + $this->inExpression = false; + if (!$arg instanceof Reference) { + throw new RuntimeException(sprintf('"%s::processValue()" must return a Reference when processing an expression, "%s" returned for service("%s").', static::class, \is_object($arg) ? \get_class($arg) : \gettype($arg), $id)); + } + $arg = sprintf('"%s"', $arg); + } + + return sprintf('$this->get(%s)', $arg); + }); + } + + return $this->expressionLanguage; + } } diff --git a/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php b/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php index bff9d420..92e4acac 100644 --- a/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php +++ b/vendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php @@ -12,13 +12,11 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ExpressionLanguage; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\ExpressionLanguage\Expression; /** * Run this pass before passes that need to know more about the relation of @@ -28,6 +26,7 @@ * retrieve the graph in other passes from the compiler. * * @author Johannes M. Schmitt + * @author Nicolas Grekas */ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements RepeatablePassInterface { @@ -36,16 +35,19 @@ class AnalyzeServiceReferencesPass extends AbstractRecursivePass implements Repe private $onlyConstructorArguments; private $hasProxyDumper; private $lazy; - private $expressionLanguage; private $byConstructor; + private $byFactory; + private $definitions; + private $aliases; /** * @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls */ - public function __construct($onlyConstructorArguments = false, $hasProxyDumper = true) + public function __construct(bool $onlyConstructorArguments = false, bool $hasProxyDumper = true) { - $this->onlyConstructorArguments = (bool) $onlyConstructorArguments; - $this->hasProxyDumper = (bool) $hasProxyDumper; + $this->onlyConstructorArguments = $onlyConstructorArguments; + $this->hasProxyDumper = $hasProxyDumper; + $this->enableExpressionProcessing(); } /** @@ -53,7 +55,7 @@ public function __construct($onlyConstructorArguments = false, $hasProxyDumper = */ public function setRepeatedPass(RepeatedPass $repeatedPass) { - // no-op for BC + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); } /** @@ -66,34 +68,37 @@ public function process(ContainerBuilder $container) $this->graph->clear(); $this->lazy = false; $this->byConstructor = false; + $this->byFactory = false; + $this->definitions = $container->getDefinitions(); + $this->aliases = $container->getAliases(); - foreach ($container->getAliases() as $id => $alias) { + foreach ($this->aliases as $id => $alias) { $targetId = $this->getDefinitionId((string) $alias); - $this->graph->connect($id, $alias, $targetId, $this->getDefinition($targetId), null); + $this->graph->connect($id, $alias, $targetId, null !== $targetId ? $this->container->getDefinition($targetId) : null, null); } - parent::process($container); + try { + parent::process($container); + } finally { + $this->aliases = $this->definitions = []; + } } protected function processValue($value, $isRoot = false) { $lazy = $this->lazy; + $inExpression = $this->inExpression(); if ($value instanceof ArgumentInterface) { - $this->lazy = true; + $this->lazy = !$this->byFactory || !$value instanceof IteratorArgument; parent::processValue($value->getValues()); $this->lazy = $lazy; return $value; } - if ($value instanceof Expression) { - $this->getExpressionLanguage()->compile((string) $value, ['this' => 'container']); - - return $value; - } if ($value instanceof Reference) { $targetId = $this->getDefinitionId((string) $value); - $targetDefinition = $this->getDefinition($targetId); + $targetDefinition = null !== $targetId ? $this->container->getDefinition($targetId) : null; $this->graph->connect( $this->currentId, @@ -106,6 +111,18 @@ protected function processValue($value, $isRoot = false) $this->byConstructor ); + if ($inExpression) { + $this->graph->connect( + '.internal.reference_in_expression', + null, + $targetId, + $targetDefinition, + $value, + $this->lazy || ($targetDefinition && $targetDefinition->isLazy()), + true + ); + } + return $value; } if (!$value instanceof Definition) { @@ -123,70 +140,60 @@ protected function processValue($value, $isRoot = false) $byConstructor = $this->byConstructor; $this->byConstructor = $isRoot || $byConstructor; + + $byFactory = $this->byFactory; + $this->byFactory = true; $this->processValue($value->getFactory()); + $this->byFactory = $byFactory; $this->processValue($value->getArguments()); - $this->byConstructor = $byConstructor; - if (!$this->onlyConstructorArguments) { - $this->processValue($value->getProperties()); - $this->processValue($value->getMethodCalls()); - $this->processValue($value->getConfigurator()); + $properties = $value->getProperties(); + $setters = $value->getMethodCalls(); + + // Any references before a "wither" are part of the constructor-instantiation graph + $lastWitherIndex = null; + foreach ($setters as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } } - $this->lazy = $lazy; - return $value; - } + if (null !== $lastWitherIndex) { + $this->processValue($properties); + $setters = $properties = []; - /** - * Returns a service definition given the full name or an alias. - * - * @param string $id A full id or alias for a service definition - * - * @return Definition|null The definition related to the supplied id - */ - private function getDefinition($id) - { - return null === $id ? null : $this->container->getDefinition($id); - } + foreach ($value->getMethodCalls() as $k => $call) { + if (null === $lastWitherIndex) { + $setters[] = $call; + continue; + } - private function getDefinitionId($id) - { - while ($this->container->hasAlias($id)) { - $id = (string) $this->container->getAlias($id); + if ($lastWitherIndex === $k) { + $lastWitherIndex = null; + } + + $this->processValue($call); + } } - if (!$this->container->hasDefinition($id)) { - return null; + $this->byConstructor = $byConstructor; + + if (!$this->onlyConstructorArguments) { + $this->processValue($properties); + $this->processValue($setters); + $this->processValue($value->getConfigurator()); } + $this->lazy = $lazy; - return $this->container->normalizeId($id); + return $value; } - private function getExpressionLanguage() + private function getDefinitionId(string $id): ?string { - if (null === $this->expressionLanguage) { - if (!class_exists(ExpressionLanguage::class)) { - throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); - } - - $providers = $this->container->getExpressionLanguageProviders(); - $this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) { - if ('""' === substr_replace($arg, '', 1, -1)) { - $id = stripcslashes(substr($arg, 1, -1)); - $id = $this->getDefinitionId($id); - - $this->graph->connect( - $this->currentId, - $this->currentDefinition, - $id, - $this->getDefinition($id) - ); - } - - return sprintf('$this->get(%s)', $arg); - }); + while (isset($this->aliases[$id])) { + $id = (string) $this->aliases[$id]; } - return $this->expressionLanguage; + return isset($this->definitions[$id]) ? $id : null; } } diff --git a/vendor/symfony/dependency-injection/Compiler/AutowireExceptionPass.php b/vendor/symfony/dependency-injection/Compiler/AutowireExceptionPass.php deleted file mode 100644 index 6a755025..00000000 --- a/vendor/symfony/dependency-injection/Compiler/AutowireExceptionPass.php +++ /dev/null @@ -1,74 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Compiler; - -@trigger_error('The '.__NAMESPACE__.'\AutowireExceptionPass class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the DefinitionErrorExceptionPass class instead.', \E_USER_DEPRECATED); - -use Symfony\Component\DependencyInjection\ContainerBuilder; - -/** - * Throws autowire exceptions from AutowirePass for definitions that still exist. - * - * @deprecated since version 3.4, will be removed in 4.0. - * - * @author Ryan Weaver - */ -class AutowireExceptionPass implements CompilerPassInterface -{ - private $autowirePass; - private $inlineServicePass; - - public function __construct(AutowirePass $autowirePass, InlineServiceDefinitionsPass $inlineServicePass) - { - $this->autowirePass = $autowirePass; - $this->inlineServicePass = $inlineServicePass; - } - - public function process(ContainerBuilder $container) - { - // the pass should only be run once - if (null === $this->autowirePass || null === $this->inlineServicePass) { - return; - } - - $inlinedIds = $this->inlineServicePass->getInlinedServiceIds(); - $exceptions = $this->autowirePass->getAutowiringExceptions(); - - // free up references - $this->autowirePass = null; - $this->inlineServicePass = null; - - foreach ($exceptions as $exception) { - if ($this->doesServiceExistInTheContainer($exception->getServiceId(), $container, $inlinedIds)) { - throw $exception; - } - } - } - - private function doesServiceExistInTheContainer($serviceId, ContainerBuilder $container, array $inlinedIds) - { - if ($container->hasDefinition($serviceId)) { - return true; - } - - // was the service inlined? Of so, does its parent service exist? - if (isset($inlinedIds[$serviceId])) { - foreach ($inlinedIds[$serviceId] as $parentId) { - if ($this->doesServiceExistInTheContainer($parentId, $container, $inlinedIds)) { - return true; - } - } - } - - return false; - } -} diff --git a/vendor/symfony/dependency-injection/Compiler/AutowirePass.php b/vendor/symfony/dependency-injection/Compiler/AutowirePass.php index b1dae2a4..c88143d1 100644 --- a/vendor/symfony/dependency-injection/Compiler/AutowirePass.php +++ b/vendor/symfony/dependency-injection/Compiler/AutowirePass.php @@ -12,7 +12,6 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\Config\Resource\ClassExistenceResource; -use Symfony\Component\DependencyInjection\Config\AutowireServiceResource; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException; @@ -28,33 +27,26 @@ */ class AutowirePass extends AbstractRecursivePass { - private $definedTypes = []; private $types; private $ambiguousServiceTypes; - private $autowired = []; private $lastFailure; private $throwOnAutowiringException; - private $autowiringExceptions = []; - private $strictMode; - - /** - * @param bool $throwOnAutowireException Errors can be retrieved via Definition::getErrors() - */ - public function __construct($throwOnAutowireException = true) + private $decoratedClass; + private $decoratedId; + private $methodCalls; + private $defaultArgument; + private $getPreviousValue; + private $decoratedMethodIndex; + private $decoratedMethodArgumentIndex; + private $typesClone; + + public function __construct(bool $throwOnAutowireException = true) { $this->throwOnAutowiringException = $throwOnAutowireException; - } - - /** - * @deprecated since version 3.4, to be removed in 4.0. - * - * @return AutowiringFailedException[] - */ - public function getAutowiringExceptions() - { - @trigger_error('Calling AutowirePass::getAutowiringExceptions() is deprecated since Symfony 3.4 and will be removed in 4.0. Use Definition::getErrors() instead.', \E_USER_DEPRECATED); - - return $this->autowiringExceptions; + $this->defaultArgument = new class() { + public $value; + public $names; + }; } /** @@ -62,42 +54,21 @@ public function getAutowiringExceptions() */ public function process(ContainerBuilder $container) { - // clear out any possibly stored exceptions from before - $this->autowiringExceptions = []; - $this->strictMode = $container->hasParameter('container.autowiring.strict_mode') && $container->getParameter('container.autowiring.strict_mode'); - try { + $this->typesClone = clone $this; parent::process($container); } finally { - $this->definedTypes = []; - $this->types = null; - $this->ambiguousServiceTypes = null; - $this->autowired = []; + $this->decoratedClass = null; + $this->decoratedId = null; + $this->methodCalls = null; + $this->defaultArgument->names = null; + $this->getPreviousValue = null; + $this->decoratedMethodIndex = null; + $this->decoratedMethodArgumentIndex = null; + $this->typesClone = null; } } - /** - * Creates a resource to help know if this service has changed. - * - * @return AutowireServiceResource - * - * @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead. - */ - public static function createResourceForClass(\ReflectionClass $reflectionClass) - { - @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', \E_USER_DEPRECATED); - - $metadata = []; - - foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { - if (!$reflectionMethod->isStatic()) { - $metadata[$reflectionMethod->name] = self::getResourceMetadataForMethod($reflectionMethod); - } - } - - return new AutowireServiceResource($reflectionClass->name, $reflectionClass->getFileName(), $metadata); - } - /** * {@inheritdoc} */ @@ -110,20 +81,30 @@ protected function processValue($value, $isRoot = false) throw $e; } - $this->autowiringExceptions[] = $e; - $this->container->getDefinition($this->currentId)->addError($e->getMessage()); + $this->container->getDefinition($this->currentId)->addError($e->getMessageCallback() ?? $e->getMessage()); return parent::processValue($value, $isRoot); } } - private function doProcessValue($value, $isRoot = false) + /** + * @return mixed + */ + private function doProcessValue($value, bool $isRoot = false) { if ($value instanceof TypedReference) { - if ($ref = $this->getAutowiredReference($value, $value->getRequiringClass() ? sprintf('for "%s" in "%s"', $value->getType(), $value->getRequiringClass()) : '')) { + if ($ref = $this->getAutowiredReference($value)) { return $ref; } - $this->container->log($this, $this->createTypeNotFoundMessage($value, 'it')); + if (ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) { + $message = $this->createTypeNotFoundMessageCallback($value, 'it'); + + // since the error message varies by referenced id and $this->currentId, so should the id of the dummy errored definition + $this->container->register($id = sprintf('.errored.%s.%s', $this->currentId, (string) $value), $value->getType()) + ->addError($message); + + return new TypedReference($id, $value->getType(), $value->getInvalidBehavior(), $value->getName()); + } } $value = parent::processValue($value, $isRoot); @@ -136,7 +117,7 @@ private function doProcessValue($value, $isRoot = false) return $value; } - $methodCalls = $value->getMethodCalls(); + $this->methodCalls = $value->getMethodCalls(); try { $constructor = $this->getConstructor($value, false); @@ -145,33 +126,40 @@ private function doProcessValue($value, $isRoot = false) } if ($constructor) { - array_unshift($methodCalls, [$constructor, $value->getArguments()]); + array_unshift($this->methodCalls, [$constructor, $value->getArguments()]); } - $methodCalls = $this->autowireCalls($reflectionClass, $methodCalls); + $this->methodCalls = $this->autowireCalls($reflectionClass, $isRoot); if ($constructor) { - list(, $arguments) = array_shift($methodCalls); + [, $arguments] = array_shift($this->methodCalls); if ($arguments !== $value->getArguments()) { $value->setArguments($arguments); } } - if ($methodCalls !== $value->getMethodCalls()) { - $value->setMethodCalls($methodCalls); + if ($this->methodCalls !== $value->getMethodCalls()) { + $value->setMethodCalls($this->methodCalls); } return $value; } - /** - * @return array - */ - private function autowireCalls(\ReflectionClass $reflectionClass, array $methodCalls) + private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot): array { - foreach ($methodCalls as $i => $call) { - list($method, $arguments) = $call; + $this->decoratedId = null; + $this->decoratedClass = null; + $this->getPreviousValue = null; + + if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && null !== ($this->decoratedId = $definition->innerServiceId) && $this->container->has($this->decoratedId)) { + $this->decoratedClass = $this->container->findDefinition($this->decoratedId)->getClass(); + } + + $patchedIndexes = []; + + foreach ($this->methodCalls as $i => $call) { + [$method, $arguments] = $call; if ($method instanceof \ReflectionFunctionAbstract) { $reflectionMethod = $method; @@ -187,14 +175,40 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC } } - $arguments = $this->autowireMethod($reflectionMethod, $arguments); + $arguments = $this->autowireMethod($reflectionMethod, $arguments, $i); if ($arguments !== $call[1]) { - $methodCalls[$i][1] = $arguments; + $this->methodCalls[$i][1] = $arguments; + $patchedIndexes[] = $i; + } + } + + // use named arguments to skip complex default values + foreach ($patchedIndexes as $i) { + $namedArguments = null; + $arguments = $this->methodCalls[$i][1]; + + foreach ($arguments as $j => $value) { + if ($namedArguments && !$value instanceof $this->defaultArgument) { + unset($arguments[$j]); + $arguments[$namedArguments[$j]] = $value; + } + if ($namedArguments || !$value instanceof $this->defaultArgument) { + continue; + } + + if (\PHP_VERSION_ID >= 80100 && (\is_array($value->value) ? $value->value : \is_object($value->value))) { + unset($arguments[$j]); + $namedArguments = $value->names; + } else { + $arguments[$j] = $value->value; + } } + + $this->methodCalls[$i][1] = $arguments; } - return $methodCalls; + return $this->methodCalls; } /** @@ -204,16 +218,19 @@ private function autowireCalls(\ReflectionClass $reflectionClass, array $methodC * * @throws AutowiringFailedException */ - private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments) + private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, int $methodIndex): array { $class = $reflectionMethod instanceof \ReflectionMethod ? $reflectionMethod->class : $this->currentId; $method = $reflectionMethod->name; $parameters = $reflectionMethod->getParameters(); - if (method_exists('ReflectionMethod', 'isVariadic') && $reflectionMethod->isVariadic()) { + if ($reflectionMethod->isVariadic()) { array_pop($parameters); } + $this->defaultArgument->names = new \ArrayObject(); foreach ($parameters as $index => $parameter) { + $this->defaultArgument->names[$index] = $parameter->name; + if (\array_key_exists($index, $arguments) && '' !== $arguments[$index]) { continue; } @@ -231,38 +248,62 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a // be false when isOptional() returns true. If the // argument *is* optional, allow it to be missing if ($parameter->isOptional()) { - continue; + --$index; + break; } $type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false); - $type = $type ? sprintf('is type-hinted "%s"', $type) : 'has no type-hint'; + $type = $type ? sprintf('is type-hinted "%s"', ltrim($type, '\\')) : 'has no type-hint'; throw new AutowiringFailedException($this->currentId, sprintf('Cannot autowire service "%s": argument "$%s" of method "%s()" %s, you should configure its value explicitly.', $this->currentId, $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method, $type)); } // specifically pass the default value - $arguments[$index] = $parameter->getDefaultValue(); + $arguments[$index] = clone $this->defaultArgument; + $arguments[$index]->value = $parameter->getDefaultValue(); continue; } - if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, !$parameter->isOptional() ? $class : ''), 'for '.sprintf('argument "$%s" of method "%s()"', $parameter->name, $class.'::'.$method))) { - $failureMessage = $this->createTypeNotFoundMessage($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); + $getValue = function () use ($type, $parameter, $class, $method) { + if (!$value = $this->getAutowiredReference($ref = new TypedReference($type, $type, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $parameter->name))) { + $failureMessage = $this->createTypeNotFoundMessageCallback($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method)); + + if ($parameter->isDefaultValueAvailable()) { + $value = clone $this->defaultArgument; + $value->value = $parameter->getDefaultValue(); + } elseif (!$parameter->allowsNull()) { + throw new AutowiringFailedException($this->currentId, $failureMessage); + } + } + + return $value; + }; + + if ($this->decoratedClass && $isDecorated = is_a($this->decoratedClass, $type, true)) { + if ($this->getPreviousValue) { + // The inner service is injected only if there is only 1 argument matching the type of the decorated class + // across all arguments of all autowired methods. + // If a second matching argument is found, the default behavior is restored. + + $getPreviousValue = $this->getPreviousValue; + $this->methodCalls[$this->decoratedMethodIndex][1][$this->decoratedMethodArgumentIndex] = $getPreviousValue(); + $this->decoratedClass = null; // Prevent further checks + } else { + $arguments[$index] = new TypedReference($this->decoratedId, $this->decoratedClass); + $this->getPreviousValue = $getValue; + $this->decoratedMethodIndex = $methodIndex; + $this->decoratedMethodArgumentIndex = $index; - if ($parameter->isDefaultValueAvailable()) { - $value = $parameter->getDefaultValue(); - } elseif (!$parameter->allowsNull()) { - throw new AutowiringFailedException($this->currentId, $failureMessage); + continue; } - $this->container->log($this, $failureMessage); } - $arguments[$index] = $value; + $arguments[$index] = $getValue(); } if ($parameters && !isset($arguments[++$index])) { while (0 <= --$index) { - $parameter = $parameters[$index]; - if (!$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== $arguments[$index]) { + if (!$arguments[$index] instanceof $this->defaultArgument) { break; } unset($arguments[$index]); @@ -277,48 +318,33 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a } /** - * @return TypedReference|null A reference to the service matching the given type, if any + * Returns a reference to the service matching the given type, if any. */ - private function getAutowiredReference(TypedReference $reference, $deprecationMessage) + private function getAutowiredReference(TypedReference $reference): ?TypedReference { $this->lastFailure = null; $type = $reference->getType(); - if ($type !== $this->container->normalizeId($reference) || ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract())) { + if ($type !== (string) $reference) { return $reference; } - if (null === $this->types) { - $this->populateAvailableTypes($this->strictMode); - } - - if (isset($this->definedTypes[$type])) { - return new TypedReference($this->types[$type], $type); - } - - if (!$this->strictMode && isset($this->types[$type])) { - $message = 'Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won\'t be supported in version 4.0.'; - if ($aliasSuggestion = $this->getAliasesSuggestionForType($type = $reference->getType(), $deprecationMessage)) { - $message .= ' '.$aliasSuggestion; - } else { - $message .= sprintf(' You should %s the "%s" service to "%s" instead.', isset($this->types[$this->types[$type]]) ? 'alias' : 'rename (or alias)', $this->types[$type], $type); + if (null !== $name = $reference->getName()) { + if ($this->container->has($alias = $type.' $'.$name) && !$this->container->findDefinition($alias)->isAbstract()) { + return new TypedReference($alias, $type, $reference->getInvalidBehavior()); } - @trigger_error($message, \E_USER_DEPRECATED); - - return new TypedReference($this->types[$type], $type); - } - - if (!$reference->canBeAutoregistered() || isset($this->types[$type]) || isset($this->ambiguousServiceTypes[$type])) { - return null; - } - - if (isset($this->autowired[$type])) { - return $this->autowired[$type] ? new TypedReference($this->autowired[$type], $type) : null; + if ($this->container->has($name) && !$this->container->findDefinition($name)->isAbstract()) { + foreach ($this->container->getAliases() as $id => $alias) { + if ($name === (string) $alias && str_starts_with($id, $type.' $')) { + return new TypedReference($name, $type, $reference->getInvalidBehavior()); + } + } + } } - if (!$this->strictMode) { - return $this->createAutowiredDefinition($type); + if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) { + return new TypedReference($type, $type, $reference->getInvalidBehavior()); } return null; @@ -327,41 +353,27 @@ private function getAutowiredReference(TypedReference $reference, $deprecationMe /** * Populates the list of available types. */ - private function populateAvailableTypes($onlyAutowiringTypes = false) + private function populateAvailableTypes(ContainerBuilder $container) { $this->types = []; - if (!$onlyAutowiringTypes) { - $this->ambiguousServiceTypes = []; - } + $this->ambiguousServiceTypes = []; - foreach ($this->container->getDefinitions() as $id => $definition) { - $this->populateAvailableType($id, $definition, $onlyAutowiringTypes); + foreach ($container->getDefinitions() as $id => $definition) { + $this->populateAvailableType($container, $id, $definition); } } /** * Populates the list of available types for a given definition. - * - * @param string $id */ - private function populateAvailableType($id, Definition $definition, $onlyAutowiringTypes) + private function populateAvailableType(ContainerBuilder $container, string $id, Definition $definition) { // Never use abstract services if ($definition->isAbstract()) { return; } - foreach ($definition->getAutowiringTypes(false) as $type) { - $this->definedTypes[$type] = true; - $this->types[$type] = $id; - unset($this->ambiguousServiceTypes[$type]); - } - - if ($onlyAutowiringTypes) { - return; - } - - if (preg_match('/^\d+_[^~]++~[._a-zA-Z\d]{7}$/', $id) || $definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), false)) { + if ('' === $id || '.' === $id[0] || $definition->isDeprecated() || !$reflectionClass = $container->getReflectionClass($definition->getClass(), false)) { return; } @@ -376,16 +388,9 @@ private function populateAvailableType($id, Definition $definition, $onlyAutowir /** * Associates a type and a service id if applicable. - * - * @param string $type - * @param string $id */ - private function set($type, $id) + private function set(string $type, string $id) { - if (isset($this->definedTypes[$type])) { - return; - } - // is this already a type/class that is known to match multiple services? if (isset($this->ambiguousServiceTypes[$type])) { $this->ambiguousServiceTypes[$type][] = $id; @@ -408,62 +413,24 @@ private function set($type, $id) $this->ambiguousServiceTypes[$type][] = $id; } - /** - * Registers a definition for the type if possible or throws an exception. - * - * @param string $type - * - * @return TypedReference|null A reference to the registered definition - */ - private function createAutowiredDefinition($type) + private function createTypeNotFoundMessageCallback(TypedReference $reference, string $label): \Closure { - if (!($typeHint = $this->container->getReflectionClass($type, false)) || !$typeHint->isInstantiable()) { - return null; + if (null === $this->typesClone->container) { + $this->typesClone->container = new ContainerBuilder($this->container->getParameterBag()); + $this->typesClone->container->setAliases($this->container->getAliases()); + $this->typesClone->container->setDefinitions($this->container->getDefinitions()); + $this->typesClone->container->setResourceTracking(false); } - $currentId = $this->currentId; - $this->currentId = $type; - $this->autowired[$type] = $argumentId = sprintf('autowired.%s', $type); - $argumentDefinition = new Definition($type); - $argumentDefinition->setPublic(false); - $argumentDefinition->setAutowired(true); - try { - $originalThrowSetting = $this->throwOnAutowiringException; - $this->throwOnAutowiringException = true; - $this->processValue($argumentDefinition, true); - $this->container->setDefinition($argumentId, $argumentDefinition); - } catch (AutowiringFailedException $e) { - $this->autowired[$type] = false; - $this->lastFailure = $e->getMessage(); - $this->container->log($this, $this->lastFailure); - - return null; - } finally { - $this->throwOnAutowiringException = $originalThrowSetting; - $this->currentId = $currentId; - } - - @trigger_error(sprintf('Relying on service auto-registration for type "%s" is deprecated since Symfony 3.4 and won\'t be supported in 4.0. Create a service named "%s" instead.', $type, $type), \E_USER_DEPRECATED); - - $this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId)); - - return new TypedReference($argumentId, $type); + return (function () use ($reference, $label, $currentId) { + return $this->createTypeNotFoundMessage($reference, $label, $currentId); + })->bindTo($this->typesClone); } - private function createTypeNotFoundMessage(TypedReference $reference, $label) + private function createTypeNotFoundMessage(TypedReference $reference, string $label, string $currentId): string { - $trackResources = $this->container->isTrackingResources(); - $this->container->setResourceTracking(false); - try { - if ($r = $this->container->getReflectionClass($type = $reference->getType(), false)) { - $alternatives = $this->createTypeAlternatives($reference); - } - } finally { - $this->container->setResourceTracking($trackResources); - } - - if (!$r) { + if (!$r = $this->container->getReflectionClass($type = $reference->getType(), false)) { // either $type does not exist or a parent class does not exist try { $resource = new ClassExistenceResource($type, false); @@ -476,6 +443,7 @@ private function createTypeNotFoundMessage(TypedReference $reference, $label) $message = sprintf('has type "%s" but this class %s.', $type, $parentMsg ? sprintf('is missing a parent class (%s)', $parentMsg) : 'was not found'); } else { + $alternatives = $this->createTypeAlternatives($this->container, $reference); $message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists'; $message = sprintf('references %s "%s" but %s.%s', $r->isInterface() ? 'interface' : 'class', $type, $message, $alternatives); @@ -484,7 +452,7 @@ private function createTypeNotFoundMessage(TypedReference $reference, $label) } } - $message = sprintf('Cannot autowire service "%s": %s %s', $this->currentId, $label, $message); + $message = sprintf('Cannot autowire service "%s": %s %s', $currentId, $label, $message); if (null !== $this->lastFailure) { $message = $this->lastFailure."\n".$message; @@ -494,22 +462,23 @@ private function createTypeNotFoundMessage(TypedReference $reference, $label) return $message; } - private function createTypeAlternatives(TypedReference $reference) + private function createTypeAlternatives(ContainerBuilder $container, TypedReference $reference): string { // try suggesting available aliases first - if ($message = $this->getAliasesSuggestionForType($type = $reference->getType())) { + if ($message = $this->getAliasesSuggestionForType($container, $type = $reference->getType())) { return ' '.$message; } if (null === $this->ambiguousServiceTypes) { - $this->populateAvailableTypes(); + $this->populateAvailableTypes($container); } - if (isset($this->ambiguousServiceTypes[$type])) { + $servicesAndAliases = $container->getServiceIds(); + if (!$container->has($type) && false !== $key = array_search(strtolower($type), array_map('strtolower', $servicesAndAliases))) { + return sprintf(' Did you mean "%s"?', $servicesAndAliases[$key]); + } elseif (isset($this->ambiguousServiceTypes[$type])) { $message = sprintf('one of these existing services: "%s"', implode('", "', $this->ambiguousServiceTypes[$type])); } elseif (isset($this->types[$type])) { $message = sprintf('the existing "%s" service', $this->types[$type]); - } elseif ($reference->getRequiringClass() && !$reference->canBeAutoregistered() && !$this->strictMode) { - return ' It cannot be auto-registered because it is from a different root namespace.'; } else { return ''; } @@ -517,52 +486,17 @@ private function createTypeAlternatives(TypedReference $reference) return sprintf(' You should maybe alias this %s to %s.', class_exists($type, false) ? 'class' : 'interface', $message); } - /** - * @deprecated since version 3.3, to be removed in 4.0. - */ - private static function getResourceMetadataForMethod(\ReflectionMethod $method) - { - $methodArgumentsMetadata = []; - foreach ($method->getParameters() as $parameter) { - try { - if (method_exists($parameter, 'getType')) { - $type = $parameter->getType(); - if ($type && !$type->isBuiltin()) { - $class = new \ReflectionClass($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type); - } else { - $class = null; - } - } else { - $class = $parameter->getClass(); - } - } catch (\ReflectionException $e) { - // type-hint is against a non-existent class - $class = false; - } - - $isVariadic = method_exists($parameter, 'isVariadic') && $parameter->isVariadic(); - $methodArgumentsMetadata[] = [ - 'class' => $class, - 'isOptional' => $parameter->isOptional(), - 'defaultValue' => ($parameter->isOptional() && !$isVariadic) ? $parameter->getDefaultValue() : null, - ]; - } - - return $methodArgumentsMetadata; - } - - private function getAliasesSuggestionForType($type, $extraContext = null) + private function getAliasesSuggestionForType(ContainerBuilder $container, string $type): ?string { $aliases = []; foreach (class_parents($type) + class_implements($type) as $parent) { - if ($this->container->has($parent) && !$this->container->findDefinition($parent)->isAbstract()) { + if ($container->has($parent) && !$container->findDefinition($parent)->isAbstract()) { $aliases[] = $parent; } } - $extraContext = $extraContext ? ' '.$extraContext : ''; if (1 < $len = \count($aliases)) { - $message = sprintf('Try changing the type-hint%s to one of its parents: ', $extraContext); + $message = 'Try changing the type-hint to one of its parents: '; for ($i = 0, --$len; $i < $len; ++$i) { $message .= sprintf('%s "%s", ', class_exists($aliases[$i], false) ? 'class' : 'interface', $aliases[$i]); } @@ -572,7 +506,7 @@ private function getAliasesSuggestionForType($type, $extraContext = null) } if ($aliases) { - return sprintf('Try changing the type-hint%s to "%s" instead.', $extraContext, $aliases[0]); + return sprintf('Try changing the type-hint to "%s" instead.', $aliases[0]); } return null; diff --git a/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php b/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php index efb9df7b..4e80bb4f 100644 --- a/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/AutowireRequiredMethodsPass.php @@ -35,8 +35,9 @@ protected function processValue($value, $isRoot = false) } $alreadyCalledMethods = []; + $withers = []; - foreach ($value->getMethodCalls() as list($method)) { + foreach ($value->getMethodCalls() as [$method]) { $alreadyCalledMethods[strtolower($method)] = true; } @@ -50,7 +51,11 @@ protected function processValue($value, $isRoot = false) while (true) { if (false !== $doc = $r->getDocComment()) { if (false !== stripos($doc, '@required') && preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@required(?:\s|\*/$)#i', $doc)) { - $value->addMethodCall($reflectionMethod->name); + if (preg_match('#(?:^/\*\*|\n\s*+\*)\s*+@return\s++static[\s\*]#i', $doc)) { + $withers[] = [$reflectionMethod->name, [], true]; + } else { + $value->addMethodCall($reflectionMethod->name, []); + } break; } if (false === stripos($doc, '@inheritdoc') || !preg_match('#(?:^/\*\*|\n\s*+\*)\s*+(?:\{@inheritdoc\}|@inheritdoc)(?:\s|\*/$)#i', $doc)) { @@ -65,6 +70,15 @@ protected function processValue($value, $isRoot = false) } } + if ($withers) { + // Prepend withers to prevent creating circular loops + $setters = $value->getMethodCalls(); + $value->setMethodCalls($withers); + foreach ($setters as $call) { + $value->addMethodCall($call[0], $call[1], $call[2] ?? false); + } + } + return $value; } } diff --git a/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php b/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php index 30a6f524..557e6af6 100644 --- a/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php +++ b/vendor/symfony/dependency-injection/Compiler/CheckArgumentsValidityPass.php @@ -24,7 +24,7 @@ class CheckArgumentsValidityPass extends AbstractRecursivePass { private $throwExceptions; - public function __construct($throwExceptions = true) + public function __construct(bool $throwExceptions = true) { $this->throwExceptions = $throwExceptions; } @@ -39,7 +39,13 @@ protected function processValue($value, $isRoot = false) } $i = 0; + $hasNamedArgs = false; foreach ($value->getArguments() as $k => $v) { + if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) { + $hasNamedArgs = true; + continue; + } + if ($k !== $i++) { if (!\is_int($k)) { $msg = sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k); @@ -57,11 +63,27 @@ protected function processValue($value, $isRoot = false) throw new RuntimeException($msg); } } + + if ($hasNamedArgs) { + $msg = sprintf('Invalid constructor argument for service "%s": cannot use positional argument after named argument. Check your service definition.', $this->currentId); + $value->addError($msg); + if ($this->throwExceptions) { + throw new RuntimeException($msg); + } + + break; + } } foreach ($value->getMethodCalls() as $methodCall) { $i = 0; + $hasNamedArgs = false; foreach ($methodCall[1] as $k => $v) { + if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) { + $hasNamedArgs = true; + continue; + } + if ($k !== $i++) { if (!\is_int($k)) { $msg = sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k); @@ -79,6 +101,16 @@ protected function processValue($value, $isRoot = false) throw new RuntimeException($msg); } } + + if ($hasNamedArgs) { + $msg = sprintf('Invalid argument for method call "%s" of service "%s": cannot use positional argument after named argument. Check your service definition.', $methodCall[0], $this->currentId); + $value->addError($msg); + if ($this->throwExceptions) { + throw new RuntimeException($msg); + } + + break; + } } } diff --git a/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php b/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php index 4b6d277f..7abac908 100644 --- a/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php +++ b/vendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php @@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\EnvParameterException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Loader\FileLoader; /** * This pass validates each definition individually only taking the information @@ -38,17 +39,17 @@ public function process(ContainerBuilder $container) { foreach ($container->getDefinitions() as $id => $definition) { // synthetic service is public - if ($definition->isSynthetic() && !($definition->isPublic() || $definition->isPrivate())) { + if ($definition->isSynthetic() && !$definition->isPublic()) { throw new RuntimeException(sprintf('A synthetic service ("%s") must be public.', $id)); } // non-synthetic, non-abstract service has class - if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) { + if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) { if ($definition->getFactory()) { throw new RuntimeException(sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id)); } if (class_exists($id) || interface_exists($id, false)) { - if (0 === strpos($id, '\\') && 1 < substr_count($id, '\\')) { + if (str_starts_with($id, '\\') && 1 < substr_count($id, '\\')) { throw new RuntimeException(sprintf('The definition for "%s" has no class attribute, and appears to reference a class or interface. Please specify the class attribute explicitly or remove the leading backslash by renaming the service to "%s" to get rid of this error.', $id, substr($id, 1))); } diff --git a/vendor/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php b/vendor/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php index 77b35f18..eef71587 100644 --- a/vendor/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php +++ b/vendor/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Reference; @@ -22,15 +23,66 @@ */ class CheckExceptionOnInvalidReferenceBehaviorPass extends AbstractRecursivePass { + private $serviceLocatorContextIds = []; + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $this->serviceLocatorContextIds = []; + foreach ($container->findTaggedServiceIds('container.service_locator_context') as $id => $tags) { + $this->serviceLocatorContextIds[$id] = $tags[0]['id']; + $container->getDefinition($id)->clearTag('container.service_locator_context'); + } + + try { + return parent::process($container); + } finally { + $this->serviceLocatorContextIds = []; + } + } + protected function processValue($value, $isRoot = false) { if (!$value instanceof Reference) { return parent::processValue($value, $isRoot); } - if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior() && !$this->container->has($id = (string) $value)) { - throw new ServiceNotFoundException($id, $this->currentId); + if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $value->getInvalidBehavior() || $this->container->has($id = (string) $value)) { + return $value; + } + + $currentId = $this->currentId; + $graph = $this->container->getCompiler()->getServiceReferenceGraph(); + + if (isset($this->serviceLocatorContextIds[$currentId])) { + $currentId = $this->serviceLocatorContextIds[$currentId]; + $locator = $this->container->getDefinition($this->currentId)->getFactory()[0]; + + foreach ($locator->getArgument(0) as $k => $v) { + if ($v->getValues()[0] === $value) { + if ($k !== $id) { + $currentId = $k.'" in the container provided to "'.$currentId; + } + throw new ServiceNotFoundException($id, $currentId); + } + } + } + + if ('.' === $currentId[0] && $graph->hasNode($currentId)) { + foreach ($graph->getNode($currentId)->getInEdges() as $edge) { + if (!$edge->getValue() instanceof Reference || ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $edge->getValue()->getInvalidBehavior()) { + continue; + } + $sourceId = $edge->getSourceNode()->getId(); + + if ('.' !== $sourceId[0]) { + $currentId = $sourceId; + break; + } + } } - return $value; + throw new ServiceNotFoundException($id, $currentId); } } diff --git a/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php b/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php new file mode 100644 index 00000000..ca10af65 --- /dev/null +++ b/vendor/symfony/dependency-injection/Compiler/CheckTypeDeclarationsPass.php @@ -0,0 +1,329 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; +use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\ExpressionLanguage; +use Symfony\Component\DependencyInjection\Parameter; +use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\ExpressionLanguage\Expression; + +/** + * Checks whether injected parameters are compatible with type declarations. + * + * This pass should be run after all optimization passes. + * + * It can be added either: + * * before removing passes to check all services even if they are not currently used, + * * after removing passes to check only services are used in the app. + * + * @author Nicolas Grekas + * @author Julien Maulny + */ +final class CheckTypeDeclarationsPass extends AbstractRecursivePass +{ + private const SCALAR_TYPES = [ + 'int' => true, + 'float' => true, + 'bool' => true, + 'string' => true, + ]; + + private const BUILTIN_TYPES = [ + 'array' => true, + 'bool' => true, + 'callable' => true, + 'float' => true, + 'int' => true, + 'iterable' => true, + 'object' => true, + 'string' => true, + ]; + + private $autoload; + private $skippedIds; + + private $expressionLanguage; + + /** + * @param bool $autoload Whether services who's class in not loaded should be checked or not. + * Defaults to false to save loading code during compilation. + * @param array $skippedIds An array indexed by the service ids to skip + */ + public function __construct(bool $autoload = false, array $skippedIds = []) + { + $this->autoload = $autoload; + $this->skippedIds = $skippedIds; + } + + /** + * {@inheritdoc} + */ + protected function processValue($value, $isRoot = false) + { + if (isset($this->skippedIds[$this->currentId])) { + return $value; + } + + if (!$value instanceof Definition || $value->hasErrors() || $value->isDeprecated()) { + return parent::processValue($value, $isRoot); + } + + if (!$this->autoload) { + if (!$class = $value->getClass()) { + return parent::processValue($value, $isRoot); + } + if (!class_exists($class, false) && !interface_exists($class, false)) { + return parent::processValue($value, $isRoot); + } + } + + if (ServiceLocator::class === $value->getClass()) { + return parent::processValue($value, $isRoot); + } + + if ($constructor = $this->getConstructor($value, false)) { + $this->checkTypeDeclarations($value, $constructor, $value->getArguments()); + } + + foreach ($value->getMethodCalls() as $methodCall) { + try { + $reflectionMethod = $this->getReflectionMethod($value, $methodCall[0]); + } catch (RuntimeException $e) { + if ($value->getFactory()) { + continue; + } + + throw $e; + } + + $this->checkTypeDeclarations($value, $reflectionMethod, $methodCall[1]); + } + + return parent::processValue($value, $isRoot); + } + + /** + * @throws InvalidArgumentException When not enough parameters are defined for the method + */ + private function checkTypeDeclarations(Definition $checkedDefinition, \ReflectionFunctionAbstract $reflectionFunction, array $values): void + { + $numberOfRequiredParameters = $reflectionFunction->getNumberOfRequiredParameters(); + + if (\count($values) < $numberOfRequiredParameters) { + throw new InvalidArgumentException(sprintf('Invalid definition for service "%s": "%s::%s()" requires %d arguments, %d passed.', $this->currentId, $reflectionFunction->class, $reflectionFunction->name, $numberOfRequiredParameters, \count($values))); + } + + $reflectionParameters = $reflectionFunction->getParameters(); + $checksCount = min($reflectionFunction->getNumberOfParameters(), \count($values)); + + $envPlaceholderUniquePrefix = $this->container->getParameterBag() instanceof EnvPlaceholderParameterBag ? $this->container->getParameterBag()->getEnvPlaceholderUniquePrefix() : null; + + for ($i = 0; $i < $checksCount; ++$i) { + if (!$reflectionParameters[$i]->hasType() || $reflectionParameters[$i]->isVariadic()) { + continue; + } + + $this->checkType($checkedDefinition, $values[$i], $reflectionParameters[$i], $envPlaceholderUniquePrefix); + } + + if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) { + $variadicParameters = \array_slice($values, $lastParameter->getPosition()); + + foreach ($variadicParameters as $variadicParameter) { + $this->checkType($checkedDefinition, $variadicParameter, $lastParameter, $envPlaceholderUniquePrefix); + } + } + } + + /** + * @throws InvalidParameterTypeException When a parameter is not compatible with the declared type + */ + private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, \ReflectionType $reflectionType = null): void + { + $reflectionType = $reflectionType ?? $parameter->getType(); + + if ($reflectionType instanceof \ReflectionUnionType) { + foreach ($reflectionType->getTypes() as $t) { + try { + $this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $t); + + return; + } catch (InvalidParameterTypeException $e) { + } + } + + throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter); + } + if ($reflectionType instanceof \ReflectionIntersectionType) { + foreach ($reflectionType->getTypes() as $t) { + $this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $t); + } + + return; + } + if (!$reflectionType instanceof \ReflectionNamedType) { + return; + } + + $type = $reflectionType->getName(); + + if ($value instanceof Reference) { + if (!$this->container->has($value = (string) $value)) { + return; + } + + if ('service_container' === $value && is_a($type, Container::class, true)) { + return; + } + + $value = $this->container->findDefinition($value); + } + + if ('self' === $type) { + $type = $parameter->getDeclaringClass()->getName(); + } + + if ('static' === $type) { + $type = $checkedDefinition->getClass(); + } + + $class = null; + + if ($value instanceof Definition) { + if ($value->getFactory()) { + return; + } + + $class = $value->getClass(); + + if ($class && isset(self::BUILTIN_TYPES[strtolower($class)])) { + $class = strtolower($class); + } elseif (!$class || (!$this->autoload && !class_exists($class, false) && !interface_exists($class, false))) { + return; + } + } elseif ($value instanceof Parameter) { + $value = $this->container->getParameter($value); + } elseif ($value instanceof Expression) { + try { + $value = $this->getExpressionLanguage()->evaluate($value, ['container' => $this->container]); + } catch (\Exception $e) { + // If a service from the expression cannot be fetched from the container, we skip the validation. + return; + } + } elseif (\is_string($value)) { + if ('%' === ($value[0] ?? '') && preg_match('/^%([^%]+)%$/', $value, $match)) { + $value = $this->container->getParameter(substr($value, 1, -1)); + } + + if ($envPlaceholderUniquePrefix && \is_string($value) && str_contains($value, 'env_')) { + // If the value is an env placeholder that is either mixed with a string or with another env placeholder, then its resolved value will always be a string, so we don't need to resolve it. + // We don't need to change the value because it is already a string. + if ('' === preg_replace('/'.$envPlaceholderUniquePrefix.'_\w+_[a-f0-9]{32}/U', '', $value, -1, $c) && 1 === $c) { + try { + $value = $this->container->resolveEnvPlaceholders($value, true); + } catch (\Exception $e) { + // If an env placeholder cannot be resolved, we skip the validation. + return; + } + } + } + } + + if (null === $value && $parameter->allowsNull()) { + return; + } + + if (null === $class) { + if ($value instanceof IteratorArgument) { + $class = RewindableGenerator::class; + } elseif ($value instanceof ServiceClosureArgument) { + $class = \Closure::class; + } elseif ($value instanceof ServiceLocatorArgument) { + $class = ServiceLocator::class; + } elseif (\is_object($value)) { + $class = \get_class($value); + } else { + $class = \gettype($value); + $class = ['integer' => 'int', 'double' => 'float', 'boolean' => 'bool'][$class] ?? $class; + } + } + + if (isset(self::SCALAR_TYPES[$type]) && isset(self::SCALAR_TYPES[$class])) { + return; + } + + if ('string' === $type && method_exists($class, '__toString')) { + return; + } + + if ('callable' === $type && (\Closure::class === $class || method_exists($class, '__invoke'))) { + return; + } + + if ('callable' === $type && \is_array($value) && isset($value[0]) && ($value[0] instanceof Reference || $value[0] instanceof Definition || \is_string($value[0]))) { + return; + } + + if ('iterable' === $type && (\is_array($value) || 'array' === $class || is_subclass_of($class, \Traversable::class))) { + return; + } + + if ($type === $class) { + return; + } + + if ('object' === $type && !isset(self::BUILTIN_TYPES[$class])) { + return; + } + + if ('mixed' === $type) { + return; + } + + if (is_a($class, $type, true)) { + return; + } + + if ('false' === $type) { + if (false === $value) { + return; + } + } elseif ($reflectionType->isBuiltin()) { + $checkFunction = sprintf('is_%s', $type); + if ($checkFunction($value)) { + return; + } + } + + throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : \gettype($value), $parameter); + } + + private function getExpressionLanguage(): ExpressionLanguage + { + if (null === $this->expressionLanguage) { + $this->expressionLanguage = new ExpressionLanguage(null, $this->container->getExpressionLanguageProviders()); + } + + return $this->expressionLanguage; + } +} diff --git a/vendor/symfony/dependency-injection/Compiler/Compiler.php b/vendor/symfony/dependency-injection/Compiler/Compiler.php index 0eb9d036..224ff6b1 100644 --- a/vendor/symfony/dependency-injection/Compiler/Compiler.php +++ b/vendor/symfony/dependency-injection/Compiler/Compiler.php @@ -23,7 +23,6 @@ class Compiler { private $passConfig; private $log = []; - private $loggingFormatter; private $serviceReferenceGraph; public function __construct() @@ -52,68 +51,23 @@ public function getServiceReferenceGraph() return $this->serviceReferenceGraph; } - /** - * Returns the logging formatter which can be used by compilation passes. - * - * @return LoggingFormatter - * - * @deprecated since version 3.3, to be removed in 4.0. Use the ContainerBuilder::log() method instead. - */ - public function getLoggingFormatter() - { - if (null === $this->loggingFormatter) { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the ContainerBuilder::log() method instead.', __METHOD__), \E_USER_DEPRECATED); - - $this->loggingFormatter = new LoggingFormatter(); - } - - return $this->loggingFormatter; - } - /** * Adds a pass to the PassConfig. * - * @param CompilerPassInterface $pass A compiler pass - * @param string $type The type of the pass + * @param string $type The type of the pass + * @param int $priority Used to sort the passes */ - public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/) + public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0) { - if (\func_num_args() >= 3) { - $priority = func_get_arg(2); - } else { - if (__CLASS__ !== static::class) { - $r = new \ReflectionMethod($this, __FUNCTION__); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error(sprintf('Method %s() will have a third `int $priority = 0` argument in version 4.0. Not defining it is deprecated since Symfony 3.2.', __METHOD__), \E_USER_DEPRECATED); - } - } - - $priority = 0; - } - $this->passConfig->addPass($pass, $type, $priority); } - /** - * Adds a log message. - * - * @param string $string The log message - * - * @deprecated since version 3.3, to be removed in 4.0. Use the ContainerBuilder::log() method instead. - */ - public function addLogMessage($string) - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the ContainerBuilder::log() method instead.', __METHOD__), \E_USER_DEPRECATED); - - $this->log[] = $string; - } - /** * @final */ - public function log(CompilerPassInterface $pass, $message) + public function log(CompilerPassInterface $pass, string $message) { - if (false !== strpos($message, "\n")) { + if (str_contains($message, "\n")) { $message = str_replace("\n", "\n".\get_class($pass).': ', trim($message)); } diff --git a/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php b/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php index bf5f9157..af7c957a 100644 --- a/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php +++ b/vendor/symfony/dependency-injection/Compiler/DecoratorServicePass.php @@ -13,6 +13,10 @@ use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; +use Symfony\Component\DependencyInjection\Reference; /** * Overwrites a service but keeps the overridden one. @@ -36,14 +40,18 @@ public function process(ContainerBuilder $container) } $decoratingDefinitions = []; - foreach ($definitions as list($id, $definition)) { - list($inner, $renamedId) = $definition->getDecoratedService(); + foreach ($definitions as [$id, $definition]) { + $decoratedService = $definition->getDecoratedService(); + [$inner, $renamedId] = $decoratedService; + $invalidBehavior = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; $definition->setDecoratedService(null); if (!$renamedId) { $renamedId = $id.'.inner'; } + $definition->innerServiceId = $renamedId; + $definition->decorationOnInvalid = $invalidBehavior; // we create a new alias/service for the service we are replacing // to be able to reference it in the new one @@ -51,27 +59,46 @@ public function process(ContainerBuilder $container) $alias = $container->getAlias($inner); $public = $alias->isPublic(); $private = $alias->isPrivate(); - $container->setAlias($renamedId, new Alias($container->normalizeId($alias), false)); - } else { + $container->setAlias($renamedId, new Alias((string) $alias, false)); + $decoratedDefinition = $container->findDefinition($alias); + } elseif ($container->hasDefinition($inner)) { $decoratedDefinition = $container->getDefinition($inner); $public = $decoratedDefinition->isPublic(); $private = $decoratedDefinition->isPrivate(); $decoratedDefinition->setPublic(false); $container->setDefinition($renamedId, $decoratedDefinition); $decoratingDefinitions[$inner] = $decoratedDefinition; + } elseif (ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) { + $container->removeDefinition($id); + continue; + } elseif (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) { + $public = $definition->isPublic(); + $private = $definition->isPrivate(); + $decoratedDefinition = null; + } else { + throw new ServiceNotFoundException($inner, $id); + } + + if ($decoratedDefinition && $decoratedDefinition->isSynthetic()) { + throw new InvalidArgumentException(sprintf('A synthetic service cannot be decorated: service "%s" cannot decorate "%s".', $id, $inner)); } if (isset($decoratingDefinitions[$inner])) { $decoratingDefinition = $decoratingDefinitions[$inner]; - $definition->setTags(array_merge($decoratingDefinition->getTags(), $definition->getTags())); - $autowiringTypes = $decoratingDefinition->getAutowiringTypes(false); - if ($types = array_merge($autowiringTypes, $definition->getAutowiringTypes(false))) { - $definition->setAutowiringTypes($types); - } - $decoratingDefinition->setTags([]); - if ($autowiringTypes) { - $decoratingDefinition->setAutowiringTypes([]); + + $decoratingTags = $decoratingDefinition->getTags(); + $resetTags = []; + + // container.service_locator and container.service_subscriber have special logic and they must not be transferred out to decorators + foreach (['container.service_locator', 'container.service_subscriber'] as $containerTag) { + if (isset($decoratingTags[$containerTag])) { + $resetTags[$containerTag] = $decoratingTags[$containerTag]; + unset($decoratingTags[$containerTag]); + } } + + $definition->setTags(array_merge($decoratingTags, $definition->getTags())); + $decoratingDefinition->setTags($resetTags); $decoratingDefinitions[$inner] = $definition; } diff --git a/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php b/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php index 73b5d1d5..5ee0ff1f 100644 --- a/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php +++ b/vendor/symfony/dependency-injection/Compiler/DefinitionErrorExceptionPass.php @@ -11,8 +11,10 @@ namespace Symfony\Component\DependencyInjection\Compiler; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Reference; /** * Throws an exception for any Definitions that have errors and still exist. @@ -26,10 +28,25 @@ class DefinitionErrorExceptionPass extends AbstractRecursivePass */ protected function processValue($value, $isRoot = false) { - if (!$value instanceof Definition || empty($value->getErrors())) { + if (!$value instanceof Definition || !$value->hasErrors()) { return parent::processValue($value, $isRoot); } + if ($isRoot && !$value->isPublic()) { + $graph = $this->container->getCompiler()->getServiceReferenceGraph(); + $runtimeException = false; + foreach ($graph->getNode($this->currentId)->getInEdges() as $edge) { + if (!$edge->getValue() instanceof Reference || ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE !== $edge->getValue()->getInvalidBehavior()) { + $runtimeException = false; + break; + } + $runtimeException = true; + } + if ($runtimeException) { + return parent::processValue($value, $isRoot); + } + } + // only show the first error so the user can focus on it $errors = $value->getErrors(); $message = reset($errors); diff --git a/vendor/symfony/dependency-injection/Compiler/FactoryReturnTypePass.php b/vendor/symfony/dependency-injection/Compiler/FactoryReturnTypePass.php deleted file mode 100644 index 67575c03..00000000 --- a/vendor/symfony/dependency-injection/Compiler/FactoryReturnTypePass.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Compiler; - -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -/** - * @author Guilhem N. - * - * @deprecated since version 3.3, to be removed in 4.0. - */ -class FactoryReturnTypePass implements CompilerPassInterface -{ - private $resolveClassPass; - - public function __construct(ResolveClassPass $resolveClassPass = null) - { - if (null === $resolveClassPass) { - @trigger_error('The '.__CLASS__.' class is deprecated since Symfony 3.3 and will be removed in 4.0.', \E_USER_DEPRECATED); - } - $this->resolveClassPass = $resolveClassPass; - } - - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container) - { - // works only since php 7.0 and hhvm 3.11 - if (!method_exists(\ReflectionMethod::class, 'getReturnType')) { - return; - } - $resolveClassPassChanges = null !== $this->resolveClassPass ? $this->resolveClassPass->getChanges() : []; - - foreach ($container->getDefinitions() as $id => $definition) { - $this->updateDefinition($container, $id, $definition, $resolveClassPassChanges); - } - } - - private function updateDefinition(ContainerBuilder $container, $id, Definition $definition, array $resolveClassPassChanges, array $previous = []) - { - // circular reference - if (isset($previous[$id])) { - return; - } - - $factory = $definition->getFactory(); - if (null === $factory || (!isset($resolveClassPassChanges[$id]) && null !== $definition->getClass())) { - return; - } - - $class = null; - if (\is_string($factory)) { - try { - $m = new \ReflectionFunction($factory); - if (false !== $m->getFileName() && file_exists($m->getFileName())) { - $container->fileExists($m->getFileName()); - } - } catch (\ReflectionException $e) { - return; - } - } else { - if ($factory[0] instanceof Reference) { - $previous[$id] = true; - $factoryId = $container->normalizeId($factory[0]); - $factoryDefinition = $container->findDefinition($factoryId); - $this->updateDefinition($container, $factoryId, $factoryDefinition, $resolveClassPassChanges, $previous); - $class = $factoryDefinition->getClass(); - } else { - $class = $factory[0]; - } - - if (!$m = $container->getReflectionClass($class, false)) { - return; - } - try { - $m = $m->getMethod($factory[1]); - } catch (\ReflectionException $e) { - return; - } - } - - $returnType = $m->getReturnType(); - if (null !== $returnType && !$returnType->isBuiltin()) { - $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; - if (null !== $class) { - $declaringClass = $m->getDeclaringClass()->getName(); - if ('self' === strtolower($returnType)) { - $returnType = $declaringClass; - } elseif ('parent' === strtolower($returnType)) { - $returnType = get_parent_class($declaringClass) ?: null; - } - } - - if (null !== $returnType && (!isset($resolveClassPassChanges[$id]) || $returnType !== $resolveClassPassChanges[$id])) { - @trigger_error(sprintf('Relying on its factory\'s return-type to define the class of service "%s" is deprecated since Symfony 3.3 and won\'t work in 4.0. Set the "class" attribute to "%s" on the service definition instead.', $id, $returnType), \E_USER_DEPRECATED); - } - $definition->setClass($returnType); - } - } -} diff --git a/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php b/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php index 9d8a02e7..358b750f 100644 --- a/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Reference; @@ -23,31 +24,98 @@ */ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface { + private $analyzingPass; + private $repeatedPass; private $cloningIds = []; - private $inlinedServiceIds = []; + private $connectedIds = []; + private $notInlinedIds = []; + private $inlinedIds = []; + private $notInlinableIds = []; + private $graph; + + public function __construct(AnalyzeServiceReferencesPass $analyzingPass = null) + { + $this->analyzingPass = $analyzingPass; + } /** * {@inheritdoc} */ public function setRepeatedPass(RepeatedPass $repeatedPass) { - // no-op for BC + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); + $this->repeatedPass = $repeatedPass; } - /** - * Returns an array of all services inlined by this pass. - * - * The key is the inlined service id and its value is the list of services it was inlined into. - * - * @deprecated since version 3.4, to be removed in 4.0. - * - * @return array - */ - public function getInlinedServiceIds() + public function process(ContainerBuilder $container) { - @trigger_error('Calling InlineServiceDefinitionsPass::getInlinedServiceIds() is deprecated since Symfony 3.4 and will be removed in 4.0.', \E_USER_DEPRECATED); + $this->container = $container; + if ($this->analyzingPass) { + $analyzedContainer = new ContainerBuilder(); + $analyzedContainer->setAliases($container->getAliases()); + $analyzedContainer->setDefinitions($container->getDefinitions()); + foreach ($container->getExpressionLanguageProviders() as $provider) { + $analyzedContainer->addExpressionLanguageProvider($provider); + } + } else { + $analyzedContainer = $container; + } + try { + $remainingInlinedIds = []; + $this->connectedIds = $this->notInlinedIds = $container->getDefinitions(); + do { + if ($this->analyzingPass) { + $analyzedContainer->setDefinitions(array_intersect_key($analyzedContainer->getDefinitions(), $this->connectedIds)); + $this->analyzingPass->process($analyzedContainer); + } + $this->graph = $analyzedContainer->getCompiler()->getServiceReferenceGraph(); + $notInlinedIds = $this->notInlinedIds; + $this->connectedIds = $this->notInlinedIds = $this->inlinedIds = []; + + foreach ($analyzedContainer->getDefinitions() as $id => $definition) { + if (!$this->graph->hasNode($id)) { + continue; + } + foreach ($this->graph->getNode($id)->getOutEdges() as $edge) { + if (isset($notInlinedIds[$edge->getSourceNode()->getId()])) { + $this->currentId = $id; + $this->processValue($definition, true); + break; + } + } + } + + foreach ($this->inlinedIds as $id => $isPublicOrNotShared) { + if ($isPublicOrNotShared) { + $remainingInlinedIds[$id] = $id; + } else { + $container->removeDefinition($id); + $analyzedContainer->removeDefinition($id); + } + } + } while ($this->inlinedIds && $this->analyzingPass); + + if ($this->inlinedIds && $this->repeatedPass) { + $this->repeatedPass->setRepeat(); + } + + foreach ($remainingInlinedIds as $id) { + if (isset($this->notInlinableIds[$id])) { + continue; + } + + $definition = $container->getDefinition($id); - return $this->inlinedServiceIds; + if (!$definition->isShared() && !$definition->isPublic()) { + $container->removeDefinition($id); + } + } + } finally { + $this->container = null; + $this->connectedIds = $this->notInlinedIds = $this->inlinedIds = []; + $this->notInlinableIds = []; + $this->graph = null; + } } /** @@ -56,7 +124,7 @@ public function getInlinedServiceIds() protected function processValue($value, $isRoot = false) { if ($value instanceof ArgumentInterface) { - // Reference found in ArgumentInterface::getValues() are not inlineable + // References found in ArgumentInterface::getValues() are not inlineable return $value; } @@ -67,18 +135,23 @@ protected function processValue($value, $isRoot = false) $value = clone $value; } - if (!$value instanceof Reference || !$this->container->hasDefinition($id = $this->container->normalizeId($value))) { + if (!$value instanceof Reference) { return parent::processValue($value, $isRoot); + } elseif (!$this->container->hasDefinition($id = (string) $value)) { + return $value; } $definition = $this->container->getDefinition($id); - if (!$this->isInlineableDefinition($id, $definition, $this->container->getCompiler()->getServiceReferenceGraph())) { + if (!$this->isInlineableDefinition($id, $definition)) { + $this->notInlinableIds[$id] = true; + return $value; } $this->container->log($this, sprintf('Inlined service "%s" to "%s".', $id, $this->currentId)); - $this->inlinedServiceIds[$id][] = $this->currentId; + $this->inlinedIds[$id] = $definition->isPublic() || !$definition->isShared(); + $this->notInlinedIds[$this->currentId] = true; if ($definition->isShared()) { return $definition; @@ -101,53 +174,64 @@ protected function processValue($value, $isRoot = false) /** * Checks if the definition is inlineable. - * - * @return bool If the definition is inlineable */ - private function isInlineableDefinition($id, Definition $definition, ServiceReferenceGraph $graph) + private function isInlineableDefinition(string $id, Definition $definition): bool { - if ($definition->getErrors() || $definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic()) { + if ($definition->hasErrors() || $definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic()) { return false; } if (!$definition->isShared()) { + if (!$this->graph->hasNode($id)) { + return true; + } + + foreach ($this->graph->getNode($id)->getInEdges() as $edge) { + $srcId = $edge->getSourceNode()->getId(); + $this->connectedIds[$srcId] = true; + if ($edge->isWeak() || $edge->isLazy()) { + return !$this->connectedIds[$id] = true; + } + } + return true; } - if ($definition->isPublic() || $definition->isPrivate()) { + if ($definition->isPublic()) { return false; } - if (!$graph->hasNode($id)) { + if (!$this->graph->hasNode($id)) { return true; } if ($this->currentId == $id) { return false; } + $this->connectedIds[$id] = true; - $ids = []; - $isReferencedByConstructor = false; - foreach ($graph->getNode($id)->getInEdges() as $edge) { - $isReferencedByConstructor = $isReferencedByConstructor || $edge->isReferencedByConstructor(); + $srcIds = []; + $srcCount = 0; + foreach ($this->graph->getNode($id)->getInEdges() as $edge) { + $srcId = $edge->getSourceNode()->getId(); + $this->connectedIds[$srcId] = true; if ($edge->isWeak() || $edge->isLazy()) { return false; } - $ids[] = $edge->getSourceNode()->getId(); + $srcIds[$srcId] = true; + ++$srcCount; } - if (!$ids) { - return true; - } + if (1 !== \count($srcIds)) { + $this->notInlinedIds[$id] = true; - if (\count(array_unique($ids)) > 1) { return false; } - if (\count($ids) > 1 && \is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) { + if ($srcCount > 1 && \is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) { return false; } - return $this->container->getDefinition($ids[0])->isShared(); + return $this->container->getDefinition($srcId)->isShared(); } } diff --git a/vendor/symfony/dependency-injection/Compiler/LoggingFormatter.php b/vendor/symfony/dependency-injection/Compiler/LoggingFormatter.php deleted file mode 100644 index 0d91f00f..00000000 --- a/vendor/symfony/dependency-injection/Compiler/LoggingFormatter.php +++ /dev/null @@ -1,54 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Compiler; - -@trigger_error('The '.__NAMESPACE__.'\LoggingFormatter class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the ContainerBuilder::log() method instead.', \E_USER_DEPRECATED); - -/** - * Used to format logging messages during the compilation. - * - * @author Johannes M. Schmitt - * - * @deprecated since version 3.3, to be removed in 4.0. Use the ContainerBuilder::log() method instead. - */ -class LoggingFormatter -{ - public function formatRemoveService(CompilerPassInterface $pass, $id, $reason) - { - return $this->format($pass, sprintf('Removed service "%s"; reason: %s.', $id, $reason)); - } - - public function formatInlineService(CompilerPassInterface $pass, $id, $target) - { - return $this->format($pass, sprintf('Inlined service "%s" to "%s".', $id, $target)); - } - - public function formatUpdateReference(CompilerPassInterface $pass, $serviceId, $oldDestId, $newDestId) - { - return $this->format($pass, sprintf('Changed reference of service "%s" previously pointing to "%s" to "%s".', $serviceId, $oldDestId, $newDestId)); - } - - public function formatResolveInheritance(CompilerPassInterface $pass, $childId, $parentId) - { - return $this->format($pass, sprintf('Resolving inheritance for "%s" (parent: %s).', $childId, $parentId)); - } - - public function formatUnusedAutowiringPatterns(CompilerPassInterface $pass, $id, array $patterns) - { - return $this->format($pass, sprintf('Autowiring\'s patterns "%s" for service "%s" don\'t match any method.', implode('", "', $patterns), $id)); - } - - public function format(CompilerPassInterface $pass, $message) - { - return sprintf('%s: %s', \get_class($pass), $message); - } -} diff --git a/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php b/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php index caa1fd22..5e4dd399 100644 --- a/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php +++ b/vendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; @@ -37,6 +38,7 @@ public function process(ContainerBuilder $container) $definitions = $container->getDefinitions(); $aliases = $container->getAliases(); $exprLangProviders = $container->getExpressionLanguageProviders(); + $configAvailable = class_exists(BaseNode::class); foreach ($container->getExtensions() as $extension) { if ($extension instanceof PrependExtensionInterface) { @@ -53,6 +55,9 @@ public function process(ContainerBuilder $container) if ($resolvingBag instanceof EnvPlaceholderParameterBag && $extension instanceof Extension) { // create a dedicated bag so that we can track env vars per-extension $resolvingBag = new MergeExtensionConfigurationParameterBag($resolvingBag); + if ($configAvailable) { + BaseNode::setPlaceholderUniquePrefix($resolvingBag->getEnvPlaceholderUniquePrefix()); + } } $config = $resolvingBag->resolveValue($config); @@ -74,6 +79,10 @@ public function process(ContainerBuilder $container) $container->getParameterBag()->mergeEnvPlaceholders($resolvingBag); } + if ($configAvailable) { + BaseNode::resetPlaceholders(); + } + throw $e; } @@ -86,6 +95,10 @@ public function process(ContainerBuilder $container) $container->getParameterBag()->add($parameters); } + if ($configAvailable) { + BaseNode::resetPlaceholders(); + } + $container->addDefinitions($definitions); $container->addAliases($aliases); } @@ -128,9 +141,14 @@ public function freezeAfterProcessing(Extension $extension, ContainerBuilder $co /** * {@inheritdoc} */ - public function getEnvPlaceholders() + public function getEnvPlaceholders(): array + { + return $this->processedEnvPlaceholders ?? parent::getEnvPlaceholders(); + } + + public function getUnusedEnvPlaceholders(): array { - return null !== $this->processedEnvPlaceholders ? $this->processedEnvPlaceholders : parent::getEnvPlaceholders(); + return null === $this->processedEnvPlaceholders ? [] : array_diff_key(parent::getEnvPlaceholders(), $this->processedEnvPlaceholders); } } @@ -153,7 +171,7 @@ public function __construct(ExtensionInterface $extension, ParameterBagInterface /** * {@inheritdoc} */ - public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/) + public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): self { throw new LogicException(sprintf('You cannot add compiler pass "%s" from extension "%s". Compiler passes must be registered before the container is compiled.', \get_class($pass), $this->extensionClass)); } @@ -169,7 +187,7 @@ public function registerExtension(ExtensionInterface $extension) /** * {@inheritdoc} */ - public function compile($resolveEnvPlaceholders = false) + public function compile(bool $resolveEnvPlaceholders = false) { throw new LogicException(sprintf('Cannot compile the container in extension "%s".', $this->extensionClass)); } @@ -191,7 +209,7 @@ public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs } foreach ($bag->getEnvPlaceholders() as $env => $placeholders) { - if (false === strpos($env, ':')) { + if (!str_contains($env, ':')) { continue; } foreach ($placeholders as $placeholder) { diff --git a/vendor/symfony/dependency-injection/Compiler/PassConfig.php b/vendor/symfony/dependency-injection/Compiler/PassConfig.php index d95b2198..f02a88fc 100644 --- a/vendor/symfony/dependency-injection/Compiler/PassConfig.php +++ b/vendor/symfony/dependency-injection/Compiler/PassConfig.php @@ -22,11 +22,11 @@ */ class PassConfig { - const TYPE_AFTER_REMOVING = 'afterRemoving'; - const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization'; - const TYPE_BEFORE_REMOVING = 'beforeRemoving'; - const TYPE_OPTIMIZE = 'optimization'; - const TYPE_REMOVE = 'removing'; + public const TYPE_AFTER_REMOVING = 'afterRemoving'; + public const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization'; + public const TYPE_BEFORE_REMOVING = 'beforeRemoving'; + public const TYPE_OPTIMIZE = 'optimization'; + public const TYPE_REMOVE = 'removing'; private $mergePass; private $afterRemovingPasses = []; @@ -41,7 +41,7 @@ public function __construct() $this->beforeOptimizationPasses = [ 100 => [ - $resolveClassPass = new ResolveClassPass(), + new ResolveClassPass(), new ResolveInstanceofConditionalsPass(), new RegisterEnvVarProcessorsPass(), ], @@ -49,17 +49,17 @@ public function __construct() ]; $this->optimizationPasses = [[ + new ValidateEnvPlaceholdersPass(), new ResolveChildDefinitionsPass(), - new ServiceLocatorTagPass(), new RegisterServiceSubscribersPass(), - new DecoratorServicePass(), new ResolveParameterPlaceHoldersPass(false, false), new ResolveFactoryClassPass(), - new FactoryReturnTypePass($resolveClassPass), - new CheckDefinitionValidityPass(), new ResolveNamedArgumentsPass(), new AutowireRequiredMethodsPass(), new ResolveBindingsPass(), + new ServiceLocatorTagPass(), + new DecoratorServicePass(), + new CheckDefinitionValidityPass(), new AutowirePass(false), new ResolveTaggedIteratorArgumentPass(), new ResolveServiceSubscribersPass(), @@ -81,14 +81,15 @@ public function __construct() new RemovePrivateAliasesPass(), new ReplaceAliasByActualDefinitionPass(), new RemoveAbstractDefinitionsPass(), - new RepeatedPass([ - new AnalyzeServiceReferencesPass(), - new InlineServiceDefinitionsPass(), - new AnalyzeServiceReferencesPass(), - new RemoveUnusedDefinitionsPass(), - ]), - new DefinitionErrorExceptionPass(), + new RemoveUnusedDefinitionsPass(), + new AnalyzeServiceReferencesPass(), new CheckExceptionOnInvalidReferenceBehaviorPass(), + new InlineServiceDefinitionsPass(new AnalyzeServiceReferencesPass()), + new AnalyzeServiceReferencesPass(), + new DefinitionErrorExceptionPass(), + ]]; + + $this->afterRemovingPasses = [[ new ResolveHotPathPass(), ]]; } @@ -113,26 +114,13 @@ public function getPasses() /** * Adds a pass. * - * @param CompilerPassInterface $pass A Compiler pass - * @param string $type The pass type + * @param string $type The pass type + * @param int $priority Used to sort the passes * * @throws InvalidArgumentException when a pass type doesn't exist */ - public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/) + public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION, int $priority = 0) { - if (\func_num_args() >= 3) { - $priority = func_get_arg(2); - } else { - if (__CLASS__ !== static::class) { - $r = new \ReflectionMethod($this, __FUNCTION__); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error(sprintf('Method %s() will have a third `int $priority = 0` argument in version 4.0. Not defining it is deprecated since Symfony 3.2.', __METHOD__), \E_USER_DEPRECATED); - } - } - - $priority = 0; - } - $property = $type.'Passes'; if (!isset($this->$property)) { throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type)); @@ -268,7 +256,7 @@ public function setRemovingPasses(array $passes) * * @return CompilerPassInterface[] */ - private function sortPasses(array $passes) + private function sortPasses(array $passes): array { if (0 === \count($passes)) { return []; @@ -277,6 +265,6 @@ private function sortPasses(array $passes) krsort($passes); // Flatten the array - return \call_user_func_array('array_merge', $passes); + return array_merge(...$passes); } } diff --git a/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php b/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php index c7e12536..f558927e 100644 --- a/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php +++ b/vendor/symfony/dependency-injection/Compiler/PriorityTaggedServiceTrait.php @@ -11,8 +11,11 @@ namespace Symfony\Component\DependencyInjection\Compiler; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; /** * Trait that allows a generic method to find and sort service by priority option in the tag. @@ -31,24 +34,141 @@ trait PriorityTaggedServiceTrait * @see https://bugs.php.net/53710 * @see https://bugs.php.net/60926 * - * @param string $tagName + * @param string|TaggedIteratorArgument $tagName * * @return Reference[] */ - private function findAndSortTaggedServices($tagName, ContainerBuilder $container) + private function findAndSortTaggedServices($tagName, ContainerBuilder $container): array { + $indexAttribute = $defaultIndexMethod = $needsIndexes = $defaultPriorityMethod = null; + + if ($tagName instanceof TaggedIteratorArgument) { + $indexAttribute = $tagName->getIndexAttribute(); + $defaultIndexMethod = $tagName->getDefaultIndexMethod(); + $needsIndexes = $tagName->needsIndexes(); + $defaultPriorityMethod = $tagName->getDefaultPriorityMethod() ?? 'getDefaultPriority'; + $tagName = $tagName->getTag(); + } + + $i = 0; $services = []; foreach ($container->findTaggedServiceIds($tagName, true) as $serviceId => $attributes) { - $priority = isset($attributes[0]['priority']) ? $attributes[0]['priority'] : 0; - $services[$priority][] = new Reference($serviceId); + $defaultPriority = null; + $defaultIndex = null; + $class = $container->getDefinition($serviceId)->getClass(); + $class = $container->getParameterBag()->resolveValue($class) ?: null; + + foreach ($attributes as $attribute) { + $index = $priority = null; + + if (isset($attribute['priority'])) { + $priority = $attribute['priority']; + } elseif (null === $defaultPriority && $defaultPriorityMethod && $class) { + $defaultPriority = PriorityTaggedServiceUtil::getDefaultPriority($container, $serviceId, $class, $defaultPriorityMethod, $tagName); + } + $priority = $priority ?? $defaultPriority ?? $defaultPriority = 0; + + if (null === $indexAttribute && !$defaultIndexMethod && !$needsIndexes) { + $services[] = [$priority, ++$i, null, $serviceId, null]; + continue 2; + } + + if (null !== $indexAttribute && isset($attribute[$indexAttribute])) { + $index = $attribute[$indexAttribute]; + } elseif (null === $defaultIndex && $defaultPriorityMethod && $class) { + $defaultIndex = PriorityTaggedServiceUtil::getDefaultIndex($container, $serviceId, $class, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute); + } + $index = $index ?? $defaultIndex ?? $defaultIndex = $serviceId; + + $services[] = [$priority, ++$i, $index, $serviceId, $class]; + } + } + + uasort($services, static function ($a, $b) { return $b[0] <=> $a[0] ?: $a[1] <=> $b[1]; }); + + $refs = []; + foreach ($services as [, , $index, $serviceId, $class]) { + if (!$class) { + $reference = new Reference($serviceId); + } elseif ($index === $serviceId) { + $reference = new TypedReference($serviceId, $class); + } else { + $reference = new TypedReference($serviceId, $class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, $index); + } + + if (null === $index) { + $refs[] = $reference; + } else { + $refs[$index] = $reference; + } + } + + return $refs; + } +} + +/** + * @internal + */ +class PriorityTaggedServiceUtil +{ + /** + * Gets the index defined by the default index method. + */ + public static function getDefaultIndex(ContainerBuilder $container, string $serviceId, string $class, string $defaultIndexMethod, string $tagName, ?string $indexAttribute): ?string + { + if (!($r = $container->getReflectionClass($class)) || !$r->hasMethod($defaultIndexMethod)) { + return null; + } + + if (null !== $indexAttribute) { + $service = $class !== $serviceId ? sprintf('service "%s"', $serviceId) : 'on the corresponding service'; + $message = [sprintf('Either method "%s::%s()" should ', $class, $defaultIndexMethod), sprintf(' or tag "%s" on %s is missing attribute "%s".', $tagName, $service, $indexAttribute)]; + } else { + $message = [sprintf('Method "%s::%s()" should ', $class, $defaultIndexMethod), '.']; + } + + if (!($rm = $r->getMethod($defaultIndexMethod))->isStatic()) { + throw new InvalidArgumentException(implode('be static', $message)); + } + + if (!$rm->isPublic()) { + throw new InvalidArgumentException(implode('be public', $message)); + } + + $defaultIndex = $rm->invoke(null); + + if (!\is_string($defaultIndex)) { + throw new InvalidArgumentException(implode(sprintf('return a string (got "%s")', \gettype($defaultIndex)), $message)); + } + + return $defaultIndex; + } + + /** + * Gets the priority defined by the default priority method. + */ + public static function getDefaultPriority(ContainerBuilder $container, string $serviceId, string $class, string $defaultPriorityMethod, string $tagName): ?int + { + if (!($r = $container->getReflectionClass($class)) || !$r->hasMethod($defaultPriorityMethod)) { + return null; } - if ($services) { - krsort($services); - $services = \call_user_func_array('array_merge', $services); + if (!($rm = $r->getMethod($defaultPriorityMethod))->isStatic()) { + throw new InvalidArgumentException(sprintf('Either method "%s::%s()" should be static or tag "%s" on service "%s" is missing attribute "priority".', $class, $defaultPriorityMethod, $tagName, $serviceId)); + } + + if (!$rm->isPublic()) { + throw new InvalidArgumentException(sprintf('Either method "%s::%s()" should be public or tag "%s" on service "%s" is missing attribute "priority".', $class, $defaultPriorityMethod, $tagName, $serviceId)); + } + + $defaultPriority = $rm->invoke(null); + + if (!\is_int($defaultPriority)) { + throw new InvalidArgumentException(sprintf('Method "%s::%s()" should return an integer (got "%s") or tag "%s" on service "%s" is missing attribute "priority".', $class, $defaultPriorityMethod, \gettype($defaultPriority), $tagName, $serviceId)); } - return $services; + return $defaultPriority; } } diff --git a/vendor/symfony/dependency-injection/Compiler/RegisterEnvVarProcessorsPass.php b/vendor/symfony/dependency-injection/Compiler/RegisterEnvVarProcessorsPass.php index b4d0d055..251889eb 100644 --- a/vendor/symfony/dependency-injection/Compiler/RegisterEnvVarProcessorsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/RegisterEnvVarProcessorsPass.php @@ -11,14 +11,12 @@ namespace Symfony\Component\DependencyInjection\Compiler; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\EnvVarProcessor; use Symfony\Component\DependencyInjection\EnvVarProcessorInterface; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; /** * Creates the container.env_var_processors_locator service. @@ -27,7 +25,7 @@ */ class RegisterEnvVarProcessorsPass implements CompilerPassInterface { - private static $allowedTypes = ['array', 'bool', 'float', 'int', 'string']; + private const ALLOWED_TYPES = ['array', 'bool', 'float', 'int', 'string']; public function process(ContainerBuilder $container) { @@ -41,7 +39,7 @@ public function process(ContainerBuilder $container) throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EnvVarProcessorInterface::class)); } foreach ($class::getProvidedTypes() as $prefix => $type) { - $processors[$prefix] = new ServiceClosureArgument(new Reference($id)); + $processors[$prefix] = new Reference($id); $types[$prefix] = self::validateProvidedTypes($type, $class); } } @@ -56,20 +54,19 @@ public function process(ContainerBuilder $container) } if ($processors) { - $container->register('container.env_var_processors_locator', ServiceLocator::class) + $container->setAlias('container.env_var_processors_locator', (string) ServiceLocatorTagPass::register($container, $processors)) ->setPublic(true) - ->setArguments([$processors]) ; } } - private static function validateProvidedTypes($types, $class) + private static function validateProvidedTypes(string $types, string $class): array { $types = explode('|', $types); foreach ($types as $type) { - if (!\in_array($type, self::$allowedTypes)) { - throw new InvalidArgumentException(sprintf('Invalid type "%s" returned by "%s::getProvidedTypes()", expected one of "%s".', $type, $class, implode('", "', self::$allowedTypes))); + if (!\in_array($type, self::ALLOWED_TYPES)) { + throw new InvalidArgumentException(sprintf('Invalid type "%s" returned by "%s::getProvidedTypes()", expected one of "%s".', $type, $class, implode('", "', self::ALLOWED_TYPES))); } } diff --git a/vendor/symfony/dependency-injection/Compiler/RegisterReverseContainerPass.php b/vendor/symfony/dependency-injection/Compiler/RegisterReverseContainerPass.php new file mode 100644 index 00000000..571eab3e --- /dev/null +++ b/vendor/symfony/dependency-injection/Compiler/RegisterReverseContainerPass.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas + */ +class RegisterReverseContainerPass implements CompilerPassInterface +{ + private $beforeRemoving; + private $serviceId; + private $tagName; + + public function __construct(bool $beforeRemoving, string $serviceId = 'reverse_container', string $tagName = 'container.reversible') + { + $this->beforeRemoving = $beforeRemoving; + $this->serviceId = $serviceId; + $this->tagName = $tagName; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->serviceId)) { + return; + } + + $refType = $this->beforeRemoving ? ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + $services = []; + foreach ($container->findTaggedServiceIds($this->tagName) as $id => $tags) { + $services[$id] = new Reference($id, $refType); + } + + if ($this->beforeRemoving) { + // prevent inlining of the reverse container + $services[$this->serviceId] = new Reference($this->serviceId, $refType); + } + $locator = $container->getDefinition($this->serviceId)->getArgument(1); + + if ($locator instanceof Reference) { + $locator = $container->getDefinition((string) $locator); + } + if ($locator instanceof Definition) { + foreach ($services as $id => $ref) { + $services[$id] = new ServiceClosureArgument($ref); + } + $locator->replaceArgument(0, $services); + } else { + $locator->setValues($services); + } + } +} diff --git a/vendor/symfony/dependency-injection/Compiler/RegisterServiceSubscribersPass.php b/vendor/symfony/dependency-injection/Compiler/RegisterServiceSubscribersPass.php index bf1387c0..b6d1ede4 100644 --- a/vendor/symfony/dependency-injection/Compiler/RegisterServiceSubscribersPass.php +++ b/vendor/symfony/dependency-injection/Compiler/RegisterServiceSubscribersPass.php @@ -11,12 +11,15 @@ namespace Symfony\Component\DependencyInjection\Compiler; +use Psr\Container\ContainerInterface as PsrContainerInterface; +use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\DependencyInjection\TypedReference; +use Symfony\Contracts\Service\ServiceProviderInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; /** * Compiler pass to register tagged services that require a service locator. @@ -65,7 +68,6 @@ protected function processValue($value, $isRoot = false) $class = $r->name; $subscriberMap = []; - $declaringClass = (new \ReflectionMethod($class, 'getSubscribedServices'))->class; foreach ($class::getSubscribedServices() as $key => $type) { if (!\is_string($type) || !preg_match('/^\??[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $type)) { @@ -75,8 +77,9 @@ protected function processValue($value, $isRoot = false) $type = substr($type, 1); $optionalBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; } - if (\is_int($key)) { + if (\is_int($name = $key)) { $key = $type; + $name = null; } if (!isset($serviceMap[$key])) { if (!$autowire) { @@ -85,7 +88,20 @@ protected function processValue($value, $isRoot = false) $serviceMap[$key] = new Reference($type); } - $subscriberMap[$key] = new TypedReference($this->container->normalizeId($serviceMap[$key]), $type, $declaringClass, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE); + if ($name) { + if (false !== $i = strpos($name, '::get')) { + $name = lcfirst(substr($name, 5 + $i)); + } elseif (str_contains($name, '::')) { + $name = null; + } + } + + if (null !== $name && !$this->container->has($name) && !$this->container->has($type.' $'.$name)) { + $camelCaseName = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name)))); + $name = $this->container->has($type.' $'.$camelCaseName) ? $camelCaseName : $name; + } + + $subscriberMap[$key] = new TypedReference((string) $serviceMap[$key], $type, $optionalBehavior ?: ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $name); unset($serviceMap[$key]); } @@ -94,7 +110,14 @@ protected function processValue($value, $isRoot = false) throw new InvalidArgumentException(sprintf('Service %s not exist in the map returned by "%s::getSubscribedServices()" for service "%s".', $message, $class, $this->currentId)); } - $value->addTag('container.service_subscriber.locator', ['id' => (string) ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId)]); + $locatorRef = ServiceLocatorTagPass::register($this->container, $subscriberMap, $this->currentId); + + $value->addTag('container.service_subscriber.locator', ['id' => (string) $locatorRef]); + + $value->setBindings([ + PsrContainerInterface::class => new BoundArgument($locatorRef, false), + ServiceProviderInterface::class => new BoundArgument($locatorRef, false), + ] + $value->getBindings()); return parent::processValue($value); } diff --git a/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php b/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php index 03d9e1d8..75b36d22 100644 --- a/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php +++ b/vendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php @@ -28,7 +28,7 @@ class RemovePrivateAliasesPass implements CompilerPassInterface public function process(ContainerBuilder $container) { foreach ($container->getAliases() as $id => $alias) { - if ($alias->isPublic() || $alias->isPrivate()) { + if ($alias->isPublic()) { continue; } diff --git a/vendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php b/vendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php index a1013f66..8f3a1c2d 100644 --- a/vendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php @@ -12,22 +12,24 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; /** * Removes unused service definitions from the container. * * @author Johannes M. Schmitt + * @author Nicolas Grekas */ -class RemoveUnusedDefinitionsPass implements RepeatablePassInterface +class RemoveUnusedDefinitionsPass extends AbstractRecursivePass implements RepeatablePassInterface { - private $repeatedPass; + private $connectedIds = []; /** * {@inheritdoc} */ public function setRepeatedPass(RepeatedPass $repeatedPass) { - $this->repeatedPass = $repeatedPass; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); } /** @@ -35,51 +37,62 @@ public function setRepeatedPass(RepeatedPass $repeatedPass) */ public function process(ContainerBuilder $container) { - $graph = $container->getCompiler()->getServiceReferenceGraph(); + try { + $this->enableExpressionProcessing(); + $this->container = $container; + $connectedIds = []; + $aliases = $container->getAliases(); - $hasChanged = false; - foreach ($container->getDefinitions() as $id => $definition) { - if ($definition->isPublic() || $definition->isPrivate()) { - continue; + foreach ($aliases as $id => $alias) { + if ($alias->isPublic()) { + $this->connectedIds[] = (string) $aliases[$id]; + } } - if ($graph->hasNode($id)) { - $edges = $graph->getNode($id)->getInEdges(); - $referencingAliases = []; - $sourceIds = []; - foreach ($edges as $edge) { - if ($edge->isWeak()) { - continue; - } - $node = $edge->getSourceNode(); - $sourceIds[] = $node->getId(); + foreach ($container->getDefinitions() as $id => $definition) { + if ($definition->isPublic()) { + $connectedIds[$id] = true; + $this->processValue($definition); + } + } - if ($node->isAlias()) { - $referencingAliases[] = $node->getValue(); + while ($this->connectedIds) { + $ids = $this->connectedIds; + $this->connectedIds = []; + foreach ($ids as $id) { + if (!isset($connectedIds[$id]) && $container->hasDefinition($id)) { + $connectedIds[$id] = true; + $this->processValue($container->getDefinition($id)); } } - $isReferenced = (\count(array_unique($sourceIds)) - \count($referencingAliases)) > 0; - } else { - $referencingAliases = []; - $isReferenced = false; } - if (1 === \count($referencingAliases) && false === $isReferenced) { - $container->setDefinition((string) reset($referencingAliases), $definition); - $definition->setPublic(!$definition->isPrivate()); - $definition->setPrivate(reset($referencingAliases)->isPrivate()); - $container->removeDefinition($id); - $container->log($this, sprintf('Removed service "%s"; reason: replaces alias %s.', $id, reset($referencingAliases))); - } elseif (0 === \count($referencingAliases) && false === $isReferenced) { - $container->removeDefinition($id); - $container->resolveEnvPlaceholders(serialize($definition)); - $container->log($this, sprintf('Removed service "%s"; reason: unused.', $id)); - $hasChanged = true; + foreach ($container->getDefinitions() as $id => $definition) { + if (!isset($connectedIds[$id])) { + $container->removeDefinition($id); + $container->resolveEnvPlaceholders(!$definition->hasErrors() ? serialize($definition) : $definition); + $container->log($this, sprintf('Removed service "%s"; reason: unused.', $id)); + } } + } finally { + $this->container = null; + $this->connectedIds = []; } + } - if ($hasChanged) { - $this->repeatedPass->setRepeat(); + /** + * {@inheritdoc} + */ + protected function processValue($value, $isRoot = false) + { + if (!$value instanceof Reference) { + return parent::processValue($value, $isRoot); } + + if (ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior()) { + $this->connectedIds[] = (string) $value; + } + + return $value; } } diff --git a/vendor/symfony/dependency-injection/Compiler/RepeatablePassInterface.php b/vendor/symfony/dependency-injection/Compiler/RepeatablePassInterface.php index 2b88bfb9..11a5b0d5 100644 --- a/vendor/symfony/dependency-injection/Compiler/RepeatablePassInterface.php +++ b/vendor/symfony/dependency-injection/Compiler/RepeatablePassInterface.php @@ -16,6 +16,8 @@ * RepeatedPass. * * @author Johannes M. Schmitt + * + * @deprecated since Symfony 4.2. */ interface RepeatablePassInterface extends CompilerPassInterface { diff --git a/vendor/symfony/dependency-injection/Compiler/RepeatedPass.php b/vendor/symfony/dependency-injection/Compiler/RepeatedPass.php index 3da1a0d5..bc155cf0 100644 --- a/vendor/symfony/dependency-injection/Compiler/RepeatedPass.php +++ b/vendor/symfony/dependency-injection/Compiler/RepeatedPass.php @@ -11,6 +11,8 @@ namespace Symfony\Component\DependencyInjection\Compiler; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', RepeatedPass::class), \E_USER_DEPRECATED); + use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; @@ -18,6 +20,8 @@ * A pass that might be run repeatedly. * * @author Johannes M. Schmitt + * + * @deprecated since Symfony 4.2. */ class RepeatedPass implements CompilerPassInterface { diff --git a/vendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php b/vendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php index 472bf941..99810963 100644 --- a/vendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Reference; /** @@ -36,7 +37,7 @@ public function process(ContainerBuilder $container) $seenAliasTargets = []; $replacements = []; foreach ($container->getAliases() as $definitionId => $target) { - $targetId = $container->normalizeId($target); + $targetId = (string) $target; // Special case: leave this target alone if ('service_container' === $targetId) { continue; @@ -53,10 +54,14 @@ public function process(ContainerBuilder $container) $seenAliasTargets[$targetId] = true; try { $definition = $container->getDefinition($targetId); - } catch (InvalidArgumentException $e) { - throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $definitionId, $targetId), null, $e); + } catch (ServiceNotFoundException $e) { + if ('' !== $e->getId() && '@' === $e->getId()[0]) { + throw new ServiceNotFoundException($e->getId(), $e->getSourceId(), null, [substr($e->getId(), 1)]); + } + + throw $e; } - if ($definition->isPublic() || $definition->isPrivate()) { + if ($definition->isPublic()) { continue; } // Remove private definition and schedule for replacement @@ -77,7 +82,7 @@ public function process(ContainerBuilder $container) */ protected function processValue($value, $isRoot = false) { - if ($value instanceof Reference && isset($this->replacements[$referenceId = $this->container->normalizeId($value)])) { + if ($value instanceof Reference && isset($this->replacements[$referenceId = (string) $value])) { // Perform the replacement $newId = $this->replacements[$referenceId]; $value = new Reference($newId, $value->getInvalidBehavior()); diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php index 065dbb4b..97b613f6 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveBindingsPass.php @@ -12,6 +12,8 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Argument\BoundArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; +use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; @@ -39,8 +41,39 @@ public function process(ContainerBuilder $container) try { parent::process($container); - foreach ($this->unusedBindings as list($key, $serviceId)) { - $message = sprintf('Unused binding "%s" in service "%s".', $key, $serviceId); + foreach ($this->unusedBindings as [$key, $serviceId, $bindingType, $file]) { + $argumentType = $argumentName = $message = null; + + if (str_contains($key, ' ')) { + [$argumentType, $argumentName] = explode(' ', $key, 2); + } elseif ('$' === $key[0]) { + $argumentName = $key; + } else { + $argumentType = $key; + } + + if ($argumentType) { + $message .= sprintf('of type "%s" ', $argumentType); + } + + if ($argumentName) { + $message .= sprintf('named "%s" ', $argumentName); + } + + if (BoundArgument::DEFAULTS_BINDING === $bindingType) { + $message .= 'under "_defaults"'; + } elseif (BoundArgument::INSTANCEOF_BINDING === $bindingType) { + $message .= 'under "_instanceof"'; + } else { + $message .= sprintf('for service "%s"', $serviceId); + } + + if ($file) { + $message .= sprintf(' in file "%s"', $file); + } + + $message = sprintf('A binding is configured for an argument %s, but no corresponding argument has been found. It may be unused and should be removed, or it may have a typo.', $message); + if ($this->errorMessages) { $message .= sprintf("\nCould be related to%s:", 1 < \count($this->errorMessages) ? ' one of' : ''); } @@ -61,9 +94,14 @@ public function process(ContainerBuilder $container) */ protected function processValue($value, $isRoot = false) { - if ($value instanceof TypedReference && $value->getType() === $this->container->normalizeId($value)) { + if ($value instanceof TypedReference && $value->getType() === (string) $value) { // Already checked $bindings = $this->container->getDefinition($this->currentId)->getBindings(); + $name = $value->getName(); + + if (isset($name, $bindings[$name = $value.' $'.$name])) { + return $this->getBindingValue($bindings[$name]); + } if (isset($bindings[$value->getType()])) { return $this->getBindingValue($bindings[$value->getType()]); @@ -76,21 +114,32 @@ protected function processValue($value, $isRoot = false) return parent::processValue($value, $isRoot); } + $bindingNames = []; + foreach ($bindings as $key => $binding) { - list($bindingValue, $bindingId, $used) = $binding->getValues(); + [$bindingValue, $bindingId, $used, $bindingType, $file] = $binding->getValues(); if ($used) { $this->usedBindings[$bindingId] = true; unset($this->unusedBindings[$bindingId]); } elseif (!isset($this->usedBindings[$bindingId])) { - $this->unusedBindings[$bindingId] = [$key, $this->currentId]; + $this->unusedBindings[$bindingId] = [$key, $this->currentId, $bindingType, $file]; + } + + if (preg_match('/^(?:(?:array|bool|float|int|string|iterable|([^ $]++)) )\$/', $key, $m)) { + $bindingNames[substr($key, \strlen($m[0]))] = $binding; } - if (isset($key[0]) && '$' === $key[0]) { + if (!isset($m[1])) { continue; } - if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition) { - throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected null, an instance of "%s" or an instance of "%s", "%s" given.', $key, $this->currentId, Reference::class, Definition::class, \gettype($bindingValue))); + if (is_subclass_of($m[1], \UnitEnum::class)) { + $bindingNames[substr($key, \strlen($m[0]))] = $binding; + continue; + } + + if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) { + throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, \gettype($bindingValue))); } } @@ -112,7 +161,7 @@ protected function processValue($value, $isRoot = false) } foreach ($calls as $i => $call) { - list($method, $arguments) = $call; + [$method, $arguments] = $call; if ($method instanceof \ReflectionFunctionAbstract) { $reflectionMethod = $method; @@ -132,19 +181,31 @@ protected function processValue($value, $isRoot = false) continue; } + $typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter); + + if ($typeHint && \array_key_exists($k = ltrim($typeHint, '\\').' $'.$parameter->name, $bindings)) { + $arguments[$key] = $this->getBindingValue($bindings[$k]); + + continue; + } + if (\array_key_exists('$'.$parameter->name, $bindings)) { $arguments[$key] = $this->getBindingValue($bindings['$'.$parameter->name]); continue; } - $typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter, true); + if ($typeHint && '\\' === $typeHint[0] && isset($bindings[$typeHint = substr($typeHint, 1)])) { + $arguments[$key] = $this->getBindingValue($bindings[$typeHint]); - if (!isset($bindings[$typeHint])) { continue; } - $arguments[$key] = $this->getBindingValue($bindings[$typeHint]); + if (isset($bindingNames[$parameter->name])) { + $bindingKey = array_search($binding, $bindings, true); + $argumentType = substr($bindingKey, 0, strpos($bindingKey, ' ')); + $this->errorMessages[] = sprintf('Did you forget to add the type "%s" to argument "$%s" of method "%s::%s()"?', $argumentType, $parameter->name, $reflectionMethod->class, $reflectionMethod->name); + } } if ($arguments !== $call[1]) { @@ -154,7 +215,7 @@ protected function processValue($value, $isRoot = false) } if ($constructor) { - list(, $arguments) = array_pop($calls); + [, $arguments] = array_pop($calls); if ($arguments !== $value->getArguments()) { $value->setArguments($arguments); @@ -168,9 +229,12 @@ protected function processValue($value, $isRoot = false) return parent::processValue($value, $isRoot); } + /** + * @return mixed + */ private function getBindingValue(BoundArgument $binding) { - list($bindingValue, $bindingId) = $binding->getValues(); + [$bindingValue, $bindingId] = $binding->getValues(); $this->usedBindings[$bindingId] = true; unset($this->unusedBindings[$bindingId]); diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php index 539395a4..333480d6 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveChildDefinitionsPass.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\ExceptionInterface; use Symfony\Component\DependencyInjection\Exception\RuntimeException; @@ -52,11 +53,9 @@ protected function processValue($value, $isRoot = false) /** * Resolves the definition. * - * @return Definition - * * @throws RuntimeException When the definition is invalid */ - private function resolveDefinition(ChildDefinition $definition) + private function resolveDefinition(ChildDefinition $definition): Definition { try { return $this->doResolveDefinition($definition); @@ -71,7 +70,7 @@ private function resolveDefinition(ChildDefinition $definition) } } - private function doResolveDefinition(ChildDefinition $definition) + private function doResolveDefinition(ChildDefinition $definition): Definition { if (!$this->container->has($parent = $definition->getParent())) { throw new RuntimeException(sprintf('Parent definition "%s" does not exist.', $parent)); @@ -102,9 +101,6 @@ private function doResolveDefinition(ChildDefinition $definition) $def->setArguments($parentDef->getArguments()); $def->setMethodCalls($parentDef->getMethodCalls()); $def->setProperties($parentDef->getProperties()); - if ($parentDef->getAutowiringTypes(false)) { - $def->setAutowiringTypes($parentDef->getAutowiringTypes(false)); - } if ($parentDef->isDeprecated()) { $def->setDeprecated(true, $parentDef->getDeprecationMessage('%service_id%')); } @@ -118,6 +114,8 @@ private function doResolveDefinition(ChildDefinition $definition) $def->setBindings($definition->getBindings() + $parentDef->getBindings()); + $def->setSynthetic($definition->isSynthetic()); + // overwrite with values specified in the decorator $changes = $definition->getChanges(); if (isset($changes['class'])) { @@ -154,7 +152,7 @@ private function doResolveDefinition(ChildDefinition $definition) if (null === $decoratedService) { $def->setDecoratedService($decoratedService); } else { - $def->setDecoratedService($decoratedService[0], $decoratedService[1], $decoratedService[2]); + $def->setDecoratedService($decoratedService[0], $decoratedService[1], $decoratedService[2], $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE); } } @@ -162,7 +160,7 @@ private function doResolveDefinition(ChildDefinition $definition) foreach ($definition->getArguments() as $k => $v) { if (is_numeric($k)) { $def->addArgument($v); - } elseif (0 === strpos($k, 'index_')) { + } elseif (str_starts_with($k, 'index_')) { $def->replaceArgument((int) substr($k, \strlen('index_')), $v); } else { $def->setArgument($k, $v); @@ -179,10 +177,8 @@ private function doResolveDefinition(ChildDefinition $definition) $def->setMethodCalls(array_merge($def->getMethodCalls(), $calls)); } - // merge autowiring types - foreach ($definition->getAutowiringTypes(false) as $autowiringType) { - $def->addAutowiringType($autowiringType); - } + $def->addError($parentDef); + $def->addError($definition); // these attributes are always taken from the child $def->setAbstract($definition->isAbstract()); @@ -194,5 +190,3 @@ private function doResolveDefinition(ChildDefinition $definition) return $def; } } - -class_alias(ResolveChildDefinitionsPass::class, ResolveDefinitionTemplatesPass::class); diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php index b1c1b4f8..e67a2a8e 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveClassPass.php @@ -20,8 +20,6 @@ */ class ResolveClassPass implements CompilerPassInterface { - private $changes = []; - /** * {@inheritdoc} */ @@ -33,24 +31,10 @@ public function process(ContainerBuilder $container) } if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $id)) { if ($definition instanceof ChildDefinition && !class_exists($id)) { - throw new InvalidArgumentException(sprintf('Service definition "%s" has a parent but no class, and its name looks like a FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.', $id)); + throw new InvalidArgumentException(sprintf('Service definition "%s" has a parent but no class, and its name looks like an FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.', $id)); } - $this->changes[strtolower($id)] = $id; $definition->setClass($id); } } } - - /** - * @internal - * - * @deprecated since 3.3, to be removed in 4.0. - */ - public function getChanges() - { - $changes = $this->changes; - $this->changes = []; - - return $changes; - } } diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveDefinitionTemplatesPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveDefinitionTemplatesPass.php deleted file mode 100644 index 79fca8d5..00000000 --- a/vendor/symfony/dependency-injection/Compiler/ResolveDefinitionTemplatesPass.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Compiler; - -@trigger_error('The '.__NAMESPACE__.'\ResolveDefinitionTemplatesPass class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the ResolveChildDefinitionsPass class instead.', \E_USER_DEPRECATED); - -class_exists(ResolveChildDefinitionsPass::class); - -if (false) { - /** - * This definition decorates another definition. - * - * @author Johannes M. Schmitt - * - * @deprecated The ResolveDefinitionTemplatesPass class is deprecated since version 3.4 and will be removed in 4.0. Use the ResolveChildDefinitionsPass class instead. - */ - class ResolveDefinitionTemplatesPass extends AbstractRecursivePass - { - } -} diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php index 4e025113..bfdd91c4 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveHotPathPass.php @@ -26,7 +26,7 @@ class ResolveHotPathPass extends AbstractRecursivePass private $tagName; private $resolvedIds = []; - public function __construct($tagName = 'container.hot_path') + public function __construct(string $tagName = 'container.hot_path') { $this->tagName = $tagName; } @@ -55,7 +55,7 @@ protected function processValue($value, $isRoot = false) if ($value instanceof Definition && $isRoot && (isset($this->resolvedIds[$this->currentId]) || !$value->hasTag($this->tagName) || $value->isDeprecated())) { return $value->isDeprecated() ? $value->clearTag($this->tagName) : $value; } - if ($value instanceof Reference && ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior() && $this->container->has($id = $this->container->normalizeId($value))) { + if ($value instanceof Reference && ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE !== $value->getInvalidBehavior() && $this->container->has($id = (string) $value)) { $definition = $this->container->findDefinition($id); if (!$definition->hasTag($this->tagName) && !$definition->isDeprecated()) { $this->resolvedIds[$id] = true; diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php index 6268ed9e..37ad3495 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveInstanceofConditionalsPass.php @@ -33,9 +33,12 @@ public function process(ContainerBuilder $container) if ($definition->getArguments()) { throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines arguments but these are not supported and should be removed.', $interface)); } - if ($definition->getMethodCalls()) { - throw new InvalidArgumentException(sprintf('Autoconfigured instanceof for type "%s" defines method calls but these are not supported and should be removed.', $interface)); - } + } + + $tagsToKeep = []; + + if ($container->hasParameter('container.behavior_describing_tags')) { + $tagsToKeep = $container->getParameter('container.behavior_describing_tags'); } foreach ($container->getDefinitions() as $id => $definition) { @@ -43,11 +46,15 @@ public function process(ContainerBuilder $container) // don't apply "instanceof" to children: it will be applied to their parent continue; } - $container->setDefinition($id, $this->processDefinition($container, $id, $definition)); + $container->setDefinition($id, $this->processDefinition($container, $id, $definition, $tagsToKeep)); + } + + if ($container->hasParameter('container.behavior_describing_tags')) { + $container->getParameterBag()->remove('container.behavior_describing_tags'); } } - private function processDefinition(ContainerBuilder $container, $id, Definition $definition) + private function processDefinition(ContainerBuilder $container, string $id, Definition $definition, array $tagsToKeep): Definition { $instanceofConditionals = $definition->getInstanceofConditionals(); $autoconfiguredInstanceof = $definition->isAutoconfigured() ? $container->getAutoconfiguredInstanceof() : []; @@ -64,10 +71,12 @@ private function processDefinition(ContainerBuilder $container, $id, Definition $definition->setInstanceofConditionals([]); $parent = $shared = null; $instanceofTags = []; + $instanceofCalls = []; + $instanceofBindings = []; $reflectionClass = null; foreach ($conditionals as $interface => $instanceofDefs) { - if ($interface !== $class && !(null === $reflectionClass ? $reflectionClass = ($container->getReflectionClass($class, false) ?: false) : $reflectionClass)) { + if ($interface !== $class && !($reflectionClass ?? $reflectionClass = $container->getReflectionClass($class, false) ?: false)) { continue; } @@ -78,11 +87,19 @@ private function processDefinition(ContainerBuilder $container, $id, Definition foreach ($instanceofDefs as $key => $instanceofDef) { /** @var ChildDefinition $instanceofDef */ $instanceofDef = clone $instanceofDef; - $instanceofDef->setAbstract(true)->setParent($parent ?: 'abstract.instanceof.'.$id); - $parent = 'instanceof.'.$interface.'.'.$key.'.'.$id; + $instanceofDef->setAbstract(true)->setParent($parent ?: '.abstract.instanceof.'.$id); + $parent = '.instanceof.'.$interface.'.'.$key.'.'.$id; $container->setDefinition($parent, $instanceofDef); $instanceofTags[] = $instanceofDef->getTags(); + $instanceofBindings = $instanceofDef->getBindings() + $instanceofBindings; + + foreach ($instanceofDef->getMethodCalls() as $methodCall) { + $instanceofCalls[] = $methodCall; + } + $instanceofDef->setTags([]); + $instanceofDef->setMethodCalls([]); + $instanceofDef->setBindings([]); if (isset($instanceofDef->getChanges()['shared'])) { $shared = $instanceofDef->isShared(); @@ -92,13 +109,14 @@ private function processDefinition(ContainerBuilder $container, $id, Definition if ($parent) { $bindings = $definition->getBindings(); - $abstract = $container->setDefinition('abstract.instanceof.'.$id, $definition); + $abstract = $container->setDefinition('.abstract.instanceof.'.$id, $definition); // cast Definition to ChildDefinition $definition->setBindings([]); $definition = serialize($definition); $definition = substr_replace($definition, '53', 2, 2); $definition = substr_replace($definition, 'Child', 44, 0); + /** @var ChildDefinition $definition */ $definition = unserialize($definition); $definition->setParent($parent); @@ -106,19 +124,23 @@ private function processDefinition(ContainerBuilder $container, $id, Definition $definition->setShared($shared); } + // Don't add tags to service decorators $i = \count($instanceofTags); while (0 <= --$i) { foreach ($instanceofTags[$i] as $k => $v) { - foreach ($v as $v) { - if ($definition->hasTag($k) && \in_array($v, $definition->getTag($k))) { - continue; + if (null === $definition->getDecoratedService() || \in_array($k, $tagsToKeep, true)) { + foreach ($v as $v) { + if ($definition->hasTag($k) && \in_array($v, $definition->getTag($k))) { + continue; + } + $definition->addTag($k, $v); } - $definition->addTag($k, $v); } } } - $definition->setBindings($bindings); + $definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls())); + $definition->setBindings($bindings + $instanceofBindings); // reset fields with "merge" behavior $abstract @@ -133,7 +155,7 @@ private function processDefinition(ContainerBuilder $container, $id, Definition return $definition; } - private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container) + private function mergeConditionals(array $autoconfiguredInstanceof, array $instanceofConditionals, ContainerBuilder $container): array { // make each value an array of ChildDefinition $conditionals = array_map(function ($childDef) { return [$childDef]; }, $autoconfiguredInstanceof); diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php index f1a1475a..948de421 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php @@ -17,7 +17,9 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\TypedReference; /** * Emulates the invalid behavior if the reference is not found within the @@ -29,6 +31,7 @@ class ResolveInvalidReferencesPass implements CompilerPassInterface { private $container; private $signalingException; + private $currentId; /** * Process the ContainerBuilder to resolve invalid references. @@ -39,7 +42,9 @@ public function process(ContainerBuilder $container) $this->signalingException = new RuntimeException('Invalid reference.'); try { - $this->processValue($container->getDefinitions(), 1); + foreach ($container->getDefinitions() as $this->currentId => $definition) { + $this->processValue($definition); + } } finally { $this->container = $this->signalingException = null; } @@ -48,9 +53,11 @@ public function process(ContainerBuilder $container) /** * Processes arguments to determine invalid references. * + * @return mixed + * * @throws RuntimeException When an invalid reference is found */ - private function processValue($value, $rootLevel = 0, $level = 0) + private function processValue($value, int $rootLevel = 0, int $level = 0) { if ($value instanceof ServiceClosureArgument) { $value->setValues($this->processValue($value->getValues(), 1, 1)); @@ -90,11 +97,29 @@ private function processValue($value, $rootLevel = 0, $level = 0) $value = array_values($value); } } elseif ($value instanceof Reference) { - if ($this->container->has($value)) { + if ($this->container->has($id = (string) $value)) { return $value; } + + $currentDefinition = $this->container->getDefinition($this->currentId); + + // resolve decorated service behavior depending on decorator service + if ($currentDefinition->innerServiceId === $id && ContainerInterface::NULL_ON_INVALID_REFERENCE === $currentDefinition->decorationOnInvalid) { + return null; + } + $invalidBehavior = $value->getInvalidBehavior(); + if (ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior && $value instanceof TypedReference && !$this->container->has($id)) { + $e = new ServiceNotFoundException($id, $this->currentId); + + // since the error message varies by $id and $this->currentId, so should the id of the dummy errored definition + $this->container->register($id = sprintf('.errored.%s.%s', $this->currentId, $id), $value->getType()) + ->addError($e->getMessage()); + + return new TypedReference($id, $value->getType(), $value->getInvalidBehavior()); + } + // resolve invalid behavior if (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) { $value = null; diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php index 225014f1..ab8ac1d0 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveNamedArgumentsPass.php @@ -36,7 +36,7 @@ protected function processValue($value, $isRoot = false) $calls[] = ['__construct', $value->getArguments()]; foreach ($calls as $i => $call) { - list($method, $arguments) = $call; + [$method, $arguments] = $call; $parameters = null; $resolvedArguments = []; @@ -53,10 +53,20 @@ protected function processValue($value, $isRoot = false) $parameters = $r->getParameters(); } + if (isset($key[0]) && '$' !== $key[0] && !class_exists($key) && !interface_exists($key, false)) { + throw new InvalidArgumentException(sprintf('Invalid service "%s": did you forget to add the "$" prefix to argument "%s"?', $this->currentId, $key)); + } + if (isset($key[0]) && '$' === $key[0]) { foreach ($parameters as $j => $p) { if ($key === '$'.$p->name) { - $resolvedArguments[$j] = $argument; + if ($p->isVariadic() && \is_array($argument)) { + foreach ($argument as $variadicArgument) { + $resolvedArguments[$j++] = $variadicArgument; + } + } else { + $resolvedArguments[$j] = $argument; + } continue 2; } @@ -88,7 +98,7 @@ protected function processValue($value, $isRoot = false) } } - list(, $arguments) = array_pop($calls); + [, $arguments] = array_pop($calls); if ($arguments !== $value->getArguments()) { $value->setArguments($arguments); diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php index 2559dcf1..7764dde9 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php @@ -30,7 +30,9 @@ public function process(ContainerBuilder $container) parent::process($container); foreach ($container->getAliases() as $id => $alias) { - $aliasId = $container->normalizeId($alias); + $aliasId = (string) $alias; + $this->currentId = $id; + if ($aliasId !== $defId = $this->getDefinitionId($aliasId, $container)) { $container->setAlias($id, $defId)->setPublic($alias->isPublic())->setPrivate($alias->isPrivate()); } @@ -42,34 +44,39 @@ public function process(ContainerBuilder $container) */ protected function processValue($value, $isRoot = false) { - if ($value instanceof Reference) { - $defId = $this->getDefinitionId($id = $this->container->normalizeId($value), $this->container); - - if ($defId !== $id) { - return new Reference($defId, $value->getInvalidBehavior()); - } + if (!$value instanceof Reference) { + return parent::processValue($value, $isRoot); } - return parent::processValue($value); + $defId = $this->getDefinitionId($id = (string) $value, $this->container); + + return $defId !== $id ? new Reference($defId, $value->getInvalidBehavior()) : $value; } - /** - * Resolves an alias into a definition id. - * - * @param string $id The definition or alias id to resolve - * - * @return string The definition id with aliases resolved - */ - private function getDefinitionId($id, ContainerBuilder $container) + private function getDefinitionId(string $id, ContainerBuilder $container): string { + if (!$container->hasAlias($id)) { + return $id; + } + + $alias = $container->getAlias($id); + + if ($alias->isDeprecated()) { + $referencingDefinition = $container->hasDefinition($this->currentId) ? $container->getDefinition($this->currentId) : $container->getAlias($this->currentId); + if (!$referencingDefinition->isDeprecated()) { + @trigger_error(sprintf('%s. It is being referenced by the "%s" %s.', rtrim($alias->getDeprecationMessage($id), '. '), $this->currentId, $container->hasDefinition($this->currentId) ? 'service' : 'alias'), \E_USER_DEPRECATED); + } + } + $seen = []; - while ($container->hasAlias($id)) { + do { if (isset($seen[$id])) { throw new ServiceCircularReferenceException($id, array_merge(array_keys($seen), [$id])); } + $seen[$id] = true; - $id = $container->normalizeId($container->getAlias($id)); - } + $id = (string) $container->getAlias($id); + } while ($container->hasAlias($id)); return $id; } diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveServiceSubscribersPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveServiceSubscribersPass.php index ccc80a44..399f3490 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveServiceSubscribersPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveServiceSubscribersPass.php @@ -14,6 +14,7 @@ use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Contracts\Service\ServiceProviderInterface; /** * Compiler pass to inject their service locator to service subscribers. @@ -26,7 +27,7 @@ class ResolveServiceSubscribersPass extends AbstractRecursivePass protected function processValue($value, $isRoot = false) { - if ($value instanceof Reference && $this->serviceLocator && ContainerInterface::class === $this->container->normalizeId($value)) { + if ($value instanceof Reference && $this->serviceLocator && \in_array((string) $value, [ContainerInterface::class, ServiceProviderInterface::class], true)) { return new Reference($this->serviceLocator); } diff --git a/vendor/symfony/dependency-injection/Compiler/ResolveTaggedIteratorArgumentPass.php b/vendor/symfony/dependency-injection/Compiler/ResolveTaggedIteratorArgumentPass.php index 009cee9b..a4305722 100644 --- a/vendor/symfony/dependency-injection/Compiler/ResolveTaggedIteratorArgumentPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ResolveTaggedIteratorArgumentPass.php @@ -31,7 +31,7 @@ protected function processValue($value, $isRoot = false) return parent::processValue($value, $isRoot); } - $value->setValues($this->findAndSortTaggedServices($value->getTag(), $this->container)); + $value->setValues($this->findAndSortTaggedServices($value, $this->container)); return $value; } diff --git a/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php b/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php index a7427c5a..5fdbe568 100644 --- a/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php +++ b/vendor/symfony/dependency-injection/Compiler/ServiceLocatorTagPass.php @@ -13,6 +13,7 @@ use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; @@ -26,8 +27,18 @@ */ final class ServiceLocatorTagPass extends AbstractRecursivePass { + use PriorityTaggedServiceTrait; + protected function processValue($value, $isRoot = false) { + if ($value instanceof ServiceLocatorArgument) { + if ($value->getTaggedIteratorArgument()) { + $value->setValues($this->findAndSortTaggedServices($value->getTaggedIteratorArgument(), $this->container)); + } + + return self::register($this->container, $value->getValues()); + } + if (!$value instanceof Definition || !$value->hasTag('container.service_locator')) { return parent::processValue($value, $isRoot); } @@ -65,7 +76,7 @@ protected function processValue($value, $isRoot = false) $value->setArguments($arguments); - $id = 'service_locator.'.ContainerBuilder::hash($value); + $id = '.service_locator.'.ContainerBuilder::hash($value); if ($isRoot) { if ($id !== $this->currentId) { @@ -82,11 +93,8 @@ protected function processValue($value, $isRoot = false) /** * @param Reference[] $refMap - * @param string|null $callerId - * - * @return Reference */ - public static function register(ContainerBuilder $container, array $refMap, $callerId = null) + public static function register(ContainerBuilder $container, array $refMap, string $callerId = null): Reference { foreach ($refMap as $id => $ref) { if (!$ref instanceof Reference) { @@ -105,7 +113,7 @@ public static function register(ContainerBuilder $container, array $refMap, $cal $locator->setBindings($container->getDefinition($callerId)->getBindings()); } - if (!$container->hasDefinition($id = 'service_locator.'.ContainerBuilder::hash($locator))) { + if (!$container->hasDefinition($id = '.service_locator.'.ContainerBuilder::hash($locator))) { $container->setDefinition($id, $locator); } @@ -117,6 +125,7 @@ public static function register(ContainerBuilder $container, array $refMap, $cal $container->register($id .= '.'.$callerId, ServiceLocator::class) ->setPublic(false) ->setFactory([new Reference($locatorId), 'withContext']) + ->addTag('container.service_locator_context', ['id' => $callerId]) ->addArgument($callerId) ->addArgument(new Reference('service_container')); } diff --git a/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php b/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php index e419e297..308abc65 100644 --- a/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php +++ b/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php @@ -21,7 +21,7 @@ * * @author Johannes M. Schmitt * - * @final since version 3.4 + * @final */ class ServiceReferenceGraph { @@ -30,14 +30,7 @@ class ServiceReferenceGraph */ private $nodes = []; - /** - * Checks if the graph has a specific node. - * - * @param string $id Id to check - * - * @return bool - */ - public function hasNode($id) + public function hasNode(string $id): bool { return isset($this->nodes[$id]); } @@ -45,13 +38,9 @@ public function hasNode($id) /** * Gets a node by identifier. * - * @param string $id The id to retrieve - * - * @return ServiceReferenceGraphNode - * * @throws InvalidArgumentException if no node matches the supplied identifier */ - public function getNode($id) + public function getNode(string $id): ServiceReferenceGraphNode { if (!isset($this->nodes[$id])) { throw new InvalidArgumentException(sprintf('There is no node with id "%s".', $id)); @@ -65,7 +54,7 @@ public function getNode($id) * * @return ServiceReferenceGraphNode[] */ - public function getNodes() + public function getNodes(): array { return $this->nodes; } @@ -83,19 +72,9 @@ public function clear() /** * Connects 2 nodes together in the Graph. - * - * @param string $sourceId - * @param mixed $sourceValue - * @param string $destId - * @param mixed $destValue - * @param string $reference */ - public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null/*, bool $lazy = false, bool $weak = false, bool $byConstructor = false*/) + public function connect(?string $sourceId, $sourceValue, ?string $destId, $destValue = null, $reference = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false) { - $lazy = \func_num_args() >= 6 ? func_get_arg(5) : false; - $weak = \func_num_args() >= 7 ? func_get_arg(6) : false; - $byConstructor = \func_num_args() >= 8 ? func_get_arg(7) : false; - if (null === $sourceId || null === $destId) { return; } @@ -108,15 +87,7 @@ public function connect($sourceId, $sourceValue, $destId, $destValue = null, $re $destNode->addInEdge($edge); } - /** - * Creates a graph node. - * - * @param string $id - * @param mixed $value - * - * @return ServiceReferenceGraphNode - */ - private function createNode($id, $value) + private function createNode(string $id, $value): ServiceReferenceGraphNode { if (isset($this->nodes[$id]) && $this->nodes[$id]->getValue() === $value) { return $this->nodes[$id]; diff --git a/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php b/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php index 911e7a5f..98614560 100644 --- a/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php +++ b/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php @@ -27,13 +27,7 @@ class ServiceReferenceGraphEdge private $weak; private $byConstructor; - /** - * @param mixed $value - * @param bool $lazy - * @param bool $weak - * @param bool $byConstructor - */ - public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, $lazy = false, $weak = false, $byConstructor = false) + public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null, bool $lazy = false, bool $weak = false, bool $byConstructor = false) { $this->sourceNode = $sourceNode; $this->destNode = $destNode; @@ -46,7 +40,7 @@ public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceRefere /** * Returns the value of the edge. * - * @return string + * @return mixed */ public function getValue() { diff --git a/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php b/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php index 50140b5f..fec14242 100644 --- a/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php +++ b/vendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php @@ -32,7 +32,7 @@ class ServiceReferenceGraphNode * @param string $id The node identifier * @param mixed $value The node value */ - public function __construct($id, $value) + public function __construct(string $id, $value) { $this->id = $id; $this->value = $value; diff --git a/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.php b/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.php new file mode 100644 index 00000000..cae01c61 --- /dev/null +++ b/vendor/symfony/dependency-injection/Compiler/ValidateEnvPlaceholdersPass.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Compiler; + +use Symfony\Component\Config\Definition\BaseNode; +use Symfony\Component\Config\Definition\Exception\TreeWithoutRootNodeException; +use Symfony\Component\Config\Definition\Processor; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface; +use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; +use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; + +/** + * Validates environment variable placeholders used in extension configuration with dummy values. + * + * @author Roland Franssen + */ +class ValidateEnvPlaceholdersPass implements CompilerPassInterface +{ + private const TYPE_FIXTURES = ['array' => [], 'bool' => false, 'float' => 0.0, 'int' => 0, 'string' => '']; + + private $extensionConfig = []; + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $this->extensionConfig = []; + + if (!class_exists(BaseNode::class) || !$extensions = $container->getExtensions()) { + return; + } + + $resolvingBag = $container->getParameterBag(); + if (!$resolvingBag instanceof EnvPlaceholderParameterBag) { + return; + } + + $defaultBag = new ParameterBag($resolvingBag->all()); + $envTypes = $resolvingBag->getProvidedTypes(); + try { + foreach ($resolvingBag->getEnvPlaceholders() + $resolvingBag->getUnusedEnvPlaceholders() as $env => $placeholders) { + $values = []; + if (false === $i = strpos($env, ':')) { + $default = $defaultBag->has("env($env)") ? $defaultBag->get("env($env)") : self::TYPE_FIXTURES['string']; + $defaultType = null !== $default ? self::getType($default) : 'string'; + $values[$defaultType] = $default; + } else { + $prefix = substr($env, 0, $i); + foreach ($envTypes[$prefix] ?? ['string'] as $type) { + $values[$type] = self::TYPE_FIXTURES[$type] ?? null; + } + } + foreach ($placeholders as $placeholder) { + BaseNode::setPlaceholder($placeholder, $values); + } + } + + $processor = new Processor(); + + foreach ($extensions as $name => $extension) { + if (!$extension instanceof ConfigurationExtensionInterface || !$config = array_filter($container->getExtensionConfig($name))) { + // this extension has no semantic configuration or was not called + continue; + } + + $config = $resolvingBag->resolveValue($config); + + if (null === $configuration = $extension->getConfiguration($config, $container)) { + continue; + } + + try { + $this->extensionConfig[$name] = $processor->processConfiguration($configuration, $config); + } catch (TreeWithoutRootNodeException $e) { + } + } + } finally { + BaseNode::resetPlaceholders(); + } + + $resolvingBag->clearUnusedEnvPlaceholders(); + } + + /** + * @internal + */ + public function getExtensionConfig(): array + { + try { + return $this->extensionConfig; + } finally { + $this->extensionConfig = []; + } + } + + private static function getType($value): string + { + switch ($type = \gettype($value)) { + case 'boolean': + return 'bool'; + case 'double': + return 'float'; + case 'integer': + return 'int'; + } + + return $type; + } +} diff --git a/vendor/symfony/dependency-injection/Config/AutowireServiceResource.php b/vendor/symfony/dependency-injection/Config/AutowireServiceResource.php deleted file mode 100644 index 68c1e3f6..00000000 --- a/vendor/symfony/dependency-injection/Config/AutowireServiceResource.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Config; - -@trigger_error('The '.__NAMESPACE__.'\AutowireServiceResource class is deprecated since Symfony 3.3 and will be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead.', \E_USER_DEPRECATED); - -use Symfony\Component\Config\Resource\SelfCheckingResourceInterface; -use Symfony\Component\DependencyInjection\Compiler\AutowirePass; - -/** - * @deprecated since version 3.3, to be removed in 4.0. Use ContainerBuilder::getReflectionClass() instead. - */ -class AutowireServiceResource implements SelfCheckingResourceInterface, \Serializable -{ - private $class; - private $filePath; - private $autowiringMetadata = []; - - public function __construct($class, $path, array $autowiringMetadata) - { - $this->class = $class; - $this->filePath = $path; - $this->autowiringMetadata = $autowiringMetadata; - } - - public function isFresh($timestamp) - { - if (!file_exists($this->filePath)) { - return false; - } - - // has the file *not* been modified? Definitely fresh - if (@filemtime($this->filePath) <= $timestamp) { - return true; - } - - try { - $reflectionClass = new \ReflectionClass($this->class); - } catch (\ReflectionException $e) { - // the class does not exist anymore! - return false; - } - - return (array) $this === (array) AutowirePass::createResourceForClass($reflectionClass); - } - - public function __toString() - { - return 'service.autowire.'.$this->class; - } - - /** - * @internal - */ - public function serialize() - { - return serialize([$this->class, $this->filePath, $this->autowiringMetadata]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - if (\PHP_VERSION_ID >= 70000) { - list($this->class, $this->filePath, $this->autowiringMetadata) = unserialize($serialized, ['allowed_classes' => false]); - } else { - list($this->class, $this->filePath, $this->autowiringMetadata) = unserialize($serialized); - } - } - - /** - * @deprecated Implemented for compatibility with Symfony 2.8 - */ - public function getResource() - { - return $this->filePath; - } -} diff --git a/vendor/symfony/dependency-injection/Config/ContainerParametersResource.php b/vendor/symfony/dependency-injection/Config/ContainerParametersResource.php index 7560c335..d2a74eb5 100644 --- a/vendor/symfony/dependency-injection/Config/ContainerParametersResource.php +++ b/vendor/symfony/dependency-injection/Config/ContainerParametersResource.php @@ -17,8 +17,10 @@ * Tracks container parameters. * * @author Maxime Steinhausser + * + * @final since Symfony 4.3 */ -class ContainerParametersResource implements ResourceInterface, \Serializable +class ContainerParametersResource implements ResourceInterface { private $parameters; @@ -30,30 +32,11 @@ public function __construct(array $parameters) $this->parameters = $parameters; } - /** - * {@inheritdoc} - */ public function __toString() { return 'container_parameters_'.md5(serialize($this->parameters)); } - /** - * @internal - */ - public function serialize() - { - return serialize($this->parameters); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - $this->parameters = unserialize($serialized); - } - /** * @return array Tracked parameters */ diff --git a/vendor/symfony/dependency-injection/Container.php b/vendor/symfony/dependency-injection/Container.php index e9d53023..789c8f72 100644 --- a/vendor/symfony/dependency-injection/Container.php +++ b/vendor/symfony/dependency-injection/Container.php @@ -11,14 +11,22 @@ namespace Symfony\Component\DependencyInjection; +use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocator as ArgumentServiceLocator; use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; +use Symfony\Contracts\Service\ResetInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(RewindableGenerator::class); +class_exists(ArgumentServiceLocator::class); /** * Container is a dependency injection container. @@ -41,31 +49,22 @@ class Container implements ResettableContainerInterface { protected $parameterBag; protected $services = []; + protected $privates = []; protected $fileMap = []; protected $methodMap = []; + protected $factories = []; protected $aliases = []; protected $loading = []; protected $resolving = []; protected $syntheticIds = []; - /** - * @internal - */ - protected $privates = []; - - /** - * @internal - */ - protected $normalizedIds = []; - - private $underscoreMap = ['_' => '', '.' => '_', '\\' => '_']; private $envCache = []; private $compiled = false; private $getEnv; public function __construct(ParameterBagInterface $parameterBag = null) { - $this->parameterBag = $parameterBag ?: new EnvPlaceholderParameterBag(); + $this->parameterBag = $parameterBag ?? new EnvPlaceholderParameterBag(); } /** @@ -95,20 +94,6 @@ public function isCompiled() return $this->compiled; } - /** - * Returns true if the container parameter bag are frozen. - * - * @deprecated since version 3.3, to be removed in 4.0. - * - * @return bool true if the container parameter bag are frozen, false otherwise - */ - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), \E_USER_DEPRECATED); - - return $this->parameterBag instanceof FrozenParameterBag; - } - /** * Gets the service container parameter bag. * @@ -124,7 +109,7 @@ public function getParameterBag() * * @param string $name The parameter name * - * @return mixed The parameter value + * @return array|bool|string|int|float|null * * @throws InvalidArgumentException if the parameter is not defined */ @@ -148,8 +133,8 @@ public function hasParameter($name) /** * Sets a parameter. * - * @param string $name The parameter name - * @param mixed $value The parameter value + * @param string $name The parameter name + * @param array|bool|string|int|float|null $value The parameter value */ public function setParameter($name, $value) { @@ -174,27 +159,20 @@ public function set($id, $service) $initialize(); } - $id = $this->normalizeId($id); - if ('service_container' === $id) { throw new InvalidArgumentException('You cannot set service "service_container".'); } - if (isset($this->privates[$id]) || !(isset($this->fileMap[$id]) || isset($this->methodMap[$id]))) { - if (!isset($this->privates[$id]) && !isset($this->getRemovedIds()[$id])) { + if (!(isset($this->fileMap[$id]) || isset($this->methodMap[$id]))) { + if (isset($this->syntheticIds[$id]) || !isset($this->getRemovedIds()[$id])) { // no-op } elseif (null === $service) { - @trigger_error(sprintf('The "%s" service is private, unsetting it is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED); - unset($this->privates[$id]); + throw new InvalidArgumentException(sprintf('The "%s" service is private, you cannot unset it.', $id)); } else { - @trigger_error(sprintf('The "%s" service is private, replacing it is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED); + throw new InvalidArgumentException(sprintf('The "%s" service is private, you cannot replace it.', $id)); } } elseif (isset($this->services[$id])) { - if (null === $service) { - @trigger_error(sprintf('The "%s" service is already initialized, unsetting it is deprecated since Symfony 3.3 and will fail in 4.0.', $id), \E_USER_DEPRECATED); - } else { - @trigger_error(sprintf('The "%s" service is already initialized, replacing it is deprecated since Symfony 3.3 and will fail in 4.0.', $id), \E_USER_DEPRECATED); - } + throw new InvalidArgumentException(sprintf('The "%s" service is already initialized, you cannot replace it.', $id)); } if (isset($this->aliases[$id])) { @@ -219,47 +197,22 @@ public function set($id, $service) */ public function has($id) { - for ($i = 2;;) { - if (isset($this->privates[$id])) { - @trigger_error(sprintf('The "%s" service is private, checking for its existence is deprecated since Symfony 3.2 and will fail in 4.0.', $id), \E_USER_DEPRECATED); - } - if (isset($this->aliases[$id])) { - $id = $this->aliases[$id]; - } - if (isset($this->services[$id])) { - return true; - } - if ('service_container' === $id) { - return true; - } - - if (isset($this->fileMap[$id]) || isset($this->methodMap[$id])) { - return true; - } - - if (--$i && $id !== $normalizedId = $this->normalizeId($id)) { - $id = $normalizedId; - continue; - } - - // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder, - // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper) - if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, 'get'.strtr($id, $this->underscoreMap).'Service')) { - @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED); - - return true; - } - - return false; + if (isset($this->aliases[$id])) { + $id = $this->aliases[$id]; + } + if (isset($this->services[$id])) { + return true; } + if ('service_container' === $id) { + return true; + } + + return isset($this->fileMap[$id]) || isset($this->methodMap[$id]); } /** * Gets a service. * - * If a service is defined both through a set() method and - * with a get{$id}Service() method, the former has always precedence. - * * @param string $id The service identifier * @param int $invalidBehavior The behavior when the service does not exist * @@ -273,57 +226,42 @@ public function has($id) */ public function get($id, $invalidBehavior = /* self::EXCEPTION_ON_INVALID_REFERENCE */ 1) { - // Attempt to retrieve the service by checking first aliases then - // available services. Service IDs are case insensitive, however since - // this method can be called thousands of times during a request, avoid - // calling $this->normalizeId($id) unless necessary. - for ($i = 2;;) { - if (isset($this->privates[$id])) { - @trigger_error(sprintf('The "%s" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead.', $id), \E_USER_DEPRECATED); - } - if (isset($this->aliases[$id])) { - $id = $this->aliases[$id]; - } + $service = $this->services[$id] + ?? $this->services[$id = $this->aliases[$id] ?? $id] + ?? ('service_container' === $id ? $this : ($this->factories[$id] ?? [$this, 'make'])($id, $invalidBehavior)); - // Re-use shared service instance if it exists. - if (isset($this->services[$id])) { - return $this->services[$id]; - } - if ('service_container' === $id) { - return $this; - } - - if (isset($this->loading[$id])) { - throw new ServiceCircularReferenceException($id, array_merge(array_keys($this->loading), [$id])); - } - - $this->loading[$id] = true; + if (!\is_object($service) && null !== $service) { + @trigger_error(sprintf('Non-object services are deprecated since Symfony 4.4, please fix the "%s" service which is of type "%s" right now.', $id, \gettype($service)), \E_USER_DEPRECATED); + } - try { - if (isset($this->fileMap[$id])) { - return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->load($this->fileMap[$id]); - } elseif (isset($this->methodMap[$id])) { - return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->{$this->methodMap[$id]}(); - } elseif (--$i && $id !== $normalizedId = $this->normalizeId($id)) { - unset($this->loading[$id]); - $id = $normalizedId; - continue; - } elseif (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class && method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) { - // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder, - // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper) - @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED); + return $service; + } - return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->{$method}(); - } + /** + * Creates a service. + * + * As a separate method to allow "get()" to use the really fast `??` operator. + */ + private function make(string $id, int $invalidBehavior) + { + if (isset($this->loading[$id])) { + throw new ServiceCircularReferenceException($id, array_merge(array_keys($this->loading), [$id])); + } - break; - } catch (\Exception $e) { - unset($this->services[$id]); + $this->loading[$id] = true; - throw $e; - } finally { - unset($this->loading[$id]); + try { + if (isset($this->fileMap[$id])) { + return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->load($this->fileMap[$id]); + } elseif (isset($this->methodMap[$id])) { + return /* self::IGNORE_ON_UNINITIALIZED_REFERENCE */ 4 === $invalidBehavior ? null : $this->{$this->methodMap[$id]}(); } + } catch (\Exception $e) { + unset($this->services[$id]); + + throw $e; + } finally { + unset($this->loading[$id]); } if (/* self::EXCEPTION_ON_INVALID_REFERENCE */ 1 === $invalidBehavior) { @@ -339,14 +277,19 @@ public function get($id, $invalidBehavior = /* self::EXCEPTION_ON_INVALID_REFERE $alternatives = []; foreach ($this->getServiceIds() as $knownId) { + if ('' === $knownId || '.' === $knownId[0]) { + continue; + } $lev = levenshtein($id, $knownId); - if ($lev <= \strlen($id) / 3 || false !== strpos($knownId, $id)) { + if ($lev <= \strlen($id) / 3 || str_contains($knownId, $id)) { $alternatives[] = $knownId; } } throw new ServiceNotFoundException($id, null, null, $alternatives); } + + return null; } /** @@ -358,12 +301,6 @@ public function get($id, $invalidBehavior = /* self::EXCEPTION_ON_INVALID_REFERE */ public function initialized($id) { - $id = $this->normalizeId($id); - - if (isset($this->privates[$id])) { - @trigger_error(sprintf('Checking for the initialization of the "%s" private service is deprecated since Symfony 3.4 and won\'t be supported anymore in Symfony 4.0.', $id), \E_USER_DEPRECATED); - } - if (isset($this->aliases[$id])) { $id = $this->aliases[$id]; } @@ -380,7 +317,18 @@ public function initialized($id) */ public function reset() { - $this->services = []; + $services = $this->services + $this->privates; + $this->services = $this->factories = $this->privates = []; + + foreach ($services as $service) { + try { + if ($service instanceof ResetInterface) { + $service->reset(); + } + } catch (\Throwable $e) { + continue; + } + } } /** @@ -390,22 +338,7 @@ public function reset() */ public function getServiceIds() { - $ids = []; - - if (!$this->methodMap && !$this instanceof ContainerBuilder && __CLASS__ !== static::class) { - // We only check the convention-based factory in a compiled container (i.e. a child class other than a ContainerBuilder, - // and only when the dumper has not generated the method map (otherwise the method map is considered to be fully populated by the dumper) - @trigger_error('Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map.', \E_USER_DEPRECATED); - - foreach (get_class_methods($this) as $method) { - if (preg_match('/^get(.+)Service$/', $method, $match)) { - $ids[] = self::underscore($match[1]); - } - } - } - $ids[] = 'service_container'; - - return array_map('strval', array_unique(array_merge($ids, array_keys($this->methodMap), array_keys($this->fileMap), array_keys($this->aliases), array_keys($this->services)))); + return array_map('strval', array_unique(array_merge(['service_container'], array_keys($this->fileMap), array_keys($this->methodMap), array_keys($this->aliases), array_keys($this->services)))); } /** @@ -471,9 +404,7 @@ protected function getEnv($name) $this->set($id, new ServiceLocator([])); } if (!$this->getEnv) { - $this->getEnv = new \ReflectionMethod($this, __FUNCTION__); - $this->getEnv->setAccessible(true); - $this->getEnv = $this->getEnv->getClosure($this); + $this->getEnv = \Closure::fromCallable([$this, 'getEnv']); } $processors = $this->get($id); @@ -495,29 +426,32 @@ protected function getEnv($name) } /** - * Returns the case sensitive id used at registration time. - * - * @param string $id + * @param string|false $registry + * @param string|bool $load * - * @return string + * @return mixed * * @internal */ - public function normalizeId($id) + final protected function getService($registry, string $id, ?string $method, $load) { - if (!\is_string($id)) { - $id = (string) $id; + if ('service_container' === $id) { + return $this; } - if (isset($this->normalizedIds[$normalizedId = strtolower($id)])) { - $normalizedId = $this->normalizedIds[$normalizedId]; - if ($id !== $normalizedId) { - @trigger_error(sprintf('Service identifiers will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.3.', $id, $normalizedId), \E_USER_DEPRECATED); - } - } else { - $normalizedId = $this->normalizedIds[$normalizedId] = $id; + if (\is_string($load)) { + throw new RuntimeException($load); + } + if (null === $method) { + return false !== $registry ? $this->{$registry}[$id] ?? null : null; + } + if (false !== $registry) { + return $this->{$registry}[$id] ?? $this->{$registry}[$id] = $load ? $this->load($method) : $this->{$method}(); + } + if (!$load) { + return $this->{$method}(); } - return $normalizedId; + return ($factory = $this->factories[$id] ?? $this->factories['service_container'][$id] ?? null) ? $factory() : $this->load($method); } private function __clone() diff --git a/vendor/symfony/dependency-injection/ContainerBuilder.php b/vendor/symfony/dependency-injection/ContainerBuilder.php index 97617cb0..f97a5740 100644 --- a/vendor/symfony/dependency-injection/ContainerBuilder.php +++ b/vendor/symfony/dependency-injection/ContainerBuilder.php @@ -23,6 +23,8 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Compiler\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PassConfig; @@ -39,7 +41,6 @@ use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; -use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface; @@ -125,7 +126,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface private $removedBindingIds = []; - private static $internalTypes = [ + private const INTERNAL_TYPES = [ 'int' => true, 'float' => true, 'string' => true, @@ -143,7 +144,7 @@ public function __construct(ParameterBagInterface $parameterBag = null) { parent::__construct($parameterBag); - $this->trackResources = interface_exists('Symfony\Component\Config\Resource\ResourceInterface'); + $this->trackResources = interface_exists(ResourceInterface::class); $this->setDefinition('service_container', (new Definition(ContainerInterface::class))->setSynthetic(true)->setPublic(true)); $this->setAlias(PsrContainerInterface::class, new Alias('service_container', false)); $this->setAlias(ContainerInterface::class, new Alias('service_container', false)); @@ -325,39 +326,20 @@ public function addObjectResource($object) return $this; } - /** - * Adds the given class hierarchy as resources. - * - * @return $this - * - * @deprecated since version 3.3, to be removed in 4.0. Use addObjectResource() or getReflectionClass() instead. - */ - public function addClassResource(\ReflectionClass $class) - { - @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the addObjectResource() or the getReflectionClass() method instead.', \E_USER_DEPRECATED); - - return $this->addObjectResource($class->name); - } - /** * Retrieves the requested reflection class and registers it for resource tracking. * - * @param string $class - * @param bool $throw - * - * @return \ReflectionClass|null - * * @throws \ReflectionException when a parent class/interface/trait is not found and $throw is true * * @final */ - public function getReflectionClass($class, $throw = true) + public function getReflectionClass(?string $class, bool $throw = true): ?\ReflectionClass { if (!$class = $this->getParameterBag()->resolveValue($class)) { return null; } - if (isset(self::$internalTypes[$class])) { + if (isset(self::INTERNAL_TYPES[$class])) { return null; } @@ -380,7 +362,7 @@ public function getReflectionClass($class, $throw = true) if ($this->trackResources) { if (!$classReflector) { - $this->addResource($resource ?: new ClassExistenceResource($class, false)); + $this->addResource($resource ?? new ClassExistenceResource($class, false)); } elseif (!$classReflector->isInternal()) { $path = $classReflector->getFileName(); @@ -401,11 +383,9 @@ public function getReflectionClass($class, $throw = true) * @param bool|string $trackContents Whether to track contents of the given resource. If a string is passed, * it will be used as pattern for tracking contents of the requested directory * - * @return bool - * * @final */ - public function fileExists($path, $trackContents = true) + public function fileExists(string $path, $trackContents = true): bool { $exists = file_exists($path); @@ -463,27 +443,13 @@ public function loadFromExtension($extension, array $values = null) /** * Adds a compiler pass. * - * @param CompilerPassInterface $pass A compiler pass - * @param string $type The type of compiler pass - * @param int $priority Used to sort the passes + * @param string $type The type of compiler pass + * @param int $priority Used to sort the passes * * @return $this */ - public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, int $priority = 0*/) + public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0) { - if (\func_num_args() >= 3) { - $priority = func_get_arg(2); - } else { - if (__CLASS__ !== static::class) { - $r = new \ReflectionMethod($this, __FUNCTION__); - if (__CLASS__ !== $r->getDeclaringClass()->getName()) { - @trigger_error(sprintf('Method %s() will have a third `int $priority = 0` argument in version 4.0. Not defining it is deprecated since Symfony 3.2.', __METHOD__), \E_USER_DEPRECATED); - } - } - - $priority = 0; - } - $this->getCompiler()->addPass($pass, $type, $priority); $this->addObjectResource($pass); @@ -525,7 +491,11 @@ public function getCompiler() */ public function set($id, $service) { - $id = $this->normalizeId($id); + if (!\is_object($service) && null !== $service) { + @trigger_error(sprintf('Non-object services are deprecated since Symfony 4.4, setting the "%s" service to a value of type "%s" should be avoided.', $id, \gettype($service)), \E_USER_DEPRECATED); + } + + $id = (string) $id; if ($this->isCompiled() && (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())) { // setting a synthetic service on a compiled container is alright @@ -544,7 +514,7 @@ public function set($id, $service) */ public function removeDefinition($id) { - if (isset($this->definitions[$id = $this->normalizeId($id)])) { + if (isset($this->definitions[$id = (string) $id])) { unset($this->definitions[$id]); $this->removedIds[$id] = true; } @@ -559,7 +529,7 @@ public function removeDefinition($id) */ public function has($id) { - $id = $this->normalizeId($id); + $id = (string) $id; return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id); } @@ -581,17 +551,21 @@ public function has($id) */ public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { - if ($this->isCompiled() && isset($this->removedIds[$id = $this->normalizeId($id)])) { - @trigger_error(sprintf('Fetching the "%s" private service or alias is deprecated since Symfony 3.4 and will fail in 4.0. Make it public instead.', $id), \E_USER_DEPRECATED); + if ($this->isCompiled() && isset($this->removedIds[$id = (string) $id]) && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $invalidBehavior) { + return parent::get($id); + } + + $service = $this->doGet($id, $invalidBehavior); + + if (!\is_object($service) && null !== $service) { + @trigger_error(sprintf('Non-object services are deprecated since Symfony 4.4, please fix the "%s" service which is of type "%s" right now.', $id, \gettype($service)), \E_USER_DEPRECATED); } - return $this->doGet($id, $invalidBehavior); + return $service; } - private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, $isConstructorArgument = false) + private function doGet(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, array &$inlineServices = null, bool $isConstructorArgument = false) { - $id = $this->normalizeId($id); - if (isset($inlineServices[$id])) { return $inlineServices[$id]; } @@ -613,19 +587,29 @@ private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_ } if (!isset($this->definitions[$id]) && isset($this->aliasDefinitions[$id])) { - return $this->doGet((string) $this->aliasDefinitions[$id], $invalidBehavior, $inlineServices, $isConstructorArgument); + $alias = $this->aliasDefinitions[$id]; + + if ($alias->isDeprecated()) { + @trigger_error($alias->getDeprecationMessage($id), \E_USER_DEPRECATED); + } + + return $this->doGet((string) $alias, $invalidBehavior, $inlineServices, $isConstructorArgument); } try { $definition = $this->getDefinition($id); } catch (ServiceNotFoundException $e) { - if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { + if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $invalidBehavior) { return null; } throw $e; } + if ($definition->hasErrors() && $e = $definition->getErrors()) { + throw new RuntimeException(reset($e)); + } + if ($isConstructorArgument) { $this->loading[$id] = true; } @@ -760,19 +744,8 @@ public function prependExtensionConfig($name, array $config) * Set to "true" when you want to use the current ContainerBuilder * directly, keep to "false" when the container is dumped instead. */ - public function compile(/*$resolveEnvPlaceholders = false*/) + public function compile(bool $resolveEnvPlaceholders = false) { - if (1 <= \func_num_args()) { - $resolveEnvPlaceholders = func_get_arg(0); - } else { - if (__CLASS__ !== static::class) { - $r = new \ReflectionMethod($this, __FUNCTION__); - if (__CLASS__ !== $r->getDeclaringClass()->getName() && (1 > $r->getNumberOfParameters() || 'resolveEnvPlaceholders' !== $r->getParameters()[0]->name)) { - @trigger_error(sprintf('The %s::compile() method expects a first "$resolveEnvPlaceholders" argument since Symfony 3.3. It will be made mandatory in 4.0.', static::class), \E_USER_DEPRECATED); - } - } - $resolveEnvPlaceholders = false; - } $compiler = $this->getCompiler(); if ($this->trackResources) { @@ -863,14 +836,14 @@ public function setAliases(array $aliases) */ public function setAlias($alias, $id) { - $alias = $this->normalizeId($alias); + $alias = (string) $alias; - if ('' === $alias || '\\' === substr($alias, -1) || \strlen($alias) !== strcspn($alias, "\0\r\n'")) { + if ('' === $alias || '\\' === $alias[-1] || \strlen($alias) !== strcspn($alias, "\0\r\n'")) { throw new InvalidArgumentException(sprintf('Invalid alias id: "%s".', $alias)); } if (\is_string($id)) { - $id = new Alias($this->normalizeId($id)); + $id = new Alias($id); } elseif (!$id instanceof Alias) { throw new InvalidArgumentException('$id must be a string, or an Alias object.'); } @@ -891,7 +864,7 @@ public function setAlias($alias, $id) */ public function removeAlias($alias) { - if (isset($this->aliasDefinitions[$alias = $this->normalizeId($alias)])) { + if (isset($this->aliasDefinitions[$alias = (string) $alias])) { unset($this->aliasDefinitions[$alias]); $this->removedIds[$alias] = true; } @@ -906,12 +879,10 @@ public function removeAlias($alias) */ public function hasAlias($id) { - return isset($this->aliasDefinitions[$this->normalizeId($id)]); + return isset($this->aliasDefinitions[$id = (string) $id]); } /** - * Gets all defined aliases. - * * @return Alias[] An array of aliases */ public function getAliases() @@ -930,7 +901,7 @@ public function getAliases() */ public function getAlias($id) { - $id = $this->normalizeId($id); + $id = (string) $id; if (!isset($this->aliasDefinitions[$id])) { throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id)); @@ -1007,8 +978,7 @@ public function getDefinitions() /** * Sets a service definition. * - * @param string $id The service identifier - * @param Definition $definition A Definition instance + * @param string $id The service identifier * * @return Definition the service definition * @@ -1020,9 +990,9 @@ public function setDefinition($id, Definition $definition) throw new BadMethodCallException('Adding definition to a compiled container is not allowed.'); } - $id = $this->normalizeId($id); + $id = (string) $id; - if ('' === $id || '\\' === substr($id, -1) || \strlen($id) !== strcspn($id, "\0\r\n'")) { + if ('' === $id || '\\' === $id[-1] || \strlen($id) !== strcspn($id, "\0\r\n'")) { throw new InvalidArgumentException(sprintf('Invalid service id: "%s".', $id)); } @@ -1040,7 +1010,7 @@ public function setDefinition($id, Definition $definition) */ public function hasDefinition($id) { - return isset($this->definitions[$this->normalizeId($id)]); + return isset($this->definitions[(string) $id]); } /** @@ -1054,7 +1024,7 @@ public function hasDefinition($id) */ public function getDefinition($id) { - $id = $this->normalizeId($id); + $id = (string) $id; if (!isset($this->definitions[$id])) { throw new ServiceNotFoundException($id); @@ -1076,7 +1046,7 @@ public function getDefinition($id) */ public function findDefinition($id) { - $id = $this->normalizeId($id); + $id = (string) $id; $seen = []; while (isset($this->aliasDefinitions[$id])) { @@ -1099,17 +1069,13 @@ public function findDefinition($id) /** * Creates a service for a service definition. * - * @param Definition $definition A service definition instance - * @param string $id The service identifier - * @param bool $tryProxy Whether to try proxying the service with a lazy proxy - * * @return mixed The service described by the service definition * * @throws RuntimeException When the factory definition is incomplete * @throws RuntimeException When the service is a synthetic service * @throws InvalidArgumentException When configure callable is not callable */ - private function createService(Definition $definition, array &$inlineServices, $isConstructorArgument = false, $id = null, $tryProxy = true) + private function createService(Definition $definition, array &$inlineServices, bool $isConstructorArgument = false, string $id = null, bool $tryProxy = true) { if (null === $id && isset($inlineServices[$h = spl_object_hash($definition)])) { return $inlineServices[$h]; @@ -1161,7 +1127,7 @@ private function createService(Definition $definition, array &$inlineServices, $ } if (null !== $factory) { - $service = \call_user_func_array($factory, $arguments); + $service = $factory(...$arguments); if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) { $r = new \ReflectionClass($factory[0]); @@ -1171,20 +1137,24 @@ private function createService(Definition $definition, array &$inlineServices, $ } } } else { - $r = new \ReflectionClass($class = $parameterBag->resolveValue($definition->getClass())); + $r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass())); $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs(array_values($arguments)); - // don't trigger deprecations for internal uses - // @deprecated since version 3.3, to be removed in 4.0 along with the deprecated class - $deprecationAllowlist = ['event_dispatcher' => ContainerAwareEventDispatcher::class]; - if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationAllowlist[$id]) || $deprecationAllowlist[$id] !== $class)) { + if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) { @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), \E_USER_DEPRECATED); } } - if ($tryProxy || !$definition->isLazy()) { - // share only if proxying failed, or if not a proxy + $lastWitherIndex = null; + foreach ($definition->getMethodCalls() as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + + if (null === $lastWitherIndex && ($tryProxy || !$definition->isLazy())) { + // share only if proxying failed, or if not a proxy, and if no withers are found $this->shareService($definition, $service, $id, $inlineServices); } @@ -1193,8 +1163,13 @@ private function createService(Definition $definition, array &$inlineServices, $ $service->$name = $value; } - foreach ($definition->getMethodCalls() as $call) { - $this->callMethod($service, $call, $inlineServices); + foreach ($definition->getMethodCalls() as $k => $call) { + $service = $this->callMethod($service, $call, $inlineServices); + + if ($lastWitherIndex === $k && ($tryProxy || !$definition->isLazy())) { + // share only if proxying failed, or if not a proxy, and this is the last wither + $this->shareService($definition, $service, $id, $inlineServices); + } } if ($callable = $definition->getConfigurator()) { @@ -1212,7 +1187,7 @@ private function createService(Definition $definition, array &$inlineServices, $ throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', \get_class($service))); } - \call_user_func($callable, $service); + $callable($service); } return $service; @@ -1231,7 +1206,7 @@ public function resolveServices($value) return $this->doResolveServices($value); } - private function doResolveServices($value, array &$inlineServices = [], $isConstructorArgument = false) + private function doResolveServices($value, array &$inlineServices = [], bool $isConstructorArgument = false) { if (\is_array($value)) { foreach ($value as $k => $v) { @@ -1243,7 +1218,7 @@ private function doResolveServices($value, array &$inlineServices = [], $isConst return $this->resolveServices($reference); }; } elseif ($value instanceof IteratorArgument) { - $value = new RewindableGenerator(function () use ($value) { + $value = new RewindableGenerator(function () use ($value, &$inlineServices) { foreach ($value->getValues() as $k => $v) { foreach (self::getServiceConditionals($v) as $s) { if (!$this->has($s)) { @@ -1251,14 +1226,14 @@ private function doResolveServices($value, array &$inlineServices = [], $isConst } } foreach (self::getInitializedConditionals($v) as $s) { - if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)) { + if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) { continue 2; } } - yield $k => $this->resolveServices($v); + yield $k => $this->doResolveServices($v, $inlineServices); } - }, function () use ($value) { + }, function () use ($value): int { $count = 0; foreach ($value->getValues() as $v) { foreach (self::getServiceConditionals($v) as $s) { @@ -1277,6 +1252,15 @@ private function doResolveServices($value, array &$inlineServices = [], $isConst return $count; }); + } elseif ($value instanceof ServiceLocatorArgument) { + $refs = $types = []; + foreach ($value->getValues() as $k => $v) { + if ($v) { + $refs[$k] = [$v]; + $types[$k] = $v instanceof TypedReference ? $v->getType() : '?'; + } + } + $value = new ServiceLocator(\Closure::fromCallable([$this, 'resolveServices']), $refs, $types); } elseif ($value instanceof Reference) { $value = $this->doGet((string) $value, $value->getInvalidBehavior(), $inlineServices, $isConstructorArgument); } elseif ($value instanceof Definition) { @@ -1379,6 +1363,25 @@ public function registerForAutoconfiguration($interface) return $this->autoconfiguredInstanceof[$interface]; } + /** + * Registers an autowiring alias that only binds to a specific argument name. + * + * The argument name is derived from $name if provided (from $id otherwise) + * using camel case: "foo.bar" or "foo_bar" creates an alias bound to + * "$fooBar"-named arguments with $type as type-hint. Such arguments will + * receive the service $id when autowiring is used. + */ + public function registerAliasForArgument(string $id, string $type, string $name = null): Alias + { + $name = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $name ?? $id)))); + + if (!preg_match('/^[a-zA-Z_\x7f-\xff]/', $name)) { + throw new InvalidArgumentException(sprintf('Invalid argument name "%s" for service "%s": the first character must be a letter.', $name, $id)); + } + + return $this->setAlias($type.' $'.$name, $id); + } + /** * Returns an array of ChildDefinition[] keyed by interface. * @@ -1411,6 +1414,10 @@ public function resolveEnvPlaceholders($value, $format = null, array &$usedEnvs $value = $bag->resolveValue($value); } + if ($value instanceof Definition) { + $value = (array) $value; + } + if (\is_array($value)) { $result = []; foreach ($value as $k => $v) { @@ -1475,50 +1482,20 @@ public function getEnvCounters() return $this->envCounters; } - /** - * @internal - */ - public function getNormalizedIds() - { - $normalizedIds = []; - - foreach ($this->normalizedIds as $k => $v) { - if ($v !== (string) $k) { - $normalizedIds[$k] = $v; - } - } - - return $normalizedIds; - } - /** * @final */ - public function log(CompilerPassInterface $pass, $message) + public function log(CompilerPassInterface $pass, string $message) { $this->getCompiler()->log($pass, $this->resolveEnvPlaceholders($message)); } - /** - * {@inheritdoc} - */ - public function normalizeId($id) - { - if (!\is_string($id)) { - $id = (string) $id; - } - - return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || isset($this->removedIds[$id]) ? $id : parent::normalizeId($id); - } - /** * Gets removed binding ids. * - * @return array - * * @internal */ - public function getRemovedBindingIds() + public function getRemovedBindingIds(): array { return $this->removedBindingIds; } @@ -1526,15 +1503,13 @@ public function getRemovedBindingIds() /** * Removes bindings for a service. * - * @param string $id The service identifier - * * @internal */ - public function removeBindings($id) + public function removeBindings(string $id) { if ($this->hasDefinition($id)) { foreach ($this->getDefinition($id)->getBindings() as $key => $binding) { - list(, $bindingId) = $binding->getValues(); + [, $bindingId] = $binding->getValues(); $this->removedBindingIds[(int) $bindingId] = true; } } @@ -1545,11 +1520,9 @@ public function removeBindings($id) * * @param mixed $value An array of conditionals to return * - * @return array An array of Service conditionals - * - * @internal since version 3.4 + * @internal */ - public static function getServiceConditionals($value) + public static function getServiceConditionals($value): array { $services = []; @@ -1569,11 +1542,9 @@ public static function getServiceConditionals($value) * * @param mixed $value An array of conditionals to return * - * @return array An array of uninitialized conditionals - * * @internal */ - public static function getInitializedConditionals($value) + public static function getInitializedConditionals($value): array { $services = []; @@ -1599,7 +1570,7 @@ public static function hash($value) { $hash = substr(base64_encode(hash('sha256', serialize($value), true)), 0, 7); - return str_replace(['/', '+'], ['.', '_'], strtolower($hash)); + return str_replace(['/', '+'], ['.', '_'], $hash); } /** @@ -1614,11 +1585,15 @@ protected function getEnv($name) return $value; } - foreach ($bag->getEnvPlaceholders() as $env => $placeholders) { - if (isset($placeholders[$value])) { - $bag = new ParameterBag($bag->all()); + $envPlaceholders = $bag->getEnvPlaceholders(); + if (isset($envPlaceholders[$name][$value])) { + $bag = new ParameterBag($bag->all()); - return $bag->unescapeValue($bag->get("env($name)")); + return $bag->unescapeValue($bag->get("env($name)")); + } + foreach ($envPlaceholders as $env => $placeholders) { + if (isset($placeholders[$value])) { + return $this->getEnv($env); } } @@ -1630,31 +1605,32 @@ protected function getEnv($name) } } - private function callMethod($service, $call, array &$inlineServices) + private function callMethod($service, array $call, array &$inlineServices) { foreach (self::getServiceConditionals($call[1]) as $s) { if (!$this->has($s)) { - return; + return $service; } } foreach (self::getInitializedConditionals($call[1]) as $s) { if (!$this->doGet($s, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE, $inlineServices)) { - return; + return $service; } } - \call_user_func_array([$service, $call[0]], $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices)); + $result = $service->{$call[0]}(...$this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlineServices)); + + return empty($call[2]) ? $service : $result; } /** * Shares a given service in the container. * - * @param mixed $service - * @param string|null $id + * @param mixed $service */ - private function shareService(Definition $definition, $service, $id, array &$inlineServices) + private function shareService(Definition $definition, $service, ?string $id, array &$inlineServices) { - $inlineServices[null !== $id ? $id : spl_object_hash($definition)] = $service; + $inlineServices[$id ?? spl_object_hash($definition)] = $service; if (null !== $id && $definition->isShared()) { $this->services[$id] = $service; @@ -1662,11 +1638,11 @@ private function shareService(Definition $definition, $service, $id, array &$inl } } - private function getExpressionLanguage() + private function getExpressionLanguage(): ExpressionLanguage { if (null === $this->expressionLanguage) { - if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { - throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); + if (!class_exists(\Symfony\Component\ExpressionLanguage\ExpressionLanguage::class)) { + throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); } $this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders); } @@ -1674,17 +1650,17 @@ private function getExpressionLanguage() return $this->expressionLanguage; } - private function inVendors($path) + private function inVendors(string $path): bool { if (null === $this->vendors) { - $resource = new ComposerResource(); - $this->vendors = $resource->getVendors(); - $this->addResource($resource); + $this->vendors = (new ComposerResource())->getVendors(); } $path = realpath($path) ?: $path; foreach ($this->vendors as $vendor) { - if (0 === strpos($path, $vendor) && false !== strpbrk(substr($path, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) { + if (str_starts_with($path, $vendor) && false !== strpbrk(substr($path, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) { + $this->addResource(new FileResource($vendor.'/composer/installed.json')); + return true; } } diff --git a/vendor/symfony/dependency-injection/ContainerInterface.php b/vendor/symfony/dependency-injection/ContainerInterface.php index c5ab4c2e..a3acbbde 100644 --- a/vendor/symfony/dependency-injection/ContainerInterface.php +++ b/vendor/symfony/dependency-injection/ContainerInterface.php @@ -24,10 +24,11 @@ */ interface ContainerInterface extends PsrContainerInterface { - const EXCEPTION_ON_INVALID_REFERENCE = 1; - const NULL_ON_INVALID_REFERENCE = 2; - const IGNORE_ON_INVALID_REFERENCE = 3; - const IGNORE_ON_UNINITIALIZED_REFERENCE = 4; + public const RUNTIME_EXCEPTION_ON_INVALID_REFERENCE = 0; + public const EXCEPTION_ON_INVALID_REFERENCE = 1; + public const NULL_ON_INVALID_REFERENCE = 2; + public const IGNORE_ON_INVALID_REFERENCE = 3; + public const IGNORE_ON_UNINITIALIZED_REFERENCE = 4; /** * Sets a service. @@ -53,8 +54,6 @@ public function set($id, $service); public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE); /** - * Returns true if the given service is defined. - * * @param string $id The service identifier * * @return bool true if the service is defined, false otherwise @@ -75,7 +74,7 @@ public function initialized($id); * * @param string $name The parameter name * - * @return mixed The parameter value + * @return array|bool|string|int|float|null * * @throws InvalidArgumentException if the parameter is not defined */ @@ -93,8 +92,8 @@ public function hasParameter($name); /** * Sets a parameter. * - * @param string $name The parameter name - * @param mixed $value The parameter value + * @param string $name The parameter name + * @param array|bool|string|int|float|null $value The parameter value */ public function setParameter($name, $value); } diff --git a/vendor/symfony/dependency-injection/Definition.php b/vendor/symfony/dependency-injection/Definition.php index c3a94f5c..34ddbbbd 100644 --- a/vendor/symfony/dependency-injection/Definition.php +++ b/vendor/symfony/dependency-injection/Definition.php @@ -22,6 +22,8 @@ */ class Definition { + private const DEFAULT_DEPRECATION_TEMPLATE = 'The "%service_id%" service is deprecated. You should stop using it, as it will be removed in the future.'; + private $class; private $file; private $factory; @@ -41,14 +43,25 @@ class Definition private $lazy = false; private $decoratedService; private $autowired = false; - private $autowiringTypes = []; private $changes = []; private $bindings = []; private $errors = []; protected $arguments = []; - private static $defaultDeprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.'; + /** + * @internal + * + * Used to store the name of the inner id when using service decoration together with autowiring + */ + public $innerServiceId; + + /** + * @internal + * + * Used to store the behavior to follow when using service decoration and the decorated service is invalid + */ + public $decorationOnInvalid; /** * @param string|null $class The service class @@ -89,7 +102,7 @@ public function setChanges(array $changes) /** * Sets a factory. * - * @param string|array $factory A PHP function or an array containing a class/Reference and a method to call + * @param string|array|Reference|null $factory A PHP function, reference or an array containing a class/Reference and a method to call * * @return $this */ @@ -97,8 +110,10 @@ public function setFactory($factory) { $this->changes['factory'] = true; - if (\is_string($factory) && false !== strpos($factory, '::')) { + if (\is_string($factory) && str_contains($factory, '::')) { $factory = explode('::', $factory, 2); + } elseif ($factory instanceof Reference) { + $factory = [$factory, '__invoke']; } $this->factory = $factory; @@ -119,26 +134,33 @@ public function getFactory() /** * Sets the service that this service is decorating. * - * @param string|null $id The decorated service id, use null to remove decoration - * @param string|null $renamedId The new decorated service id - * @param int $priority The priority of decoration + * @param string|null $id The decorated service id, use null to remove decoration + * @param string|null $renamedId The new decorated service id + * @param int $priority The priority of decoration + * @param int $invalidBehavior The behavior to adopt when decorated is invalid * * @return $this * * @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals */ - public function setDecoratedService($id, $renamedId = null, $priority = 0) + public function setDecoratedService($id, $renamedId = null, $priority = 0/*, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE*/) { if ($renamedId && $id === $renamedId) { throw new InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id)); } + $invalidBehavior = 3 < \func_num_args() ? (int) func_get_arg(3) : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + $this->changes['decorated_service'] = true; if (null === $id) { $this->decoratedService = null; } else { $this->decoratedService = [$id, $renamedId, (int) $priority]; + + if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) { + $this->decoratedService[] = $invalidBehavior; + } } return $this; @@ -163,6 +185,13 @@ public function getDecoratedService() */ public function setClass($class) { + if ($class instanceof Parameter) { + @trigger_error(sprintf('Passing an instance of %s as class name to %s in deprecated in Symfony 4.4 and will result in a TypeError in 5.0. Please pass the string "%%%s%%" instead.', Parameter::class, __CLASS__, (string) $class), \E_USER_DEPRECATED); + } + if (null !== $class && !\is_string($class)) { + @trigger_error(sprintf('The class name passed to %s is expected to be a string. Passing a %s is deprecated in Symfony 4.4 and will result in a TypeError in 5.0.', __CLASS__, \is_object($class) ? \get_class($class) : \gettype($class)), \E_USER_DEPRECATED); + } + $this->changes['class'] = true; $this->class = $class; @@ -324,7 +353,7 @@ public function setMethodCalls(array $calls = []) { $this->calls = []; foreach ($calls as $call) { - $this->addMethodCall($call[0], $call[1]); + $this->addMethodCall($call[0], $call[1], $call[2] ?? false); } return $this; @@ -333,19 +362,20 @@ public function setMethodCalls(array $calls = []) /** * Adds a method to call after service initialization. * - * @param string $method The method name to call - * @param array $arguments An array of arguments to pass to the method call + * @param string $method The method name to call + * @param array $arguments An array of arguments to pass to the method call + * @param bool $returnsClone Whether the call returns the service instance or not * * @return $this * * @throws InvalidArgumentException on empty $method param */ - public function addMethodCall($method, array $arguments = []) + public function addMethodCall($method, array $arguments = []/*, bool $returnsClone = false*/) { if (empty($method)) { throw new InvalidArgumentException('Method name cannot be empty.'); } - $this->calls[] = [$method, $arguments]; + $this->calls[] = 2 < \func_num_args() && func_get_arg(2) ? [$method, $arguments, true] : [$method, $arguments]; return $this; } @@ -362,7 +392,6 @@ public function removeMethodCall($method) foreach ($this->calls as $i => $call) { if ($call[0] === $method) { unset($this->calls[$i]); - break; } } @@ -476,7 +505,7 @@ public function getTags() */ public function getTag($name) { - return isset($this->tags[$name]) ? $this->tags[$name] : []; + return $this->tags[$name] ?? []; } /** @@ -736,7 +765,7 @@ public function setDeprecated($status = true, $template = null) throw new InvalidArgumentException('Invalid characters found in deprecation template.'); } - if (false === strpos($template, '%service_id%')) { + if (!str_contains($template, '%service_id%')) { throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.'); } @@ -770,13 +799,13 @@ public function isDeprecated() */ public function getDeprecationMessage($id) { - return str_replace('%service_id%', $id, $this->deprecationTemplate ?: self::$defaultDeprecationTemplate); + return str_replace('%service_id%', $id, $this->deprecationTemplate ?: self::DEFAULT_DEPRECATION_TEMPLATE); } /** * Sets a configurator to call after the service is fully initialized. * - * @param string|array $configurator A PHP callable + * @param string|array|Reference|null $configurator A PHP function, reference or an array containing a class/Reference and a method to call * * @return $this */ @@ -784,8 +813,10 @@ public function setConfigurator($configurator) { $this->changes['configurator'] = true; - if (\is_string($configurator) && false !== strpos($configurator, '::')) { + if (\is_string($configurator) && str_contains($configurator, '::')) { $configurator = explode('::', $configurator, 2); + } elseif ($configurator instanceof Reference) { + $configurator = [$configurator, '__invoke']; } $this->configurator = $configurator; @@ -803,28 +834,6 @@ public function getConfigurator() return $this->configurator; } - /** - * Sets types that will default to this definition. - * - * @param string[] $types - * - * @return $this - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function setAutowiringTypes(array $types) - { - @trigger_error('Autowiring-types are deprecated since Symfony 3.3 and will be removed in 4.0. Use aliases instead.', \E_USER_DEPRECATED); - - $this->autowiringTypes = []; - - foreach ($types as $type) { - $this->autowiringTypes[$type] = true; - } - - return $this; - } - /** * Is the definition autowired? * @@ -851,78 +860,10 @@ public function setAutowired($autowired) return $this; } - /** - * Gets autowiring types that will default to this definition. - * - * @return string[] - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function getAutowiringTypes(/*$triggerDeprecation = true*/) - { - if (1 > \func_num_args() || func_get_arg(0)) { - @trigger_error('Autowiring-types are deprecated since Symfony 3.3 and will be removed in 4.0. Use aliases instead.', \E_USER_DEPRECATED); - } - - return array_keys($this->autowiringTypes); - } - - /** - * Adds a type that will default to this definition. - * - * @param string $type - * - * @return $this - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function addAutowiringType($type) - { - @trigger_error(sprintf('Autowiring-types are deprecated since Symfony 3.3 and will be removed in 4.0. Use aliases instead for "%s".', $type), \E_USER_DEPRECATED); - - $this->autowiringTypes[$type] = true; - - return $this; - } - - /** - * Removes a type. - * - * @param string $type - * - * @return $this - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function removeAutowiringType($type) - { - @trigger_error(sprintf('Autowiring-types are deprecated since Symfony 3.3 and will be removed in 4.0. Use aliases instead for "%s".', $type), \E_USER_DEPRECATED); - - unset($this->autowiringTypes[$type]); - - return $this; - } - - /** - * Will this definition default for the given type? - * - * @param string $type - * - * @return bool - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function hasAutowiringType($type) - { - @trigger_error(sprintf('Autowiring-types are deprecated since Symfony 3.3 and will be removed in 4.0. Use aliases instead for "%s".', $type), \E_USER_DEPRECATED); - - return isset($this->autowiringTypes[$type]); - } - /** * Gets bindings. * - * @return array + * @return array|BoundArgument[] */ public function getBindings() { @@ -941,6 +882,10 @@ public function getBindings() public function setBindings(array $bindings) { foreach ($bindings as $key => $binding) { + if (0 < strpos($key, '$') && $key !== $k = preg_replace('/[ \t]*\$/', ' $', $key)) { + unset($bindings[$key]); + $bindings[$key = $k] = $binding; + } if (!$binding instanceof BoundArgument) { $bindings[$key] = new BoundArgument($binding); } @@ -954,11 +899,19 @@ public function setBindings(array $bindings) /** * Add an error that occurred when building this Definition. * - * @param string $error + * @param string|\Closure|self $error + * + * @return $this */ public function addError($error) { - $this->errors[] = $error; + if ($error instanceof self) { + $this->errors = array_merge($this->errors, $error->errors); + } else { + $this->errors[] = $error; + } + + return $this; } /** @@ -968,6 +921,19 @@ public function addError($error) */ public function getErrors() { + foreach ($this->errors as $i => $error) { + if ($error instanceof \Closure) { + $this->errors[$i] = (string) $error(); + } elseif (!\is_string($error)) { + $this->errors[$i] = (string) $error; + } + } + return $this->errors; } + + public function hasErrors(): bool + { + return (bool) $this->errors; + } } diff --git a/vendor/symfony/dependency-injection/DefinitionDecorator.php b/vendor/symfony/dependency-injection/DefinitionDecorator.php deleted file mode 100644 index 4753c2aa..00000000 --- a/vendor/symfony/dependency-injection/DefinitionDecorator.php +++ /dev/null @@ -1,29 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection; - -@trigger_error('The '.__NAMESPACE__.'\DefinitionDecorator class is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead.', \E_USER_DEPRECATED); - -class_exists(ChildDefinition::class); - -if (false) { - /** - * This definition decorates another definition. - * - * @author Johannes M. Schmitt - * - * @deprecated The DefinitionDecorator class is deprecated since version 3.3 and will be removed in 4.0. Use the Symfony\Component\DependencyInjection\ChildDefinition class instead. - */ - class DefinitionDecorator extends Definition - { - } -} diff --git a/vendor/symfony/dependency-injection/Dumper/GraphvizDumper.php b/vendor/symfony/dependency-injection/Dumper/GraphvizDumper.php index 0591e024..09836cd3 100644 --- a/vendor/symfony/dependency-injection/Dumper/GraphvizDumper.php +++ b/vendor/symfony/dependency-injection/Dumper/GraphvizDumper.php @@ -84,12 +84,7 @@ public function dump(array $options = []) return $this->container->resolveEnvPlaceholders($this->startDot().$this->addNodes().$this->addEdges().$this->endDot(), '__ENV_%s__'); } - /** - * Returns all nodes. - * - * @return string A string representation of all nodes - */ - private function addNodes() + private function addNodes(): string { $code = ''; foreach ($this->nodes as $id => $node) { @@ -101,12 +96,7 @@ private function addNodes() return $code; } - /** - * Returns all edges. - * - * @return string A string representation of all edges - */ - private function addEdges() + private function addEdges(): string { $code = ''; foreach ($this->edges as $id => $edges) { @@ -120,15 +110,8 @@ private function addEdges() /** * Finds all edges belonging to a specific service id. - * - * @param string $id The service id used to find edges - * @param array $arguments An array of arguments - * @param bool $required - * @param string $name - * - * @return array An array of edges */ - private function findEdges($id, array $arguments, $required, $name, $lazy = false) + private function findEdges(string $id, array $arguments, bool $required, string $name, bool $lazy = false): array { $edges = []; foreach ($arguments as $argument) { @@ -166,12 +149,7 @@ private function findEdges($id, array $arguments, $required, $name, $lazy = fals return $edges; } - /** - * Finds all nodes. - * - * @return array An array of all nodes - */ - private function findNodes() + private function findNodes(): array { $nodes = []; @@ -206,7 +184,7 @@ private function findNodes() return $nodes; } - private function cloneContainer() + private function cloneContainer(): ContainerBuilder { $parameterBag = new ParameterBag($this->container->getParameterBag()->all()); @@ -221,12 +199,7 @@ private function cloneContainer() return $container; } - /** - * Returns the start dot. - * - * @return string The string representation of a start dot - */ - private function startDot() + private function startDot(): string { return sprintf("digraph sc {\n %s\n node [%s];\n edge [%s];\n\n", $this->addOptions($this->options['graph']), @@ -235,24 +208,12 @@ private function startDot() ); } - /** - * Returns the end dot. - * - * @return string - */ - private function endDot() + private function endDot(): string { return "}\n"; } - /** - * Adds attributes. - * - * @param array $attributes An array of attributes - * - * @return string A comma separated list of attributes - */ - private function addAttributes(array $attributes) + private function addAttributes(array $attributes): string { $code = []; foreach ($attributes as $k => $v) { @@ -262,14 +223,7 @@ private function addAttributes(array $attributes) return $code ? ', '.implode(', ', $code) : ''; } - /** - * Adds options. - * - * @param array $options An array of options - * - * @return string A space separated list of options - */ - private function addOptions(array $options) + private function addOptions(array $options): string { $code = []; foreach ($options as $k => $v) { @@ -279,26 +233,12 @@ private function addOptions(array $options) return implode(' ', $code); } - /** - * Dotizes an identifier. - * - * @param string $id The identifier to dotize - * - * @return string A dotized string - */ - private function dotize($id) + private function dotize(string $id): string { - return strtolower(preg_replace('/\W/i', '_', $id)); + return preg_replace('/\W/i', '_', $id); } - /** - * Compiles an array of aliases for a specified service id. - * - * @param string $id A service id - * - * @return array An array of aliases - */ - private function getAliases($id) + private function getAliases(string $id): array { $aliases = []; foreach ($this->container->getAliases() as $alias => $origin) { diff --git a/vendor/symfony/dependency-injection/Dumper/PhpDumper.php b/vendor/symfony/dependency-injection/Dumper/PhpDumper.php index 8605d755..f76daf03 100644 --- a/vendor/symfony/dependency-injection/Dumper/PhpDumper.php +++ b/vendor/symfony/dependency-injection/Dumper/PhpDumper.php @@ -11,26 +11,35 @@ namespace Symfony\Component\DependencyInjection\Dumper; +use Composer\Autoload\ClassLoader; +use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocator; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass; +use Symfony\Component\DependencyInjection\Compiler\ServiceReferenceGraphNode; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\EnvParameterException; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\ExpressionLanguage; use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper; use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper; +use Symfony\Component\DependencyInjection\Loader\FileLoader; use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Component\DependencyInjection\Variable; +use Symfony\Component\ErrorHandler\DebugClassLoader; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\HttpKernel\Kernel; @@ -45,12 +54,12 @@ class PhpDumper extends Dumper /** * Characters that might appear in the generated variable name as first character. */ - const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz'; + public const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz'; /** * Characters that might appear in the generated variable name as any but the first character. */ - const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_'; + public const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_'; private $definitionVariables; private $referenceVariables; @@ -67,9 +76,18 @@ class PhpDumper extends Dumper private $namespace; private $asFiles; private $hotPathTag; + private $inlineFactories; private $inlineRequires; private $inlinedRequires = []; private $circularReferences = []; + private $singleUsePrivateIds = []; + private $preload = []; + private $addThrow = false; + private $addGetService = false; + private $locatedIds = []; + private $serviceLocatorTag; + private $exportedVariables = []; + private $baseClass; /** * @var ProxyDumper @@ -82,7 +100,7 @@ class PhpDumper extends Dumper public function __construct(ContainerBuilder $container) { if (!$container->isCompiled()) { - @trigger_error('Dumping an uncompiled ContainerBuilder is deprecated since Symfony 3.3 and will not be supported anymore in 4.0. Compile the container beforehand.', \E_USER_DEPRECATED); + throw new LogicException('Cannot dump an uncompiled container.'); } parent::__construct($container); @@ -112,8 +130,10 @@ public function setProxyDumper(ProxyDumper $proxyDumper) */ public function dump(array $options = []) { + $this->locatedIds = []; $this->targetDirRegex = null; $this->inlinedRequires = []; + $this->exportedVariables = []; $options = array_merge([ 'class' => 'ProjectServiceContainer', 'base_class' => 'Container', @@ -121,22 +141,28 @@ public function dump(array $options = []) 'as_files' => false, 'debug' => true, 'hot_path_tag' => 'container.hot_path', + 'inline_factories_parameter' => 'container.dumper.inline_factories', 'inline_class_loader_parameter' => 'container.dumper.inline_class_loader', + 'preload_classes' => [], + 'service_locator_tag' => 'container.service_locator', 'build_time' => time(), ], $options); + $this->addThrow = $this->addGetService = false; $this->namespace = $options['namespace']; $this->asFiles = $options['as_files']; $this->hotPathTag = $options['hot_path_tag']; + $this->inlineFactories = $this->asFiles && $options['inline_factories_parameter'] && $this->container->hasParameter($options['inline_factories_parameter']) && $this->container->getParameter($options['inline_factories_parameter']); $this->inlineRequires = $options['inline_class_loader_parameter'] && $this->container->hasParameter($options['inline_class_loader_parameter']) && $this->container->getParameter($options['inline_class_loader_parameter']); + $this->serviceLocatorTag = $options['service_locator_tag']; - if (0 !== strpos($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) { + if (!str_starts_with($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) { $baseClass = sprintf('%s\%s', $options['namespace'] ? '\\'.$options['namespace'] : '', $baseClass); - $baseClassWithNamespace = $baseClass; + $this->baseClass = $baseClass; } elseif ('Container' === $baseClass) { - $baseClassWithNamespace = Container::class; + $this->baseClass = Container::class; } else { - $baseClassWithNamespace = $baseClass; + $this->baseClass = $baseClass; } $this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass); @@ -154,20 +180,7 @@ public function dump(array $options = []) } } - (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container); - $checkedNodes = []; - $this->circularReferences = []; - foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { - if (!$node->getValue() instanceof Definition) { - continue; - } - if (!isset($checkedNodes[$id])) { - $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes); - } - } - $this->container->getCompiler()->getServiceReferenceGraph()->clear(); - $checkedNodes = []; - + $this->analyzeReferences(); $this->docStar = $options['debug'] ? '*' : ''; if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) { @@ -195,25 +208,49 @@ public function dump(array $options = []) } } + $proxyClasses = $this->inlineFactories ? $this->generateProxyClasses() : null; + + if ($options['preload_classes']) { + $this->preload = array_combine($options['preload_classes'], $options['preload_classes']); + } + $code = - $this->startClass($options['class'], $baseClass, $baseClassWithNamespace). - $this->addServices(). - $this->addDefaultParametersMethod(). - $this->endClass() + $this->startClass($options['class'], $baseClass). + $this->addServices($services). + $this->addDeprecatedAliases(). + $this->addDefaultParametersMethod() ; + $proxyClasses = $proxyClasses ?? $this->generateProxyClasses(); + + if ($this->addGetService) { + $code = preg_replace( + "/(\r?\n\r?\n public function __construct.+?\\{\r?\n)/s", + "\n private \$getService;$1 \$this->getService = \\Closure::fromCallable([\$this, 'getService']);\n", + $code, + 1 + ); + } + if ($this->asFiles) { $fileStart = <<container->getRemovedIds())) { + $ids = $this->container->getRemovedIds(); + foreach ($this->container->getDefinitions() as $id => $definition) { + if (!$definition->isPublic()) { + $ids[$id] = true; + } + } + if ($ids = array_keys($ids)) { sort($ids); $c = "generateServiceFiles() as $file => $c) { - $files[$file] = $fileStart.$c; + if (!$this->inlineFactories) { + foreach ($this->generateServiceFiles($services) as $file => $c) { + $files[$file] = $fileStart.$c; + } + foreach ($proxyClasses as $file => $c) { + $files[$file] = "generateProxyClasses() as $file => $c) { - $files[$file] = "endClass(); + + if ($this->inlineFactories) { + foreach ($proxyClasses as $c) { + $code .= $c; + } } + $files[$options['class'].'.php'] = $code; $hash = ucfirst(strtr(ContainerBuilder::hash($files), '._', 'xx')); $code = []; @@ -240,6 +288,45 @@ public function dump(array $options = []) $namespaceLine = $this->namespace ? "\nnamespace {$this->namespace};\n" : ''; $time = $options['build_time']; $id = hash('crc32', $hash.$time); + $this->asFiles = false; + + if ($this->preload && null !== $autoloadFile = $this->getAutoloadFile()) { + $autoloadFile = trim($this->export($autoloadFile), '()\\'); + + $code[$options['class'].'.preload.php'] = <<= 7.4 when preloading is desired + +use Symfony\Component\DependencyInjection\Dumper\Preloader; + +if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) { + return; +} + +require $autoloadFile; +require __DIR__.'/Container{$hash}/{$options['class']}.php'; + +\$classes = []; + +EOF; + + foreach ($this->preload as $class) { + if (!$class || str_contains($class, '$')) { + continue; + } + if (!(class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false)) || (new \ReflectionClass($class))->isUserDefined()) { + $code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class); + } + } + + $code[$options['class'].'.preload.php'] .= <<<'EOF' + +Preloader::preload($classes); + +EOF; + } $code[$options['class'].'.php'] = <<generateProxyClasses() as $c) { + $code .= $this->endClass(); + foreach ($proxyClasses as $c) { $code .= $c; } } @@ -274,6 +362,9 @@ public function dump(array $options = []) $this->targetDirRegex = null; $this->inlinedRequires = []; $this->circularReferences = []; + $this->locatedIds = []; + $this->exportedVariables = []; + $this->preload = []; $unusedEnvs = []; foreach ($this->container->getEnvCounters() as $env => $use) { @@ -290,10 +381,8 @@ public function dump(array $options = []) /** * Retrieves the currently set proxy dumper or instantiates one. - * - * @return ProxyDumper */ - private function getProxyDumper() + private function getProxyDumper(): ProxyDumper { if (!$this->proxyDumper) { $this->proxyDumper = new NullDumper(); @@ -302,58 +391,99 @@ private function getProxyDumper() return $this->proxyDumper; } - private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = [], $byConstructor = true) + private function analyzeReferences() { - $checkedNodes[$sourceId] = true; - $currentPath[$sourceId] = $byConstructor; - - foreach ($edges as $edge) { - $node = $edge->getDestNode(); - $id = $node->getId(); - - if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) { - // no-op - } elseif (isset($currentPath[$id])) { - $this->addCircularReferences($id, $currentPath, $edge->isReferencedByConstructor()); - } elseif (!isset($checkedNodes[$id])) { - $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath, $edge->isReferencedByConstructor()); - } elseif (isset($this->circularReferences[$id])) { - $this->connectCircularReferences($id, $currentPath, $edge->isReferencedByConstructor()); + (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container); + $checkedNodes = []; + $this->circularReferences = []; + $this->singleUsePrivateIds = []; + foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { + if (!$node->getValue() instanceof Definition) { + continue; } - } - unset($currentPath[$sourceId]); - } - private function connectCircularReferences($sourceId, &$currentPath, $byConstructor, &$subPath = []) - { - $currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor; - - foreach ($this->circularReferences[$sourceId] as $id => $byConstructor) { - if (isset($currentPath[$id])) { - $this->addCircularReferences($id, $currentPath, $byConstructor); - } elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) { - $this->connectCircularReferences($id, $currentPath, $byConstructor, $subPath); + if ($this->isSingleUsePrivateNode($node)) { + $this->singleUsePrivateIds[$id] = $id; } + + $this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes); } - unset($currentPath[$sourceId], $subPath[$sourceId]); + + $this->container->getCompiler()->getServiceReferenceGraph()->clear(); + $this->singleUsePrivateIds = array_diff_key($this->singleUsePrivateIds, $this->circularReferences); } - private function addCircularReferences($id, $currentPath, $byConstructor) + private function collectCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$loops = [], array $path = [], bool $byConstructor = true): void { - $currentPath[$id] = $byConstructor; - $circularRefs = []; + $path[$sourceId] = $byConstructor; + $checkedNodes[$sourceId] = true; + foreach ($edges as $edge) { + $node = $edge->getDestNode(); + $id = $node->getId(); + if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isLazy() || $edge->isWeak()) { + continue; + } - foreach (array_reverse($currentPath) as $parentId => $v) { - $byConstructor = $byConstructor && $v; - $circularRefs[] = $parentId; + if (isset($path[$id])) { + $loop = null; + $loopByConstructor = $edge->isReferencedByConstructor(); + $pathInLoop = [$id, []]; + foreach ($path as $k => $pathByConstructor) { + if (null !== $loop) { + $loop[] = $k; + $pathInLoop[1][$k] = $pathByConstructor; + $loops[$k][] = &$pathInLoop; + $loopByConstructor = $loopByConstructor && $pathByConstructor; + } elseif ($k === $id) { + $loop = []; + } + } + $this->addCircularReferences($id, $loop, $loopByConstructor); + } elseif (!isset($checkedNodes[$id])) { + $this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $loops, $path, $edge->isReferencedByConstructor()); + } elseif (isset($loops[$id])) { + // we already had detected loops for this edge + // let's check if we have a common ancestor in one of the detected loops + foreach ($loops[$id] as [$first, $loopPath]) { + if (!isset($path[$first])) { + continue; + } + // We have a common ancestor, let's fill the current path + $fillPath = null; + foreach ($loopPath as $k => $pathByConstructor) { + if (null !== $fillPath) { + $fillPath[$k] = $pathByConstructor; + } elseif ($k === $id) { + $fillPath = $path; + $fillPath[$k] = $pathByConstructor; + } + } - if ($parentId === $id) { - break; + // we can now build the loop + $loop = null; + $loopByConstructor = $edge->isReferencedByConstructor(); + foreach ($fillPath as $k => $pathByConstructor) { + if (null !== $loop) { + $loop[] = $k; + $loopByConstructor = $loopByConstructor && $pathByConstructor; + } elseif ($k === $first) { + $loop = []; + } + } + $this->addCircularReferences($first, $loop, true); + break; + } } } + unset($path[$sourceId]); + } - $currentId = $id; - foreach ($circularRefs as $parentId) { + private function addCircularReferences(string $sourceId, array $currentPath, bool $byConstructor) + { + $currentId = $sourceId; + $currentPath = array_reverse($currentPath); + $currentPath[] = $currentId; + foreach ($currentPath as $parentId) { if (empty($this->circularReferences[$parentId][$currentId])) { $this->circularReferences[$parentId][$currentId] = $byConstructor; } @@ -362,7 +492,7 @@ private function addCircularReferences($id, $currentPath, $byConstructor) } } - private function collectLineage($class, array &$lineage) + private function collectLineage(string $class, array &$lineage) { if (isset($lineage[$class])) { return; @@ -370,17 +500,19 @@ private function collectLineage($class, array &$lineage) if (!$r = $this->container->getReflectionClass($class, false)) { return; } - if ($this->container instanceof $class) { + if (is_a($class, $this->baseClass, true)) { return; } $file = $r->getFileName(); - if (') : eval()\'d code' === substr($file, -17)) { + if (str_ends_with($file, ') : eval()\'d code')) { $file = substr($file, 0, strrpos($file, '(', -17)); } if (!$file || $this->doExport($file) === $exportedFile = $this->export($file)) { return; } + $lineage[$class] = substr($exportedFile, 1, -1); + if ($parent = $r->getParentClass()) { $this->collectLineage($parent->name, $lineage); } @@ -393,14 +525,16 @@ private function collectLineage($class, array &$lineage) $this->collectLineage($parent->name, $lineage); } + unset($lineage[$class]); $lineage[$class] = substr($exportedFile, 1, -1); } - private function generateProxyClasses() + private function generateProxyClasses(): array { + $proxyClasses = []; $alreadyGenerated = []; $definitions = $this->container->getDefinitions(); - $strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments'); + $strip = '' === $this->docStar && method_exists(Kernel::class, 'stripComments'); $proxyDumper = $this->getProxyDumper(); ksort($definitions); foreach ($definitions as $definition) { @@ -416,39 +550,56 @@ private function generateProxyClasses() if ("\n" === $proxyCode = "\n".$proxyDumper->getProxyCode($definition)) { continue; } + + if ($this->inlineRequires) { + $lineage = []; + $this->collectLineage($class, $lineage); + + $code = ''; + foreach (array_diff_key(array_flip($lineage), $this->inlinedRequires) as $file => $class) { + if ($this->inlineFactories) { + $this->inlinedRequires[$file] = true; + } + $code .= sprintf("include_once %s;\n", $file); + } + + $proxyCode = $code.$proxyCode; + } + if ($strip) { $proxyCode = " $proxyCode; + + $proxyClasses[sprintf('%s.php', explode(' ', $this->inlineRequires ? substr($proxyCode, \strlen($code)) : $proxyCode, 3)[1])] = $proxyCode; } + + return $proxyClasses; } - /** - * Generates the require_once statement for service includes. - * - * @return string - */ - private function addServiceInclude($cId, Definition $definition) + private function addServiceInclude(string $cId, Definition $definition): string { $code = ''; - if ($this->inlineRequires && !$this->isHotPath($definition)) { + if ($this->inlineRequires && (!$this->isHotPath($definition) || $this->getProxyDumper()->isProxyCandidate($definition))) { $lineage = []; foreach ($this->inlinedDefinitions as $def) { - if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { - $this->collectLineage($class, $lineage); + if (!$def->isDeprecated()) { + foreach ($this->getClasses($def) as $class) { + $this->collectLineage($class, $lineage); + } } } - foreach ($this->serviceCalls as $id => list($callCount, $behavior)) { + foreach ($this->serviceCalls as $id => [$callCount, $behavior]) { if ('service_container' !== $id && $id !== $cId && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior && $this->container->has($id) && $this->isTrivialInstance($def = $this->container->findDefinition($id)) - && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass()) ) { - $this->collectLineage($class, $lineage); + foreach ($this->getClasses($def) as $class) { + $this->collectLineage($class, $lineage); + } } } @@ -459,7 +610,9 @@ private function addServiceInclude($cId, Definition $definition) foreach ($this->inlinedDefinitions as $def) { if ($file = $def->getFile()) { - $code .= sprintf(" include_once %s;\n", $this->dumpValue($file)); + $file = $this->dumpValue($file); + $file = '(' === $file[0] ? substr($file, 1, -1) : $file; + $code .= sprintf(" include_once %s;\n", $file); } } @@ -471,29 +624,29 @@ private function addServiceInclude($cId, Definition $definition) } /** - * Generates the service instance. - * - * @param string $id - * @param bool $isSimpleInstance - * - * @return string - * * @throws InvalidArgumentException * @throws RuntimeException */ - private function addServiceInstance($id, Definition $definition, $isSimpleInstance) + private function addServiceInstance(string $id, Definition $definition, bool $isSimpleInstance): string { $class = $this->dumpValue($definition->getClass()); - if (0 === strpos($class, "'") && false === strpos($class, '$') && !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) { + if (str_starts_with($class, "'") && !str_contains($class, '$') && !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) { throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id)); } $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition); $instantiation = ''; - if (!$isProxyCandidate && $definition->isShared()) { - $instantiation = sprintf('$this->services[%s] = %s', $this->doExport($id), $isSimpleInstance ? '' : '$instance'); + $lastWitherIndex = null; + foreach ($definition->getMethodCalls() as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + + if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id]) && null === $lastWitherIndex) { + $instantiation = sprintf('$this->%s[%s] = %s', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $this->doExport($id), $isSimpleInstance ? '' : '$instance'); } elseif (!$isSimpleInstance) { $instantiation = '$instance'; } @@ -505,16 +658,14 @@ private function addServiceInstance($id, Definition $definition, $isSimpleInstan $instantiation .= ' = '; } - return $this->addNewInstance($definition, $return, $instantiation, $id); + return $this->addNewInstance($definition, ' '.$return.$instantiation, $id); } - /** - * Checks if the definition is a trivial instance. - * - * @return bool - */ - private function isTrivialInstance(Definition $definition) + private function isTrivialInstance(Definition $definition): bool { + if ($definition->hasErrors()) { + return true; + } if ($definition->isSynthetic() || $definition->getFile() || $definition->getMethodCalls() || $definition->getProperties() || $definition->getConfigurator()) { return false; } @@ -551,29 +702,38 @@ private function isTrivialInstance(Definition $definition) return true; } - /** - * Adds method calls to a service definition. - * - * @param string $variableName - * - * @return string - */ - private function addServiceMethodCalls(Definition $definition, $variableName = 'instance') + private function addServiceMethodCalls(Definition $definition, string $variableName, ?string $sharedNonLazyId): string { + $lastWitherIndex = null; + foreach ($definition->getMethodCalls() as $k => $call) { + if ($call[2] ?? false) { + $lastWitherIndex = $k; + } + } + $calls = ''; - foreach ($definition->getMethodCalls() as $call) { + foreach ($definition->getMethodCalls() as $k => $call) { $arguments = []; - foreach ($call[1] as $value) { - $arguments[] = $this->dumpValue($value); + foreach ($call[1] as $i => $value) { + $arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value); } - $calls .= $this->wrapServiceConditionals($call[1], sprintf(" \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments))); + $witherAssignation = ''; + + if ($call[2] ?? false) { + if (null !== $sharedNonLazyId && $lastWitherIndex === $k) { + $witherAssignation = sprintf('$this->%s[\'%s\'] = ', $definition->isPublic() ? 'services' : 'privates', $sharedNonLazyId); + } + $witherAssignation .= sprintf('$%s = ', $variableName); + } + + $calls .= $this->wrapServiceConditionals($call[1], sprintf(" %s\$%s->%s(%s);\n", $witherAssignation, $variableName, $call[0], implode(', ', $arguments))); } return $calls; } - private function addServiceProperties(Definition $definition, $variableName = 'instance') + private function addServiceProperties(Definition $definition, string $variableName = 'instance'): string { $code = ''; foreach ($definition->getProperties() as $name => $value) { @@ -583,14 +743,7 @@ private function addServiceProperties(Definition $definition, $variableName = 'i return $code; } - /** - * Adds configurator definition. - * - * @param string $variableName - * - * @return string - */ - private function addServiceConfigurator(Definition $definition, $variableName = 'instance') + private function addServiceConfigurator(Definition $definition, string $variableName = 'instance'): string { if (!$callable = $definition->getConfigurator()) { return ''; @@ -604,30 +757,22 @@ private function addServiceConfigurator(Definition $definition, $variableName = } $class = $this->dumpValue($callable[0]); - // If the class is a string we can optimize call_user_func away - if (0 === strpos($class, "'") && false === strpos($class, '$')) { + // If the class is a string we can optimize away + if (str_starts_with($class, "'") && !str_contains($class, '$')) { return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $callable[1], $variableName); } - if (0 === strpos($class, 'new ')) { + if (str_starts_with($class, 'new ')) { return sprintf(" (%s)->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName); } - return sprintf(" \\call_user_func([%s, '%s'], \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName); + return sprintf(" [%s, '%s'](\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName); } return sprintf(" %s(\$%s);\n", $callable, $variableName); } - /** - * Adds a service. - * - * @param string $id - * @param string &$file - * - * @return string - */ - private function addService($id, Definition $definition, &$file = null) + private function addService(string $id, Definition $definition): array { $this->definitionVariables = new \SplObjectStorage(); $this->referenceVariables = []; @@ -638,7 +783,7 @@ private function addService($id, Definition $definition, &$file = null) if ($class = $definition->getClass()) { $class = $class instanceof Parameter ? '%'.$class.'%' : $this->container->resolveEnvPlaceholders($class); - $return[] = sprintf(0 === strpos($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\')); + $return[] = sprintf(str_starts_with($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\')); } elseif ($definition->getFactory()) { $factory = $definition->getFactory(); if (\is_string($factory)) { @@ -651,7 +796,7 @@ private function addService($id, Definition $definition, &$file = null) } if ($definition->isDeprecated()) { - if ($return && 0 === strpos($return[\count($return) - 1], '@return')) { + if ($return && str_starts_with($return[\count($return) - 1], '@return')) { $return[] = ''; } @@ -671,12 +816,13 @@ private function addService($id, Definition $definition, &$file = null) $lazyInitialization = ''; } - $asFile = $this->asFiles && $definition->isShared() && !$this->isHotPath($definition); + $asFile = $this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition); $methodName = $this->generateMethodName($id); if ($asFile) { $file = $methodName.'.php'; $code = " // Returns the $public '$id'$shared$autowired service.\n\n"; } else { + $file = null; $code = <<docStar} @@ -693,21 +839,32 @@ protected function {$methodName}($lazyInitialization) EOF; } - $this->serviceCalls = []; - $this->inlinedDefinitions = $this->getDefinitionsFromArguments([$definition], null, $this->serviceCalls); + if ($definition->hasErrors() && $e = $definition->getErrors()) { + $this->addThrow = true; - $code .= $this->addServiceInclude($id, $definition); + $code .= sprintf(" \$this->throw(%s);\n", $this->export(reset($e))); + } else { + $this->serviceCalls = []; + $this->inlinedDefinitions = $this->getDefinitionsFromArguments([$definition], null, $this->serviceCalls); - if ($this->getProxyDumper()->isProxyCandidate($definition)) { - $factoryCode = $asFile ? "\$this->load('%s.php', false)" : '$this->%s(false)'; - $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->doExport($id))); - } + if ($definition->isDeprecated()) { + $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id))); + } else { + foreach ($this->inlinedDefinitions as $def) { + foreach ($this->getClasses($def) as $class) { + $this->preload[$class] = $class; + } + } + } - if ($definition->isDeprecated()) { - $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id))); - } + if ($this->getProxyDumper()->isProxyCandidate($definition)) { + $factoryCode = $asFile ? ($definition->isShared() ? "\$this->load('%s.php', false)" : '$this->factories[%2$s](false)') : '$this->%s(false)'; + $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->doExport($id))); + } - $code .= $this->addInlineService($id, $definition); + $code .= $this->addServiceInclude($id, $definition); + $code .= $this->addInlineService($id, $definition); + } if ($asFile) { $code = implode("\n", array_map(function ($line) { return $line ? substr($line, 8) : $line; }, explode("\n", $code))); @@ -718,10 +875,10 @@ protected function {$methodName}($lazyInitialization) $this->definitionVariables = $this->inlinedDefinitions = null; $this->referenceVariables = $this->serviceCalls = null; - return $code; + return [$file, $code]; } - private function addInlineVariables($id, Definition $definition, array $arguments, $forConstructor) + private function addInlineVariables(string $id, Definition $definition, array $arguments, bool $forConstructor): string { $code = ''; @@ -729,7 +886,7 @@ private function addInlineVariables($id, Definition $definition, array $argument if (\is_array($argument)) { $code .= $this->addInlineVariables($id, $definition, $argument, $forConstructor); } elseif ($argument instanceof Reference) { - $code .= $this->addInlineReference($id, $definition, $this->container->normalizeId($argument), $forConstructor); + $code .= $this->addInlineReference($id, $definition, $argument, $forConstructor); } elseif ($argument instanceof Definition) { $code .= $this->addInlineService($id, $definition, $argument, $forConstructor); } @@ -738,13 +895,13 @@ private function addInlineVariables($id, Definition $definition, array $argument return $code; } - private function addInlineReference($id, Definition $definition, $targetId, $forConstructor) + private function addInlineReference(string $id, Definition $definition, string $targetId, bool $forConstructor): string { while ($this->container->hasAlias($targetId)) { $targetId = (string) $this->container->getAlias($targetId); } - list($callCount, $behavior) = $this->serviceCalls[$targetId]; + [$callCount, $behavior] = $this->serviceCalls[$targetId]; if ($id === $targetId) { return $this->addInlineService($id, $definition, $definition); @@ -754,6 +911,10 @@ private function addInlineReference($id, Definition $definition, $targetId, $for return ''; } + if ($this->container->hasDefinition($targetId) && ($def = $this->container->getDefinition($targetId)) && !$def->isShared()) { + return ''; + } + $hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]); if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) { @@ -784,19 +945,19 @@ private function addInlineReference($id, Definition $definition, $targetId, $for EOTXT , - 'services', + $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $this->doExport($id) ); return $code; } - private function addInlineService($id, Definition $definition, Definition $inlineDef = null, $forConstructor = true) + private function addInlineService(string $id, Definition $definition, Definition $inlineDef = null, bool $forConstructor = true): string { $code = ''; if ($isSimpleInstance = $isRootInstance = null === $inlineDef) { - foreach ($this->serviceCalls as $targetId => list($callCount, $behavior, $byConstructor)) { + foreach ($this->serviceCalls as $targetId => [$callCount, $behavior, $byConstructor]) { if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId]) { $code .= $this->addInlineReference($id, $definition, $targetId, $forConstructor); } @@ -827,7 +988,7 @@ private function addInlineService($id, Definition $definition, Definition $inlin if ('instance' === $name) { $code .= $this->addServiceInstance($id, $definition, $isSimpleInstance); } else { - $code .= $this->addNewInstance($inlineDef, '$'.$name, ' = ', $id); + $code .= $this->addNewInstance($inlineDef, ' $'.$name.' = ', $id); } if ('' !== $inline = $this->addInlineVariables($id, $definition, $arguments, false)) { @@ -837,7 +998,7 @@ private function addInlineService($id, Definition $definition, Definition $inlin } $code .= $this->addServiceProperties($inlineDef, $name); - $code .= $this->addServiceMethodCalls($inlineDef, $name); + $code .= $this->addServiceMethodCalls($inlineDef, $name, !$this->getProxyDumper()->isProxyCandidate($inlineDef) && $inlineDef->isShared() && !isset($this->singleUsePrivateIds[$id]) ? $id : null); $code .= $this->addServiceConfigurator($inlineDef, $name); } @@ -848,54 +1009,84 @@ private function addInlineService($id, Definition $definition, Definition $inlin return $code; } - /** - * Adds multiple services. - * - * @return string - */ - private function addServices() + private function addServices(array &$services = null): string { $publicServices = $privateServices = ''; $definitions = $this->container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { - if ($definition->isSynthetic() || ($this->asFiles && $definition->isShared() && !$this->isHotPath($definition))) { + if (!$definition->isSynthetic()) { + $services[$id] = $this->addService($id, $definition); + } else { + $services[$id] = null; + + foreach ($this->getClasses($definition) as $class) { + $this->preload[$class] = $class; + } + } + } + + foreach ($definitions as $id => $definition) { + if (!([$file, $code] = $services[$id]) || null !== $file) { continue; } if ($definition->isPublic()) { - $publicServices .= $this->addService($id, $definition); - } else { - $privateServices .= $this->addService($id, $definition); + $publicServices .= $code; + } elseif (!$this->isTrivialInstance($definition) || isset($this->locatedIds[$id])) { + $privateServices .= $code; } } return $publicServices.$privateServices; } - private function generateServiceFiles() + private function generateServiceFiles(array $services): iterable { $definitions = $this->container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { - if (!$definition->isSynthetic() && $definition->isShared() && !$this->isHotPath($definition)) { - $code = $this->addService($id, $definition, $file); + if (([$file, $code] = $services[$id]) && null !== $file && ($definition->isPublic() || !$this->isTrivialInstance($definition) || isset($this->locatedIds[$id]))) { + if (!$definition->isShared()) { + $i = strpos($code, "\n\ninclude_once "); + if (false !== $i && false !== $i = strpos($code, "\n\n", 2 + $i)) { + $code = [substr($code, 0, 2 + $i), substr($code, 2 + $i)]; + } else { + $code = ["\n", $code]; + } + $code[1] = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code[1]))); + $factory = sprintf('$this->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id)); + $lazyloadInitialization = $definition->isLazy() ? '$lazyLoad = true' : ''; + + $code[1] = sprintf("%s = function (%s) {\n%s};\n\nreturn %1\$s();\n", $factory, $lazyloadInitialization, $code[1]); + $code = $code[0].$code[1]; + } + yield $file => $code; } } } - private function addNewInstance(Definition $definition, $return, $instantiation, $id) + private function addNewInstance(Definition $definition, string $return = '', string $id = null): string { - $class = $this->dumpValue($definition->getClass()); - $return = ' '.$return.$instantiation; + $tail = $return ? ";\n" : ''; + + if (BaseServiceLocator::class === $definition->getClass() && $definition->hasTag($this->serviceLocatorTag)) { + $arguments = []; + foreach ($definition->getArgument(0) as $k => $argument) { + $arguments[$k] = $argument->getValues()[0]; + } + + return $return.$this->dumpValue(new ServiceLocatorArgument($arguments)).$tail; + } $arguments = []; - foreach ($definition->getArguments() as $value) { - $arguments[] = $this->dumpValue($value); + foreach ($definition->getArguments() as $i => $value) { + $arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value); } if (null !== $definition->getFactory()) { $callable = $definition->getFactory(); + if (\is_array($callable)) { if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) { throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).', $callable[1] ?: 'n/a')); @@ -903,48 +1094,38 @@ private function addNewInstance(Definition $definition, $return, $instantiation, if ($callable[0] instanceof Reference || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) { - return $return.sprintf("%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf('%s->%s(%s)', $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '').$tail; } $class = $this->dumpValue($callable[0]); - // If the class is a string we can optimize call_user_func away - if (0 === strpos($class, "'") && false === strpos($class, '$')) { + // If the class is a string we can optimize away + if (str_starts_with($class, "'") && !str_contains($class, '$')) { if ("''" === $class) { - throw new RuntimeException(sprintf('Cannot dump definition: The "%s" service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id)); + throw new RuntimeException(sprintf('Cannot dump definition: %s service is defined to be created by a factory but is missing the service reference, did you forget to define the factory service id or class?', $id ? 'The "'.$id.'"' : 'inline')); } - return $return.sprintf("%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf('%s::%s(%s)', $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '').$tail; } - if (0 === strpos($class, 'new ')) { - return $return.sprintf("(%s)->%s(%s);\n", $class, $callable[1], $arguments ? implode(', ', $arguments) : ''); + if (str_starts_with($class, 'new ')) { + return $return.sprintf('(%s)->%s(%s)', $class, $callable[1], $arguments ? implode(', ', $arguments) : '').$tail; } - return $return.sprintf("\\call_user_func([%s, '%s']%s);\n", $class, $callable[1], $arguments ? ', '.implode(', ', $arguments) : ''); + return $return.sprintf("[%s, '%s'](%s)", $class, $callable[1], $arguments ? implode(', ', $arguments) : '').$tail; } - return $return.sprintf("%s(%s);\n", $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : ''); + return $return.sprintf('%s(%s)', $this->dumpLiteralClass($this->dumpValue($callable)), $arguments ? implode(', ', $arguments) : '').$tail; } - if (false !== strpos($class, '$')) { - return sprintf(" \$class = %s;\n\n%snew \$class(%s);\n", $class, $return, implode(', ', $arguments)); + if (null === $class = $definition->getClass()) { + throw new RuntimeException('Cannot dump definitions which have no class nor factory.'); } - return $return.sprintf("new %s(%s);\n", $this->dumpLiteralClass($class), implode(', ', $arguments)); + return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail; } - /** - * Adds the class headers. - * - * @param string $class Class name - * @param string $baseClass The name of the base class - * @param string $baseClassWithNamespace Fully qualified base class name - * - * @return string - */ - private function startClass($class, $baseClass, $baseClassWithNamespace) + private function startClass(string $class, string $baseClass): string { - $bagClass = $this->container->isCompiled() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;'; $namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : ''; $code = <<docStar} * This class has been auto-generated * by the Symfony Dependency Injection Component. * - * @final since Symfony 3.3 + * @final */ class $class extends $baseClass { private \$parameters = []; - private \$targetDirs = []; public function __construct() { EOF; - if (null !== $this->targetDirRegex) { - $dir = $this->asFiles ? '$this->targetDirs[0] = \\dirname($containerDir)' : '__DIR__'; - $code .= <<targetDirMaxMatches}; ++\$i) { - \$this->targetDirs[\$i] = \$dir = \\dirname(\$dir); - } - -EOF; - } if ($this->asFiles) { $code = str_replace('$parameters', "\$buildParameters;\n private \$containerDir;\n private \$parameters", $code); $code = str_replace('__construct()', '__construct(array $buildParameters = [], $containerDir = __DIR__)', $code); $code .= " \$this->buildParameters = \$buildParameters;\n"; $code .= " \$this->containerDir = \$containerDir;\n"; - } - if ($this->container->isCompiled()) { - if (Container::class !== $baseClassWithNamespace) { - $r = $this->container->getReflectionClass($baseClassWithNamespace, false); - if (null !== $r - && (null !== $constructor = $r->getConstructor()) - && 0 === $constructor->getNumberOfRequiredParameters() - && Container::class !== $constructor->getDeclaringClass()->name - ) { - $code .= " parent::__construct();\n"; - $code .= " \$this->parameterBag = null;\n\n"; - } + if (null !== $this->targetDirRegex) { + $code = str_replace('$parameters', "\$targetDir;\n private \$parameters", $code); + $code .= ' $this->targetDir = \\dirname($containerDir);'."\n"; } + } - if ($this->container->getParameterBag()->all()) { - $code .= " \$this->parameters = \$this->getDefaultParameters();\n\n"; + if (Container::class !== $this->baseClass) { + $r = $this->container->getReflectionClass($this->baseClass, false); + if (null !== $r + && (null !== $constructor = $r->getConstructor()) + && 0 === $constructor->getNumberOfRequiredParameters() + && Container::class !== $constructor->getDeclaringClass()->name + ) { + $code .= " parent::__construct();\n"; + $code .= " \$this->parameterBag = null;\n\n"; } + } - $code .= " \$this->services = [];\n"; - } else { - $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null; - $code .= " parent::__construct($arguments);\n"; + if ($this->container->getParameterBag()->all()) { + $code .= " \$this->parameters = \$this->getDefaultParameters();\n\n"; } + $code .= " \$this->services = \$this->privates = [];\n"; - $code .= $this->addNormalizedIds(); $code .= $this->addSyntheticIds(); $code .= $this->addMethodMap(); - $code .= $this->asFiles ? $this->addFileMap() : ''; - $code .= $this->addPrivateServices(); + $code .= $this->asFiles && !$this->inlineFactories ? $this->addFileMap() : ''; $code .= $this->addAliases(); $code .= $this->addInlineRequires(); - $code .= <<<'EOF' + $code .= <<addRemovedIds(); - - if ($this->container->isCompiled()) { - $code .= <<addRemovedIds(); - if ($this->asFiles) { + if ($this->asFiles && !$this->inlineFactories) { $code .= <<isProxyCandidate($definition)) { continue; } - if ($this->asFiles) { + if ($this->asFiles && !$this->inlineFactories) { $proxyLoader = '$this->load("{$class}.php")'; - } elseif ($this->namespace) { - $proxyLoader = 'class_alias("'.$this->namespace.'\\\\{$class}", $class, false)'; + } elseif ($this->namespace || $this->inlineFactories) { + $proxyLoader = 'class_alias(__NAMESPACE__."\\\\$class", $class, false)'; } else { $proxyLoader = ''; } @@ -1089,31 +1244,7 @@ protected function createProxy(\$class, \Closure \$factory) return $code; } - /** - * Adds the normalizedIds property definition. - * - * @return string - */ - private function addNormalizedIds() - { - $code = ''; - $normalizedIds = $this->container->getNormalizedIds(); - ksort($normalizedIds); - foreach ($normalizedIds as $id => $normalizedId) { - if ($this->container->has($normalizedId)) { - $code .= ' '.$this->doExport($id).' => '.$this->doExport($normalizedId).",\n"; - } - } - - return $code ? " \$this->normalizedIds = [\n".$code." ];\n" : ''; - } - - /** - * Adds the syntheticIds definition. - * - * @return string - */ - private function addSyntheticIds() + private function addSyntheticIds(): string { $code = ''; $definitions = $this->container->getDefinitions(); @@ -1127,14 +1258,15 @@ private function addSyntheticIds() return $code ? " \$this->syntheticIds = [\n{$code} ];\n" : ''; } - /** - * Adds the removedIds definition. - * - * @return string - */ - private function addRemovedIds() + private function addRemovedIds(): string { - if (!$ids = $this->container->getRemovedIds()) { + $ids = $this->container->getRemovedIds(); + foreach ($this->container->getDefinitions() as $id => $definition) { + if (!$definition->isPublic()) { + $ids[$id] = true; + } + } + if (!$ids) { return ''; } if ($this->asFiles) { @@ -1144,7 +1276,7 @@ private function addRemovedIds() $ids = array_keys($ids); sort($ids); foreach ($ids as $id) { - if (preg_match('/^\d+_[^~]++~[._a-zA-Z\d]{7}$/', $id)) { + if (preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id)) { continue; } $code .= ' '.$this->doExport($id)." => true,\n"; @@ -1155,7 +1287,7 @@ private function addRemovedIds() return <<container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { - if (!$definition->isSynthetic() && (!$this->asFiles || !$definition->isShared() || $this->isHotPath($definition))) { + if (!$definition->isSynthetic() && $definition->isPublic() && (!$this->asFiles || $this->inlineFactories || $this->isHotPath($definition))) { $code .= ' '.$this->doExport($id).' => '.$this->doExport($this->generateMethodName($id)).",\n"; } } + $aliases = $this->container->getAliases(); + foreach ($aliases as $alias => $id) { + if (!$id->isDeprecated()) { + continue; + } + $code .= ' '.$this->doExport($alias).' => '.$this->doExport($this->generateMethodName($alias)).",\n"; + } + return $code ? " \$this->methodMap = [\n{$code} ];\n" : ''; } - /** - * Adds the fileMap property definition. - * - * @return string - */ - private function addFileMap() + private function addFileMap(): string { $code = ''; $definitions = $this->container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { - if (!$definition->isSynthetic() && $definition->isShared() && !$this->isHotPath($definition)) { + if (!$definition->isSynthetic() && $definition->isPublic() && !$this->isHotPath($definition)) { $code .= sprintf(" %s => '%s.php',\n", $this->doExport($id), $this->generateMethodName($id)); } } @@ -1201,67 +1331,63 @@ private function addFileMap() return $code ? " \$this->fileMap = [\n{$code} ];\n" : ''; } - /** - * Adds the privates property definition. - * - * @return string - */ - private function addPrivateServices() + private function addAliases(): string { - $code = ''; + if (!$aliases = $this->container->getAliases()) { + return "\n \$this->aliases = [];\n"; + } - $aliases = $this->container->getAliases(); + $code = " \$this->aliases = [\n"; ksort($aliases); - foreach ($aliases as $id => $alias) { - if ($alias->isPrivate()) { - $code .= ' '.$this->doExport($id)." => true,\n"; + foreach ($aliases as $alias => $id) { + if ($id->isDeprecated()) { + continue; } - } - $definitions = $this->container->getDefinitions(); - ksort($definitions); - foreach ($definitions as $id => $definition) { - if (!$definition->isPublic()) { - $code .= ' '.$this->doExport($id)." => true,\n"; + $id = (string) $id; + while (isset($aliases[$id])) { + $id = (string) $aliases[$id]; } + $code .= ' '.$this->doExport($alias).' => '.$this->doExport($id).",\n"; } - if (empty($code)) { - return ''; - } - - $out = " \$this->privates = [\n"; - $out .= $code; - $out .= " ];\n"; - - return $out; + return $code." ];\n"; } - /** - * Adds the aliases property definition. + private function addDeprecatedAliases(): string + { + $code = ''; + $aliases = $this->container->getAliases(); + foreach ($aliases as $alias => $definition) { + if (!$definition->isDeprecated()) { + continue; + } + $public = $definition->isPublic() ? 'public' : 'private'; + $id = (string) $definition; + $methodNameAlias = $this->generateMethodName($alias); + $idExported = $this->export($id); + $messageExported = $this->export($definition->getDeprecationMessage($alias)); + $code .= <<docStar} + * Gets the $public '$alias' alias. * - * @return string + * @return object The "$id" service. */ - private function addAliases() + protected function {$methodNameAlias}() { - if (!$aliases = $this->container->getAliases()) { - return $this->container->isCompiled() ? "\n \$this->aliases = [];\n" : ''; - } + @trigger_error($messageExported, E_USER_DEPRECATED); - $code = " \$this->aliases = [\n"; - ksort($aliases); - foreach ($aliases as $alias => $id) { - $id = $this->container->normalizeId($id); - while (isset($aliases[$id])) { - $id = $this->container->normalizeId($aliases[$id]); - } - $code .= ' '.$this->doExport($alias).' => '.$this->doExport($id).",\n"; + return \$this->get($idExported); + } + +EOF; } - return $code." ];\n"; + return $code; } - private function addInlineRequires() + private function addInlineRequires(): string { if (!$this->hotPathTag || !$this->inlineRequires) { return ''; @@ -1271,10 +1397,15 @@ private function addInlineRequires() foreach ($this->container->findTaggedServiceIds($this->hotPathTag) as $id => $tags) { $definition = $this->container->getDefinition($id); + + if ($this->getProxyDumper()->isProxyCandidate($definition)) { + continue; + } + $inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]); foreach ($inlinedDefinitions as $def) { - if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { + foreach ($this->getClasses($def) as $class) { $this->collectLineage($class, $lineage); } } @@ -1292,12 +1423,7 @@ private function addInlineRequires() return $code ? sprintf("\n \$this->privates['service_container'] = function () {%s\n };\n", $code) : ''; } - /** - * Adds default parameters method. - * - * @return string - */ - private function addDefaultParametersMethod() + private function addDefaultParametersMethod(): string { if (!$this->container->getParameterBag()->all()) { return ''; @@ -1305,43 +1431,36 @@ private function addDefaultParametersMethod() $php = []; $dynamicPhp = []; - $normalizedParams = []; foreach ($this->container->getParameterBag()->all() as $key => $value) { if ($key !== $resolvedKey = $this->container->resolveEnvPlaceholders($key)) { throw new InvalidArgumentException(sprintf('Parameter name cannot use env parameters: "%s".', $resolvedKey)); } - if ($key !== $lcKey = strtolower($key)) { - $normalizedParams[] = sprintf(' %s => %s,', $this->export($lcKey), $this->export($key)); - } $export = $this->exportParameters([$value]); $export = explode('0 => ', substr(rtrim($export, " ]\n"), 2, -1), 2); - if (preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDirs\[\d++\])/", $export[1])) { + if (preg_match("/\\\$this->(?:getEnv\('(?:[-.\w]*+:)*+\w++'\)|targetDir\.'')/", $export[1])) { $dynamicPhp[$key] = sprintf('%scase %s: $value = %s; break;', $export[0], $this->export($key), $export[1]); } else { $php[] = sprintf('%s%s => %s,', $export[0], $this->export($key), $export[1]); } } - $parameters = sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', 8)); - $code = ''; - if ($this->container->isCompiled()) { - $code .= <<<'EOF' + $code = <<<'EOF' + /** + * @return array|bool|float|int|string|null + */ public function getParameter($name) { $name = (string) $name; if (isset($this->buildParameters[$name])) { return $this->buildParameters[$name]; } - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } + if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { + throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); } if (isset($this->loadedDynamicParameters[$name])) { return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); @@ -1350,23 +1469,22 @@ public function getParameter($name) return $this->parameters[$name]; } - public function hasParameter($name) + public function hasParameter($name): bool { $name = (string) $name; if (isset($this->buildParameters[$name])) { return true; } - $name = $this->normalizeParameterName($name); return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); } - public function setParameter($name, $value) + public function setParameter($name, $value): void { throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); } - public function getParameterBag() + public function getParameterBag(): ParameterBagInterface { if (null === $this->parameterBag) { $parameters = $this->parameters; @@ -1383,13 +1501,13 @@ public function getParameterBag() } EOF; - if (!$this->asFiles) { - $code = preg_replace('/^.*buildParameters.*\n.*\n.*\n/m', '', $code); - } + if (!$this->asFiles) { + $code = preg_replace('/^.*buildParameters.*\n.*\n.*\n/m', '', $code); + } - if ($dynamicPhp) { - $loadedDynamicParameters = $this->exportParameters(array_combine(array_keys($dynamicPhp), array_fill(0, \count($dynamicPhp), false)), '', 8); - $getDynamicParameter = <<<'EOF' + if ($dynamicPhp) { + $loadedDynamicParameters = $this->exportParameters(array_combine(array_keys($dynamicPhp), array_fill(0, \count($dynamicPhp), false)), '', 8); + $getDynamicParameter = <<<'EOF' switch ($name) { %s default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%%s" must be defined.', $name)); @@ -1398,64 +1516,23 @@ public function getParameterBag() return $this->dynamicParameters[$name] = $value; EOF; - $getDynamicParameter = sprintf($getDynamicParameter, implode("\n", $dynamicPhp)); - } else { - $loadedDynamicParameters = '[]'; - $getDynamicParameter = str_repeat(' ', 8).'throw new InvalidArgumentException(sprintf(\'The dynamic parameter "%s" must be defined.\', $name));'; - } + $getDynamicParameter = sprintf($getDynamicParameter, implode("\n", $dynamicPhp)); + } else { + $loadedDynamicParameters = '[]'; + $getDynamicParameter = str_repeat(' ', 8).'throw new InvalidArgumentException(sprintf(\'The dynamic parameter "%s" must be defined.\', $name));'; + } - $code .= <<docStar} - * Computes a dynamic parameter. - * - * @param string \$name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter(\$name) + private function getDynamicParameter(string \$name) { {$getDynamicParameter} } - -EOF; - - $code .= ' private $normalizedParameterNames = '.($normalizedParams ? sprintf("[\n%s\n ];", implode("\n", $normalizedParams)) : '[];')."\n"; - $code .= <<<'EOF' - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - -EOF; - } elseif ($dynamicPhp) { - throw new RuntimeException('You cannot dump a not-frozen container with dynamic parameters.'); - } - - $code .= <<docStar} - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() + protected function getDefaultParameters(): array { return $parameters; } @@ -1466,16 +1543,9 @@ protected function getDefaultParameters() } /** - * Exports parameters. - * - * @param string $path - * @param int $indent - * - * @return string - * * @throws InvalidArgumentException */ - private function exportParameters(array $parameters, $path = '', $indent = 12) + private function exportParameters(array $parameters, string $path = '', int $indent = 12): string { $php = []; foreach ($parameters as $key => $value) { @@ -1501,28 +1571,27 @@ private function exportParameters(array $parameters, $path = '', $indent = 12) return sprintf("[\n%s\n%s]", implode("\n", $php), str_repeat(' ', $indent - 4)); } - /** - * Ends the class definition. - * - * @return string - */ - private function endClass() + private function endClass(): string + { + if ($this->addThrow) { + return <<<'EOF' + + protected function throw($message) { + throw new RuntimeException($message); + } +} + +EOF; + } + return <<<'EOF' } EOF; } - /** - * Wraps the service conditionals. - * - * @param string $value - * @param string $code - * - * @return string - */ - private function wrapServiceConditionals($value, $code) + private function wrapServiceConditionals($value, string $code): string { if (!$condition = $this->getServiceConditionals($value)) { return $code; @@ -1534,21 +1603,14 @@ private function wrapServiceConditionals($value, $code) return sprintf(" if (%s) {\n%s }\n", $condition, $code); } - /** - * Get the conditions to execute for conditional services. - * - * @param string $value - * - * @return string|null - */ - private function getServiceConditionals($value) + private function getServiceConditionals($value): string { $conditions = []; foreach (ContainerBuilder::getInitializedConditionals($value) as $service) { if (!$this->container->hasDefinition($service)) { return 'false'; } - $conditions[] = sprintf('isset($this->services[%s])', $this->doExport($service)); + $conditions[] = sprintf('isset($this->%s[%s])', $this->container->getDefinition($service)->isPublic() ? 'services' : 'privates', $this->doExport($service)); } foreach (ContainerBuilder::getServiceConditionals($value) as $service) { if ($this->container->hasDefinition($service) && !$this->container->getDefinition($service)->isPublic()) { @@ -1565,7 +1627,7 @@ private function getServiceConditionals($value) return implode(' && ', $conditions); } - private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = [], $byConstructor = null) + private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = [], bool $byConstructor = null): \SplObjectStorage { if (null === $definitions) { $definitions = new \SplObjectStorage(); @@ -1575,7 +1637,7 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage if (\is_array($argument)) { $this->getDefinitionsFromArguments($argument, $definitions, $calls, $byConstructor); } elseif ($argument instanceof Reference) { - $id = $this->container->normalizeId($argument); + $id = (string) $argument; while ($this->container->hasAlias($id)) { $id = (string) $this->container->getAlias($id); @@ -1605,16 +1667,9 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage } /** - * Dumps values. - * - * @param mixed $value - * @param bool $interpolate - * - * @return string - * * @throws RuntimeException */ - private function dumpValue($value, $interpolate = true) + private function dumpValue($value, bool $interpolate = true): string { if (\is_array($value)) { if ($value && $interpolate && false !== $param = array_search($value, $this->container->getParameterBag()->all(), true)) { @@ -1635,13 +1690,14 @@ private function dumpValue($value, $interpolate = true) $value = $value->getValues()[0]; $code = $this->dumpValue($value, $interpolate); + $returnedType = ''; if ($value instanceof TypedReference) { - $code = sprintf('$f = function (\\%s $v%s) { return $v; }; return $f(%s);', $value->getType(), ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $value->getInvalidBehavior() ? ' = null' : '', $code); - } else { - $code = sprintf('return %s;', $code); + $returnedType = sprintf(': %s\%s', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $value->getInvalidBehavior() ? '' : '?', $value->getType()); } - return sprintf("function () {\n %s\n }", $code); + $code = sprintf('return %s;', $code); + + return sprintf("function ()%s {\n %s\n }", $returnedType, $code); } if ($value instanceof IteratorArgument) { @@ -1673,10 +1729,43 @@ private function dumpValue($value, $interpolate = true) return implode("\n", $code); } + + if ($value instanceof ServiceLocatorArgument) { + $serviceMap = ''; + $serviceTypes = ''; + foreach ($value->getValues() as $k => $v) { + if (!$v) { + continue; + } + $id = (string) $v; + while ($this->container->hasAlias($id)) { + $id = (string) $this->container->getAlias($id); + } + $definition = $this->container->getDefinition($id); + $load = !($definition->hasErrors() && $e = $definition->getErrors()) ? $this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition) : reset($e); + $serviceMap .= sprintf("\n %s => [%s, %s, %s, %s],", + $this->export($k), + $this->export($definition->isShared() ? ($definition->isPublic() ? 'services' : 'privates') : false), + $this->doExport($id), + $this->export(ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $v->getInvalidBehavior() && !\is_string($load) ? $this->generateMethodName($id).($load ? '.php' : '') : null), + $this->export($load) + ); + $serviceTypes .= sprintf("\n %s => %s,", $this->export($k), $this->export($v instanceof TypedReference ? $v->getType() : '?')); + $this->locatedIds[$id] = true; + } + $this->addGetService = true; + + return sprintf('new \%s($this->getService, [%s%s], [%s%s])', ServiceLocator::class, $serviceMap, $serviceMap ? "\n " : '', $serviceTypes, $serviceTypes ? "\n " : ''); + } } finally { - list($this->definitionVariables, $this->referenceVariables) = $scope; + [$this->definitionVariables, $this->referenceVariables] = $scope; } } elseif ($value instanceof Definition) { + if ($value->hasErrors() && $e = $value->getErrors()) { + $this->addThrow = true; + + return sprintf('$this->throw(%s)', $this->export(reset($e))); + } if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) { return $this->dumpValue($this->definitionVariables[$value], $interpolate); } @@ -1690,54 +1779,11 @@ private function dumpValue($value, $interpolate = true) throw new RuntimeException('Cannot dump definitions which have a configurator.'); } - $arguments = []; - foreach ($value->getArguments() as $argument) { - $arguments[] = $this->dumpValue($argument); - } - - if (null !== $value->getFactory()) { - $factory = $value->getFactory(); - - if (\is_string($factory)) { - return sprintf('%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory)), implode(', ', $arguments)); - } - - if (\is_array($factory)) { - if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) { - throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s).', $factory[1] ?: 'n/a')); - } - - $class = $this->dumpValue($factory[0]); - if (\is_string($factory[0])) { - return sprintf('%s::%s(%s)', $this->dumpLiteralClass($class), $factory[1], implode(', ', $arguments)); - } - - if ($factory[0] instanceof Definition) { - if (0 === strpos($class, 'new ')) { - return sprintf('(%s)->%s(%s)', $class, $factory[1], implode(', ', $arguments)); - } - - return sprintf("\\call_user_func([%s, '%s']%s)", $class, $factory[1], \count($arguments) > 0 ? ', '.implode(', ', $arguments) : ''); - } - - if ($factory[0] instanceof Reference) { - return sprintf('%s->%s(%s)', $class, $factory[1], implode(', ', $arguments)); - } - } - - throw new RuntimeException('Cannot dump definition because of invalid factory.'); - } - - $class = $value->getClass(); - if (null === $class) { - throw new RuntimeException('Cannot dump definitions which have no class nor factory.'); - } - - return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)); + return $this->addNewInstance($value); } elseif ($value instanceof Variable) { return '$'.$value; } elseif ($value instanceof Reference) { - $id = $this->container->normalizeId($value); + $id = (string) $value; while ($this->container->hasAlias($id)) { $id = (string) $this->container->getAlias($id); @@ -1766,6 +1812,8 @@ private function dumpValue($value, $interpolate = true) return $code; } + } elseif ($value instanceof \UnitEnum) { + return sprintf('\%s::%s', \get_class($value), $value->name); } elseif (\is_object($value) || \is_resource($value)) { throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); } @@ -1776,38 +1824,25 @@ private function dumpValue($value, $interpolate = true) /** * Dumps a string to a literal (aka PHP Code) class value. * - * @param string $class - * - * @return string - * * @throws RuntimeException */ - private function dumpLiteralClass($class) + private function dumpLiteralClass(string $class): string { - if (false !== strpos($class, '$')) { + if (str_contains($class, '$')) { return sprintf('${($_ = %s) && false ?: "_"}', $class); } - if (0 !== strpos($class, "'") || !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) { + if (!str_starts_with($class, "'") || !preg_match('/^\'(?:\\\{2})?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(?:\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) { throw new RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s).', $class ?: 'n/a')); } $class = substr(str_replace('\\\\', '\\', $class), 1, -1); - return 0 === strpos($class, '\\') ? $class : '\\'.$class; + return str_starts_with($class, '\\') ? $class : '\\'.$class; } - /** - * Dumps a parameter. - * - * @param string $name - * - * @return string - */ - private function dumpParameter($name) + private function dumpParameter(string $name): string { - $name = (string) $name; - - if ($this->container->isCompiled() && $this->container->hasParameter($name)) { + if ($this->container->hasParameter($name)) { $value = $this->container->getParameter($name); $dumpedValue = $this->dumpValue($value, false); @@ -1815,7 +1850,7 @@ private function dumpParameter($name) return $dumpedValue; } - if (!preg_match("/\\\$this->(?:getEnv\('(?:\w++:)*+\w++'\)|targetDirs\[\d++\])/", $dumpedValue)) { + if (!preg_match("/\\\$this->(?:getEnv\('(?:[-.\w]*+:)*+\w++'\)|targetDir\.'')/", $dumpedValue)) { return sprintf('$this->parameters[%s]', $this->doExport($name)); } } @@ -1823,20 +1858,11 @@ private function dumpParameter($name) return sprintf('$this->getParameter(%s)', $this->doExport($name)); } - /** - * Gets a service call. - * - * @param string $id - * @param Reference $reference - * - * @return string - */ - private function getServiceCall($id, Reference $reference = null) + private function getServiceCall(string $id, Reference $reference = null): string { while ($this->container->hasAlias($id)) { $id = (string) $this->container->getAlias($id); } - $id = $this->container->normalizeId($id); if ('service_container' === $id) { return '$this'; @@ -1851,35 +1877,47 @@ private function getServiceCall($id, Reference $reference = null) return $code; } } elseif ($this->isTrivialInstance($definition)) { - $code = substr($this->addNewInstance($definition, '', '', $id), 8, -2); - if ($definition->isShared()) { - $code = sprintf('$this->services[%s] = %s', $this->doExport($id), $code); + if ($definition->hasErrors() && $e = $definition->getErrors()) { + $this->addThrow = true; + + return sprintf('$this->throw(%s)', $this->export(reset($e))); + } + $code = $this->addNewInstance($definition, '', $id); + if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) { + $code = sprintf('$this->%s[%s] = %s', $definition->isPublic() ? 'services' : 'privates', $this->doExport($id), $code); } $code = "($code)"; - } elseif ($this->asFiles && $definition->isShared() && !$this->isHotPath($definition)) { + } elseif ($this->asFiles && !$this->inlineFactories && !$this->isHotPath($definition)) { $code = sprintf("\$this->load('%s.php')", $this->generateMethodName($id)); + if (!$definition->isShared()) { + $factory = sprintf('$this->factories%s[%s]', $definition->isPublic() ? '' : "['service_container']", $this->doExport($id)); + $code = sprintf('(isset(%s) ? %1$s() : %s)', $factory, $code); + } } else { $code = sprintf('$this->%s()', $this->generateMethodName($id)); } - } elseif (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) { + if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) { + $code = sprintf('($this->%s[%s] ?? %s)', $definition->isPublic() ? 'services' : 'privates', $this->doExport($id), $code); + } + + return $code; + } + if (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) { return 'null'; - } elseif (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) { + } + if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE < $reference->getInvalidBehavior()) { $code = sprintf('$this->get(%s, /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ %d)', $this->doExport($id), ContainerInterface::NULL_ON_INVALID_REFERENCE); } else { $code = sprintf('$this->get(%s)', $this->doExport($id)); } - // The following is PHP 5.5 syntax for what could be written as "(\$this->services['$id'] ?? $code)" on PHP>=7.0 - - return sprintf("\${(\$_ = isset(\$this->services[%s]) ? \$this->services[%1\$s] : %s) && false ?: '_'}", $this->doExport($id), $code); + return sprintf('($this->services[%s] ?? %s)', $this->doExport($id), $code); } /** * Initializes the method names map to avoid conflicts with the Container methods. - * - * @param string $class the container base class */ - private function initializeMethodNamesMap($class) + private function initializeMethodNamesMap(string $class) { $this->serviceIdToMethodNameMap = []; $this->usedMethodNames = []; @@ -1892,15 +1930,9 @@ private function initializeMethodNamesMap($class) } /** - * Convert a service id to a valid PHP method name. - * - * @param string $id - * - * @return string - * * @throws InvalidArgumentException */ - private function generateMethodName($id) + private function generateMethodName(string $id): string { if (isset($this->serviceIdToMethodNameMap[$id])) { return $this->serviceIdToMethodNameMap[$id]; @@ -1923,12 +1955,7 @@ private function generateMethodName($id) return $methodName; } - /** - * Returns the next name to use. - * - * @return string - */ - private function getNextVariableName() + private function getNextVariableName(): string { $firstChars = self::FIRST_CHARS; $firstCharsLength = \strlen($firstChars); @@ -1961,11 +1988,11 @@ private function getNextVariableName() } } - private function getExpressionLanguage() + private function getExpressionLanguage(): ExpressionLanguage { if (null === $this->expressionLanguage) { - if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) { - throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); + if (!class_exists(\Symfony\Component\ExpressionLanguage\ExpressionLanguage::class)) { + throw new LogicException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.'); } $providers = $this->container->getExpressionLanguageProviders(); $this->expressionLanguage = new ExpressionLanguage(null, $providers, function ($arg) { @@ -1988,23 +2015,55 @@ private function getExpressionLanguage() return $this->expressionLanguage; } - private function isHotPath(Definition $definition) + private function isHotPath(Definition $definition): bool { return $this->hotPathTag && $definition->hasTag($this->hotPathTag) && !$definition->isDeprecated(); } + private function isSingleUsePrivateNode(ServiceReferenceGraphNode $node): bool + { + if ($node->getValue()->isPublic()) { + return false; + } + $ids = []; + foreach ($node->getInEdges() as $edge) { + if (!$value = $edge->getSourceNode()->getValue()) { + continue; + } + if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared()) { + return false; + } + $ids[$edge->getSourceNode()->getId()] = true; + } + + return 1 === \count($ids); + } + + /** + * @return mixed + */ private function export($value) { if (null !== $this->targetDirRegex && \is_string($value) && preg_match($this->targetDirRegex, $value, $matches, \PREG_OFFSET_CAPTURE)) { $suffix = $matches[0][1] + \strlen($matches[0][0]); $matches[0][1] += \strlen($matches[1][0]); $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; - $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; + + if ('\\' === \DIRECTORY_SEPARATOR && isset($value[$suffix])) { + $cookie = '\\'.random_int(100000, \PHP_INT_MAX); + $suffix = '.'.$this->doExport(str_replace('\\', $cookie, substr($value, $suffix)), true); + $suffix = str_replace('\\'.$cookie, "'.\\DIRECTORY_SEPARATOR.'", $suffix); + } else { + $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; + } + $dirname = $this->asFiles ? '$this->containerDir' : '__DIR__'; $offset = 2 + $this->targetDirMaxMatches - \count($matches); - if ($this->asFiles || 0 < $offset) { - $dirname = sprintf('$this->targetDirs[%d]', $offset); + if (0 < $offset) { + $dirname = sprintf('\dirname(__DIR__, %d)', $offset + (int) $this->asFiles); + } elseif ($this->asFiles) { + $dirname = "\$this->targetDir.''"; // empty string concatenation on purpose } if ($prefix || $suffix) { @@ -2017,9 +2076,16 @@ private function export($value) return $this->doExport($value, true); } - private function doExport($value, $resolveEnv = false) + /** + * @return mixed + */ + private function doExport($value, bool $resolveEnv = false) { - if (\is_string($value) && false !== strpos($value, "\n")) { + $shouldCacheValue = $resolveEnv && \is_string($value); + if ($shouldCacheValue && isset($this->exportedVariables[$value])) { + return $this->exportedVariables[$value]; + } + if (\is_string($value) && str_contains($value, "\n")) { $cleanParts = explode("\n", $value); $cleanParts = array_map(function ($part) { return var_export($part, true); }, $cleanParts); $export = implode('."\n".', $cleanParts); @@ -2029,7 +2095,7 @@ private function doExport($value, $resolveEnv = false) if ($resolveEnv && "'" === $export[0] && $export !== $resolvedExport = $this->container->resolveEnvPlaceholders($export, "'.\$this->getEnv('string:%s').'")) { $export = $resolvedExport; - if (".''" === substr($export, -3)) { + if (str_ends_with($export, ".''")) { $export = substr($export, 0, -3); if ("'" === $export[1]) { $export = substr_replace($export, '', 18, 7); @@ -2040,6 +2106,68 @@ private function doExport($value, $resolveEnv = false) } } + if ($shouldCacheValue) { + $this->exportedVariables[$value] = $export; + } + return $export; } + + private function getAutoloadFile(): ?string + { + $file = null; + + foreach (spl_autoload_functions() as $autoloader) { + if (!\is_array($autoloader)) { + continue; + } + + if ($autoloader[0] instanceof DebugClassLoader || $autoloader[0] instanceof LegacyDebugClassLoader) { + $autoloader = $autoloader[0]->getClassLoader(); + } + + if (!\is_array($autoloader) || !$autoloader[0] instanceof ClassLoader || !$autoloader[0]->findFile(__CLASS__)) { + continue; + } + + foreach (get_declared_classes() as $class) { + if (str_starts_with($class, 'ComposerAutoloaderInit') && $class::getLoader() === $autoloader[0]) { + $file = \dirname((new \ReflectionClass($class))->getFileName(), 2).'/autoload.php'; + + if (null !== $this->targetDirRegex && preg_match($this->targetDirRegex.'A', $file)) { + return $file; + } + } + } + } + + return $file; + } + + private function getClasses(Definition $definition): array + { + $classes = []; + + while ($definition instanceof Definition) { + if ($class = $definition->getClass()) { + $classes[] = trim($class, '\\'); + } + $factory = $definition->getFactory(); + + if (!\is_array($factory)) { + $factory = [$factory]; + } + + if (\is_string($factory[0])) { + if (false !== $i = strrpos($factory[0], '::')) { + $factory[0] = substr($factory[0], 0, $i); + } + $classes[] = trim($factory[0], '\\'); + } + + $definition = $factory[0]; + } + + return $classes; + } } diff --git a/vendor/symfony/dependency-injection/Dumper/Preloader.php b/vendor/symfony/dependency-injection/Dumper/Preloader.php new file mode 100644 index 00000000..158900bc --- /dev/null +++ b/vendor/symfony/dependency-injection/Dumper/Preloader.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Dumper; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Preloader +{ + public static function preload(array $classes) + { + set_error_handler(function ($t, $m, $f, $l) { + if (error_reporting() & $t) { + if (__FILE__ !== $f) { + throw new \ErrorException($m, 0, $t, $f, $l); + } + + throw new \ReflectionException($m); + } + }); + + $prev = []; + $preloaded = []; + + try { + while ($prev !== $classes) { + $prev = $classes; + foreach ($classes as $c) { + if (!isset($preloaded[$c])) { + self::doPreload($c, $preloaded); + } + } + $classes = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits()); + } + } finally { + restore_error_handler(); + } + } + + private static function doPreload(string $class, array &$preloaded): void + { + if (isset($preloaded[$class]) || \in_array($class, ['self', 'static', 'parent'], true)) { + return; + } + + $preloaded[$class] = true; + + try { + $r = new \ReflectionClass($class); + + if ($r->isInternal()) { + return; + } + + $r->getConstants(); + $r->getDefaultProperties(); + + if (\PHP_VERSION_ID >= 70400) { + foreach ($r->getProperties(\ReflectionProperty::IS_PUBLIC) as $p) { + self::preloadType($p->getType(), $preloaded); + } + } + + foreach ($r->getMethods(\ReflectionMethod::IS_PUBLIC) as $m) { + foreach ($m->getParameters() as $p) { + if ($p->isDefaultValueAvailable() && $p->isDefaultValueConstant()) { + $c = $p->getDefaultValueConstantName(); + + if ($i = strpos($c, '::')) { + self::doPreload(substr($c, 0, $i), $preloaded); + } + } + + self::preloadType($p->getType(), $preloaded); + } + + self::preloadType($m->getReturnType(), $preloaded); + } + } catch (\Throwable $e) { + // ignore missing classes + } + } + + private static function preloadType(?\ReflectionType $t, array &$preloaded): void + { + if (!$t) { + return; + } + + foreach (($t instanceof \ReflectionUnionType || $t instanceof \ReflectionIntersectionType) ? $t->getTypes() : [$t] as $t) { + if (!$t->isBuiltin()) { + self::doPreload($t instanceof \ReflectionNamedType ? $t->getName() : $t, $preloaded); + } + } + } +} diff --git a/vendor/symfony/dependency-injection/Dumper/XmlDumper.php b/vendor/symfony/dependency-injection/Dumper/XmlDumper.php index eff421ec..17cf2c1a 100644 --- a/vendor/symfony/dependency-injection/Dumper/XmlDumper.php +++ b/vendor/symfony/dependency-injection/Dumper/XmlDumper.php @@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; @@ -83,17 +84,14 @@ private function addMethodCalls(array $methodcalls, \DOMElement $parent) if (\count($methodcall[1])) { $this->convertParameters($methodcall[1], 'argument', $call); } + if ($methodcall[2] ?? false) { + $call->setAttribute('returns-clone', 'true'); + } $parent->appendChild($call); } } - /** - * Adds a service. - * - * @param Definition $definition - * @param string $id - */ - private function addService($definition, $id, \DOMElement $parent) + private function addService(Definition $definition, ?string $id, \DOMElement $parent) { $service = $this->document->createElement('service'); if (null !== $id) { @@ -118,9 +116,15 @@ private function addService($definition, $id, \DOMElement $parent) if ($definition->isLazy()) { $service->setAttribute('lazy', 'true'); } - if (null !== $decorated = $definition->getDecoratedService()) { - list($decorated, $renamedId, $priority) = $decorated; + if (null !== $decoratedService = $definition->getDecoratedService()) { + [$decorated, $renamedId, $priority] = $decoratedService; $service->setAttribute('decorates', $decorated); + + $decorationOnInvalid = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + if (\in_array($decorationOnInvalid, [ContainerInterface::IGNORE_ON_INVALID_REFERENCE, ContainerInterface::NULL_ON_INVALID_REFERENCE], true)) { + $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE === $decorationOnInvalid ? 'null' : 'ignore'; + $service->setAttribute('decoration-on-invalid', $invalidBehavior); + } if (null !== $renamedId) { $service->setAttribute('decoration-inner-name', $renamedId); } @@ -134,7 +138,7 @@ private function addService($definition, $id, \DOMElement $parent) $tag = $this->document->createElement('tag'); $tag->setAttribute('name', $name); foreach ($attributes as $key => $value) { - $tag->setAttribute($key, $value); + $tag->setAttribute($key, $value ?? ''); } $service->appendChild($tag); } @@ -184,13 +188,6 @@ private function addService($definition, $id, \DOMElement $parent) $service->setAttribute('autowire', 'true'); } - foreach ($definition->getAutowiringTypes(false) as $autowiringTypeValue) { - $autowiringType = $this->document->createElement('autowiring-type'); - $autowiringType->appendChild($this->document->createTextNode($autowiringTypeValue)); - - $service->appendChild($autowiringType); - } - if ($definition->isAutoconfigured()) { $service->setAttribute('autoconfigure', 'true'); } @@ -217,12 +214,7 @@ private function addService($definition, $id, \DOMElement $parent) $parent->appendChild($service); } - /** - * Adds a service alias. - * - * @param string $alias - */ - private function addServiceAlias($alias, Alias $id, \DOMElement $parent) + private function addServiceAlias(string $alias, Alias $id, \DOMElement $parent) { $service = $this->document->createElement('service'); $service->setAttribute('id', $alias); @@ -230,6 +222,14 @@ private function addServiceAlias($alias, Alias $id, \DOMElement $parent) if (!$id->isPrivate()) { $service->setAttribute('public', $id->isPublic() ? 'true' : 'false'); } + + if ($id->isDeprecated()) { + $deprecated = $this->document->createElement('deprecated'); + $deprecated->appendChild($this->document->createTextNode($id->getDeprecationMessage('%alias_id%'))); + + $service->appendChild($deprecated); + } + $parent->appendChild($service); } @@ -255,13 +255,7 @@ private function addServices(\DOMElement $parent) $parent->appendChild($services); } - /** - * Converts parameters. - * - * @param string $type - * @param string $keyAttribute - */ - private function convertParameters(array $parameters, $type, \DOMElement $parent, $keyAttribute = 'key') + private function convertParameters(array $parameters, string $type, \DOMElement $parent, string $keyAttribute = 'key') { $withKeys = array_keys($parameters) !== range(0, \count($parameters) - 1); foreach ($parameters as $key => $value) { @@ -270,20 +264,35 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent $element->setAttribute($keyAttribute, $key); } - if ($value instanceof ServiceClosureArgument) { - $value = $value->getValues()[0]; - } - if (\is_array($value)) { + if (\is_array($tag = $value)) { $element->setAttribute('type', 'collection'); $this->convertParameters($value, $type, $element, 'key'); - } elseif ($value instanceof TaggedIteratorArgument) { - $element->setAttribute('type', 'tagged'); - $element->setAttribute('tag', $value->getTag()); + } elseif ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) { + $element->setAttribute('type', $value instanceof TaggedIteratorArgument ? 'tagged_iterator' : 'tagged_locator'); + $element->setAttribute('tag', $tag->getTag()); + + if (null !== $tag->getIndexAttribute()) { + $element->setAttribute('index-by', $tag->getIndexAttribute()); + + if (null !== $tag->getDefaultIndexMethod()) { + $element->setAttribute('default-index-method', $tag->getDefaultIndexMethod()); + } + if (null !== $tag->getDefaultPriorityMethod()) { + $element->setAttribute('default-priority-method', $tag->getDefaultPriorityMethod()); + } + } } elseif ($value instanceof IteratorArgument) { $element->setAttribute('type', 'iterator'); $this->convertParameters($value->getValues(), $type, $element, 'key'); - } elseif ($value instanceof Reference) { + } elseif ($value instanceof ServiceLocatorArgument) { + $element->setAttribute('type', 'service_locator'); + $this->convertParameters($value->getValues(), $type, $element, 'key'); + } elseif ($value instanceof Reference || $value instanceof ServiceClosureArgument) { $element->setAttribute('type', 'service'); + if ($value instanceof ServiceClosureArgument) { + $element->setAttribute('type', 'service_closure'); + $value = $value->getValues()[0]; + } $element->setAttribute('id', (string) $value); $behavior = $value->getInvalidBehavior(); if (ContainerInterface::NULL_ON_INVALID_REFERENCE == $behavior) { @@ -300,6 +309,13 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent $element->setAttribute('type', 'expression'); $text = $this->document->createTextNode(self::phpToXml((string) $value)); $element->appendChild($text); + } elseif (\is_string($value) && !preg_match('/^[^\x00-\x08\x0B\x0E-\x1A\x1C-\x1F\x7F]*+$/u', $value)) { + $element->setAttribute('type', 'binary'); + $text = $this->document->createTextNode(self::phpToXml(base64_encode($value))); + $element->appendChild($text); + } elseif ($value instanceof \UnitEnum) { + $element->setAttribute('type', 'constant'); + $element->appendChild($this->document->createTextNode(self::phpToXml($value))); } else { if (\in_array($value, ['null', 'true', 'false'], true)) { $element->setAttribute('type', 'string'); @@ -318,10 +334,8 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent /** * Escapes arguments. - * - * @return array */ - private function escape(array $arguments) + private function escape(array $arguments): array { $args = []; foreach ($arguments as $k => $v) { @@ -342,11 +356,9 @@ private function escape(array $arguments) * * @param mixed $value Value to convert * - * @return string - * * @throws RuntimeException When trying to dump object or resource */ - public static function phpToXml($value) + public static function phpToXml($value): string { switch (true) { case null === $value: @@ -357,6 +369,8 @@ public static function phpToXml($value) return 'false'; case $value instanceof Parameter: return '%'.$value.'%'; + case $value instanceof \UnitEnum: + return sprintf('%s::%s', \get_class($value), $value->name); case \is_object($value) || \is_resource($value): throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); default: diff --git a/vendor/symfony/dependency-injection/Dumper/YamlDumper.php b/vendor/symfony/dependency-injection/Dumper/YamlDumper.php index 1e795c7d..e053d3b6 100644 --- a/vendor/symfony/dependency-injection/Dumper/YamlDumper.php +++ b/vendor/symfony/dependency-injection/Dumper/YamlDumper.php @@ -15,9 +15,11 @@ use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Parameter; use Symfony\Component\DependencyInjection\Reference; @@ -43,8 +45,8 @@ class YamlDumper extends Dumper */ public function dump(array $options = []) { - if (!class_exists('Symfony\Component\Yaml\Dumper')) { - throw new RuntimeException('Unable to dump the container as the Symfony Yaml Component is not installed.'); + if (!class_exists(\Symfony\Component\Yaml\Dumper::class)) { + throw new LogicException('Unable to dump the container as the Symfony Yaml Component is not installed.'); } if (null === $this->dumper) { @@ -54,14 +56,7 @@ public function dump(array $options = []) return $this->container->resolveEnvPlaceholders($this->addParameters()."\n".$this->addServices()); } - /** - * Adds a service. - * - * @param string $id - * - * @return string - */ - private function addService($id, Definition $definition) + private function addService(string $id, Definition $definition): string { $code = " $id:\n"; if ($class = $definition->getClass()) { @@ -108,14 +103,6 @@ private function addService($id, Definition $definition) $code .= " autowire: true\n"; } - $autowiringTypesCode = ''; - foreach ($definition->getAutowiringTypes(false) as $autowiringType) { - $autowiringTypesCode .= sprintf(" - %s\n", $this->dumper->dump($autowiringType)); - } - if ($autowiringTypesCode) { - $code .= sprintf(" autowiring_types:\n%s", $autowiringTypesCode); - } - if ($definition->isAutoconfigured()) { $code .= " autoconfigure: true\n"; } @@ -144,8 +131,8 @@ private function addService($id, Definition $definition) $code .= " shared: false\n"; } - if (null !== $decorated = $definition->getDecoratedService()) { - list($decorated, $renamedId, $priority) = $decorated; + if (null !== $decoratedService = $definition->getDecoratedService()) { + [$decorated, $renamedId, $priority] = $decoratedService; $code .= sprintf(" decorates: %s\n", $decorated); if (null !== $renamedId) { $code .= sprintf(" decoration_inner_name: %s\n", $renamedId); @@ -153,6 +140,12 @@ private function addService($id, Definition $definition) if (0 !== $priority) { $code .= sprintf(" decoration_priority: %s\n", $priority); } + + $decorationOnInvalid = $decoratedService[3] ?? ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + if (\in_array($decorationOnInvalid, [ContainerInterface::IGNORE_ON_INVALID_REFERENCE, ContainerInterface::NULL_ON_INVALID_REFERENCE])) { + $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE === $decorationOnInvalid ? 'null' : 'ignore'; + $code .= sprintf(" decoration_on_invalid: %s\n", $invalidBehavior); + } } if ($callable = $definition->getFactory()) { @@ -166,28 +159,18 @@ private function addService($id, Definition $definition) return $code; } - /** - * Adds a service alias. - * - * @param string $alias - * - * @return string - */ - private function addServiceAlias($alias, Alias $id) + private function addServiceAlias(string $alias, Alias $id): string { - if ($id->isPrivate()) { + $deprecated = $id->isDeprecated() ? sprintf(" deprecated: %s\n", $id->getDeprecationMessage('%alias_id%')) : ''; + + if (!$id->isDeprecated() && $id->isPrivate()) { return sprintf(" %s: '@%s'\n", $alias, $id); } - return sprintf(" %s:\n alias: %s\n public: %s\n", $alias, $id, $id->isPublic() ? 'true' : 'false'); + return sprintf(" %s:\n alias: %s\n public: %s\n%s", $alias, $id, $id->isPublic() ? 'true' : 'false', $deprecated); } - /** - * Adds services. - * - * @return string - */ - private function addServices() + private function addServices(): string { if (!$this->container->getDefinitions()) { return ''; @@ -209,12 +192,7 @@ private function addServices() return $code; } - /** - * Adds parameters. - * - * @return string - */ - private function addParameters() + private function addParameters(): string { if (!$this->container->getParameterBag()->all()) { return ''; @@ -229,6 +207,8 @@ private function addParameters() * Dumps callable to YAML format. * * @param mixed $callable + * + * @return mixed */ private function dumpCallable($callable) { @@ -246,8 +226,6 @@ private function dumpCallable($callable) /** * Dumps the value to YAML format. * - * @param mixed $value - * * @return mixed * * @throws RuntimeException When trying to dump object or resource @@ -256,13 +234,36 @@ private function dumpValue($value) { if ($value instanceof ServiceClosureArgument) { $value = $value->getValues()[0]; + + return new TaggedValue('service_closure', $this->getServiceCall((string) $value, $value)); } if ($value instanceof ArgumentInterface) { - if ($value instanceof TaggedIteratorArgument) { - return new TaggedValue('tagged', $value->getTag()); + $tag = $value; + + if ($value instanceof TaggedIteratorArgument || ($value instanceof ServiceLocatorArgument && $tag = $value->getTaggedIteratorArgument())) { + if (null === $tag->getIndexAttribute()) { + $content = $tag->getTag(); + } else { + $content = [ + 'tag' => $tag->getTag(), + 'index_by' => $tag->getIndexAttribute(), + ]; + + if (null !== $tag->getDefaultIndexMethod()) { + $content['default_index_method'] = $tag->getDefaultIndexMethod(); + } + if (null !== $tag->getDefaultPriorityMethod()) { + $content['default_priority_method'] = $tag->getDefaultPriorityMethod(); + } + } + + return new TaggedValue($value instanceof TaggedIteratorArgument ? 'tagged_iterator' : 'tagged_locator', $content); } + if ($value instanceof IteratorArgument) { $tag = 'iterator'; + } elseif ($value instanceof ServiceLocatorArgument) { + $tag = 'service_locator'; } else { throw new RuntimeException(sprintf('Unspecified Yaml tag for type "%s".', \get_class($value))); } @@ -285,6 +286,8 @@ private function dumpValue($value) return $this->getExpressionCall((string) $value); } elseif ($value instanceof Definition) { return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']); + } elseif ($value instanceof \UnitEnum) { + return new TaggedValue('php/const', sprintf('%s::%s', \get_class($value), $value->name)); } elseif (\is_object($value) || \is_resource($value)) { throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); } @@ -292,18 +295,11 @@ private function dumpValue($value) return $value; } - /** - * Gets the service call. - * - * @param string $id - * @param Reference $reference - * - * @return string - */ - private function getServiceCall($id, Reference $reference = null) + private function getServiceCall(string $id, Reference $reference = null): string { if (null !== $reference) { switch ($reference->getInvalidBehavior()) { + case ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE: break; case ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE: break; case ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE: return sprintf('@!%s', $id); default: return sprintf('@?%s', $id); @@ -313,37 +309,23 @@ private function getServiceCall($id, Reference $reference = null) return sprintf('@%s', $id); } - /** - * Gets parameter call. - * - * @param string $id - * - * @return string - */ - private function getParameterCall($id) + private function getParameterCall(string $id): string { return sprintf('%%%s%%', $id); } - private function getExpressionCall($expression) + private function getExpressionCall(string $expression): string { return sprintf('@=%s', $expression); } - /** - * Prepares parameters. - * - * @param bool $escape - * - * @return array - */ - private function prepareParameters(array $parameters, $escape = true) + private function prepareParameters(array $parameters, bool $escape = true): array { $filtered = []; foreach ($parameters as $key => $value) { if (\is_array($value)) { $value = $this->prepareParameters($value, $escape); - } elseif ($value instanceof Reference || \is_string($value) && 0 === strpos($value, '@')) { + } elseif ($value instanceof Reference || \is_string($value) && str_starts_with($value, '@')) { $value = '@'.$value; } @@ -353,12 +335,7 @@ private function prepareParameters(array $parameters, $escape = true) return $escape ? $this->escape($filtered) : $filtered; } - /** - * Escapes arguments. - * - * @return array - */ - private function escape(array $arguments) + private function escape(array $arguments): array { $args = []; foreach ($arguments as $k => $v) { diff --git a/vendor/symfony/dependency-injection/EnvVarLoaderInterface.php b/vendor/symfony/dependency-injection/EnvVarLoaderInterface.php new file mode 100644 index 00000000..0c547f8a --- /dev/null +++ b/vendor/symfony/dependency-injection/EnvVarLoaderInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection; + +/** + * EnvVarLoaderInterface objects return key/value pairs that are added to the list of available env vars. + * + * @author Nicolas Grekas + */ +interface EnvVarLoaderInterface +{ + /** + * @return string[] Key/value pairs that can be accessed using the regular "%env()%" syntax + */ + public function loadEnvVars(): array; +} diff --git a/vendor/symfony/dependency-injection/EnvVarProcessor.php b/vendor/symfony/dependency-injection/EnvVarProcessor.php index 065673dc..3441febf 100644 --- a/vendor/symfony/dependency-injection/EnvVarProcessor.php +++ b/vendor/symfony/dependency-injection/EnvVarProcessor.php @@ -11,8 +11,8 @@ namespace Symfony\Component\DependencyInjection; -use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException; +use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; /** @@ -21,10 +21,16 @@ class EnvVarProcessor implements EnvVarProcessorInterface { private $container; + private $loaders; + private $loadedVars = []; - public function __construct(ContainerInterface $container) + /** + * @param EnvVarLoaderInterface[] $loaders + */ + public function __construct(ContainerInterface $container, \Traversable $loaders = null) { $this->container = $container; + $this->loaders = $loaders ?? new \ArrayIterator(); } /** @@ -36,12 +42,19 @@ public static function getProvidedTypes() 'base64' => 'string', 'bool' => 'bool', 'const' => 'bool|int|float|string|array', + 'csv' => 'array', 'file' => 'string', 'float' => 'float', 'int' => 'int', 'json' => 'array', + 'key' => 'bool|int|float|string|array', + 'url' => 'array', + 'query_string' => 'array', 'resolve' => 'string', + 'default' => 'bool|int|float|string|array', 'string' => 'string', + 'trim' => 'string', + 'require' => 'bool|int|float|string|array', ]; } @@ -52,35 +65,124 @@ public function getEnv($prefix, $name, \Closure $getEnv) { $i = strpos($name, ':'); - if ('file' === $prefix) { + if ('key' === $prefix) { + if (false === $i) { + throw new RuntimeException(sprintf('Invalid env "key:%s": a key specifier should be provided.', $name)); + } + + $next = substr($name, $i + 1); + $key = substr($name, 0, $i); + $array = $getEnv($next); + + if (!\is_array($array)) { + throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.', $next)); + } + + if (!isset($array[$key]) && !\array_key_exists($key, $array)) { + throw new EnvNotFoundException(sprintf('Key "%s" not found in "%s" (resolved from "%s").', $key, json_encode($array), $next)); + } + + return $array[$key]; + } + + if ('default' === $prefix) { + if (false === $i) { + throw new RuntimeException(sprintf('Invalid env "default:%s": a fallback parameter should be provided.', $name)); + } + + $next = substr($name, $i + 1); + $default = substr($name, 0, $i); + + if ('' !== $default && !$this->container->hasParameter($default)) { + throw new RuntimeException(sprintf('Invalid env fallback in "default:%s": parameter "%s" not found.', $name, $default)); + } + + try { + $env = $getEnv($next); + + if ('' !== $env && null !== $env) { + return $env; + } + } catch (EnvNotFoundException $e) { + // no-op + } + + return '' === $default ? null : $this->container->getParameter($default); + } + + if ('file' === $prefix || 'require' === $prefix) { if (!is_scalar($file = $getEnv($name))) { throw new RuntimeException(sprintf('Invalid file name: env var "%s" is non-scalar.', $name)); } if (!file_exists($file)) { - throw new RuntimeException(sprintf('Env "file:%s" not found: "%s" does not exist.', $name, $file)); + throw new EnvNotFoundException(sprintf('File "%s" not found (resolved from "%s").', $file, $name)); } - return file_get_contents($file); + if ('file' === $prefix) { + return file_get_contents($file); + } else { + return require $file; + } } if (false !== $i || 'string' !== $prefix) { - if (null === $env = $getEnv($name)) { - return null; - } + $env = $getEnv($name); } elseif (isset($_ENV[$name])) { $env = $_ENV[$name]; - } elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) { + } elseif (isset($_SERVER[$name]) && !str_starts_with($name, 'HTTP_')) { $env = $_SERVER[$name]; } elseif (false === ($env = getenv($name)) || null === $env) { // null is a possible value because of thread safety issues - if (!$this->container->hasParameter("env($name)")) { - throw new EnvNotFoundException($name); + foreach ($this->loadedVars as $vars) { + if (false !== $env = ($vars[$name] ?? false)) { + break; + } } - if (null === $env = $this->container->getParameter("env($name)")) { - return null; + if (false === $env || null === $env) { + $loaders = $this->loaders; + $this->loaders = new \ArrayIterator(); + + try { + $i = 0; + $ended = true; + $count = $loaders instanceof \Countable ? $loaders->count() : 0; + foreach ($loaders as $loader) { + if (\count($this->loadedVars) > $i++) { + continue; + } + $this->loadedVars[] = $vars = $loader->loadEnvVars(); + if (false !== $env = $vars[$name] ?? false) { + $ended = false; + break; + } + } + if ($ended || $count === $i) { + $loaders = $this->loaders; + } + } catch (ParameterCircularReferenceException $e) { + // skip loaders that need an env var that is not defined + } finally { + $this->loaders = $loaders; + } + } + + if (false === $env || null === $env) { + if (!$this->container->hasParameter("env($name)")) { + throw new EnvNotFoundException(sprintf('Environment variable not found: "%s".', $name)); + } + + $env = $this->container->getParameter("env($name)"); } } + if (null === $env) { + if (!isset($this->getProvidedTypes()[$prefix])) { + throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix)); + } + + return null; + } + if (!is_scalar($env)) { throw new RuntimeException(sprintf('Non-scalar env var "%s" cannot be cast to "%s".', $name, $prefix)); } @@ -90,11 +192,11 @@ public function getEnv($prefix, $name, \Closure $getEnv) } if ('bool' === $prefix) { - return (bool) self::phpize($env); + return (bool) (filter_var($env, \FILTER_VALIDATE_BOOLEAN) ?: filter_var($env, \FILTER_VALIDATE_INT) ?: filter_var($env, \FILTER_VALIDATE_FLOAT)); } if ('int' === $prefix) { - if (!is_numeric($env = self::phpize($env))) { + if (false === $env = filter_var($env, \FILTER_VALIDATE_INT) ?: filter_var($env, \FILTER_VALIDATE_FLOAT)) { throw new RuntimeException(sprintf('Non-numeric env var "%s" cannot be cast to int.', $name)); } @@ -102,7 +204,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) } if ('float' === $prefix) { - if (!is_numeric($env = self::phpize($env))) { + if (false === $env = filter_var($env, \FILTER_VALIDATE_FLOAT)) { throw new RuntimeException(sprintf('Non-numeric env var "%s" cannot be cast to float.', $name)); } @@ -118,7 +220,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) } if ('base64' === $prefix) { - return base64_decode($env); + return base64_decode(strtr($env, '-_', '+/')); } if ('json' === $prefix) { @@ -128,19 +230,56 @@ public function getEnv($prefix, $name, \Closure $getEnv) throw new RuntimeException(sprintf('Invalid JSON in env var "%s": ', $name).json_last_error_msg()); } - if (!\is_array($env)) { - throw new RuntimeException(sprintf('Invalid JSON env var "%s": array expected, "%s" given.', $name, \gettype($env))); + if (null !== $env && !\is_array($env)) { + throw new RuntimeException(sprintf('Invalid JSON env var "%s": array or null expected, "%s" given.', $name, \gettype($env))); } return $env; } + if ('url' === $prefix) { + $parsedEnv = parse_url($env); + + if (false === $parsedEnv) { + throw new RuntimeException(sprintf('Invalid URL in env var "%s".', $name)); + } + if (!isset($parsedEnv['scheme'], $parsedEnv['host'])) { + throw new RuntimeException(sprintf('Invalid URL env var "%s": schema and host expected, "%s" given.', $name, $env)); + } + $parsedEnv += [ + 'port' => null, + 'user' => null, + 'pass' => null, + 'path' => null, + 'query' => null, + 'fragment' => null, + ]; + + // remove the '/' separator + $parsedEnv['path'] = '/' === ($parsedEnv['path'] ?? '/') ? '' : substr($parsedEnv['path'], 1); + + return $parsedEnv; + } + + if ('query_string' === $prefix) { + $queryString = parse_url($env, \PHP_URL_QUERY) ?: $env; + parse_str($queryString, $result); + + return $result; + } + if ('resolve' === $prefix) { - return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($name) { + return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($name, $getEnv) { if (!isset($match[1])) { return '%'; } - $value = $this->container->getParameter($match[1]); + + if (str_starts_with($match[1], 'env(') && str_ends_with($match[1], ')') && 'env()' !== $match[1]) { + $value = $getEnv(substr($match[1], 4, -1)); + } else { + $value = $this->container->getParameter($match[1]); + } + if (!is_scalar($value)) { throw new RuntimeException(sprintf('Parameter "%s" found when resolving env var "%s" must be scalar, "%s" given.', $match[1], $name, \gettype($value))); } @@ -149,15 +288,14 @@ public function getEnv($prefix, $name, \Closure $getEnv) }, $env); } - throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix)); - } + if ('csv' === $prefix) { + return str_getcsv($env, ',', '"', \PHP_VERSION_ID >= 70400 ? '' : '\\'); + } - private static function phpize($value) - { - if (!class_exists(XmlUtils::class)) { - throw new RuntimeException('The Symfony Config component is required to cast env vars to "bool", "int" or "float".'); + if ('trim' === $prefix) { + return trim($env); } - return XmlUtils::phpize($value); + throw new RuntimeException(sprintf('Unsupported env var prefix "%s".', $prefix)); } } diff --git a/vendor/symfony/dependency-injection/Exception/AutowiringFailedException.php b/vendor/symfony/dependency-injection/Exception/AutowiringFailedException.php index 145cd8cb..0006f562 100644 --- a/vendor/symfony/dependency-injection/Exception/AutowiringFailedException.php +++ b/vendor/symfony/dependency-injection/Exception/AutowiringFailedException.php @@ -17,12 +17,54 @@ class AutowiringFailedException extends RuntimeException { private $serviceId; + private $messageCallback; - public function __construct($serviceId, $message = '', $code = 0, \Exception $previous = null) + public function __construct(string $serviceId, $message = '', int $code = 0, \Throwable $previous = null) { $this->serviceId = $serviceId; - parent::__construct($message, $code, $previous); + if ($message instanceof \Closure + && (\function_exists('xdebug_is_enabled') ? xdebug_is_enabled() : \function_exists('xdebug_info')) + ) { + $message = $message(); + } + + if (!$message instanceof \Closure) { + parent::__construct($message, $code, $previous); + + return; + } + + $this->messageCallback = $message; + parent::__construct('', $code, $previous); + + $this->message = new class($this->message, $this->messageCallback) { + private $message; + private $messageCallback; + + public function __construct(&$message, &$messageCallback) + { + $this->message = &$message; + $this->messageCallback = &$messageCallback; + } + + public function __toString(): string + { + $messageCallback = $this->messageCallback; + $this->messageCallback = null; + + try { + return $this->message = $messageCallback(); + } catch (\Throwable $e) { + return $this->message = $e->getMessage(); + } + } + }; + } + + public function getMessageCallback(): ?\Closure + { + return $this->messageCallback; } public function getServiceId() diff --git a/vendor/symfony/dependency-injection/Exception/EnvNotFoundException.php b/vendor/symfony/dependency-injection/Exception/EnvNotFoundException.php index 577095e8..04ac8480 100644 --- a/vendor/symfony/dependency-injection/Exception/EnvNotFoundException.php +++ b/vendor/symfony/dependency-injection/Exception/EnvNotFoundException.php @@ -18,8 +18,4 @@ */ class EnvNotFoundException extends InvalidArgumentException { - public function __construct($name) - { - parent::__construct(sprintf('Environment variable not found: "%s".', $name)); - } } diff --git a/vendor/symfony/dependency-injection/Exception/EnvParameterException.php b/vendor/symfony/dependency-injection/Exception/EnvParameterException.php index 3839a463..48b5e486 100644 --- a/vendor/symfony/dependency-injection/Exception/EnvParameterException.php +++ b/vendor/symfony/dependency-injection/Exception/EnvParameterException.php @@ -18,7 +18,7 @@ */ class EnvParameterException extends InvalidArgumentException { - public function __construct(array $envs, \Exception $previous = null, $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.') + public function __construct(array $envs, \Throwable $previous = null, string $message = 'Incompatible use of dynamic environment variables "%s" found in parameters.') { parent::__construct(sprintf($message, implode('", "', $envs)), 0, $previous); } diff --git a/vendor/symfony/dependency-injection/Exception/ExceptionInterface.php b/vendor/symfony/dependency-injection/Exception/ExceptionInterface.php index 5bec4786..6202df76 100644 --- a/vendor/symfony/dependency-injection/Exception/ExceptionInterface.php +++ b/vendor/symfony/dependency-injection/Exception/ExceptionInterface.php @@ -19,6 +19,6 @@ * @author Fabien Potencier * @author Bulat Shakirzyanov */ -interface ExceptionInterface extends ContainerExceptionInterface +interface ExceptionInterface extends ContainerExceptionInterface, \Throwable { } diff --git a/vendor/symfony/dependency-injection/Exception/InvalidParameterTypeException.php b/vendor/symfony/dependency-injection/Exception/InvalidParameterTypeException.php new file mode 100644 index 00000000..2a11626f --- /dev/null +++ b/vendor/symfony/dependency-injection/Exception/InvalidParameterTypeException.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Exception; + +/** + * Thrown when trying to inject a parameter into a constructor/method with an incompatible type. + * + * @author Nicolas Grekas + * @author Julien Maulny + */ +class InvalidParameterTypeException extends InvalidArgumentException +{ + public function __construct(string $serviceId, string $type, \ReflectionParameter $parameter) + { + $acceptedType = $parameter->getType(); + $acceptedType = $acceptedType instanceof \ReflectionNamedType ? $acceptedType->getName() : (string) $acceptedType; + $this->code = $type; + + $function = $parameter->getDeclaringFunction(); + $functionName = $function instanceof \ReflectionMethod + ? sprintf('%s::%s', $function->getDeclaringClass()->getName(), $function->getName()) + : $function->getName(); + + parent::__construct(sprintf('Invalid definition for service "%s": argument %d of "%s()" accepts "%s", "%s" passed.', $serviceId, 1 + $parameter->getPosition(), $functionName, $acceptedType, $type)); + } +} diff --git a/vendor/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php b/vendor/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php index 29151765..2450ccb5 100644 --- a/vendor/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php +++ b/vendor/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php @@ -20,7 +20,7 @@ class ParameterCircularReferenceException extends RuntimeException { private $parameters; - public function __construct($parameters, \Exception $previous = null) + public function __construct(array $parameters, \Throwable $previous = null) { parent::__construct(sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], implode('" > "', $parameters), $parameters[0]), 0, $previous); diff --git a/vendor/symfony/dependency-injection/Exception/ParameterNotFoundException.php b/vendor/symfony/dependency-injection/Exception/ParameterNotFoundException.php index b08f2e85..8af993b8 100644 --- a/vendor/symfony/dependency-injection/Exception/ParameterNotFoundException.php +++ b/vendor/symfony/dependency-injection/Exception/ParameterNotFoundException.php @@ -11,12 +11,14 @@ namespace Symfony\Component\DependencyInjection\Exception; +use Psr\Container\NotFoundExceptionInterface; + /** * This exception is thrown when a non-existent parameter is used. * * @author Fabien Potencier */ -class ParameterNotFoundException extends InvalidArgumentException +class ParameterNotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface { private $key; private $sourceId; @@ -25,14 +27,14 @@ class ParameterNotFoundException extends InvalidArgumentException private $nonNestedAlternative; /** - * @param string $key The requested parameter key - * @param string $sourceId The service id that references the non-existent parameter - * @param string $sourceKey The parameter key that references the non-existent parameter - * @param \Exception $previous The previous exception - * @param string[] $alternatives Some parameter name alternatives - * @param string|null $nonNestedAlternative The alternative parameter name when the user expected dot notation for nested parameters + * @param string $key The requested parameter key + * @param string|null $sourceId The service id that references the non-existent parameter + * @param string|null $sourceKey The parameter key that references the non-existent parameter + * @param \Throwable|null $previous The previous exception + * @param string[] $alternatives Some parameter name alternatives + * @param string|null $nonNestedAlternative The alternative parameter name when the user expected dot notation for nested parameters */ - public function __construct($key, $sourceId = null, $sourceKey = null, \Exception $previous = null, array $alternatives = [], $nonNestedAlternative = null) + public function __construct(string $key, string $sourceId = null, string $sourceKey = null, \Throwable $previous = null, array $alternatives = [], string $nonNestedAlternative = null) { $this->key = $key; $this->sourceId = $sourceId; diff --git a/vendor/symfony/dependency-injection/Exception/ServiceCircularReferenceException.php b/vendor/symfony/dependency-injection/Exception/ServiceCircularReferenceException.php index 26e3fb34..a38671bc 100644 --- a/vendor/symfony/dependency-injection/Exception/ServiceCircularReferenceException.php +++ b/vendor/symfony/dependency-injection/Exception/ServiceCircularReferenceException.php @@ -21,7 +21,7 @@ class ServiceCircularReferenceException extends RuntimeException private $serviceId; private $path; - public function __construct($serviceId, array $path, \Exception $previous = null) + public function __construct(string $serviceId, array $path, \Throwable $previous = null) { parent::__construct(sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, implode(' -> ', $path)), 0, $previous); diff --git a/vendor/symfony/dependency-injection/Exception/ServiceNotFoundException.php b/vendor/symfony/dependency-injection/Exception/ServiceNotFoundException.php index 280dabf3..f91afae3 100644 --- a/vendor/symfony/dependency-injection/Exception/ServiceNotFoundException.php +++ b/vendor/symfony/dependency-injection/Exception/ServiceNotFoundException.php @@ -24,7 +24,7 @@ class ServiceNotFoundException extends InvalidArgumentException implements NotFo private $sourceId; private $alternatives; - public function __construct($id, $sourceId = null, \Exception $previous = null, array $alternatives = [], $msg = null) + public function __construct(string $id, string $sourceId = null, \Throwable $previous = null, array $alternatives = [], string $msg = null) { if (null !== $msg) { // no-op diff --git a/vendor/symfony/dependency-injection/ExpressionLanguage.php b/vendor/symfony/dependency-injection/ExpressionLanguage.php index 0c1780b8..961c737e 100644 --- a/vendor/symfony/dependency-injection/ExpressionLanguage.php +++ b/vendor/symfony/dependency-injection/ExpressionLanguage.php @@ -11,8 +11,13 @@ namespace Symfony\Component\DependencyInjection; +use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage; +if (!class_exists(BaseExpressionLanguage::class)) { + return; +} + /** * Adds some function to the default ExpressionLanguage. * @@ -25,7 +30,7 @@ class ExpressionLanguage extends BaseExpressionLanguage /** * {@inheritdoc} */ - public function __construct($cache = null, array $providers = [], callable $serviceCompiler = null) + public function __construct(CacheItemPoolInterface $cache = null, array $providers = [], callable $serviceCompiler = null) { // prepend the default provider to let users override it easily array_unshift($providers, new ExpressionLanguageProvider($serviceCompiler)); diff --git a/vendor/symfony/dependency-injection/Extension/Extension.php b/vendor/symfony/dependency-injection/Extension/Extension.php index 00fa9dc8..01c1e001 100644 --- a/vendor/symfony/dependency-injection/Extension/Extension.php +++ b/vendor/symfony/dependency-injection/Extension/Extension.php @@ -66,7 +66,7 @@ public function getNamespace() public function getAlias() { $className = static::class; - if ('Extension' != substr($className, -9)) { + if (!str_ends_with($className, 'Extension')) { throw new BadMethodCallException('This extension does not follow the naming convention; you must overwrite the getAlias() method.'); } $classBaseName = substr(strrchr($className, '\\'), 1, -9); @@ -81,21 +81,32 @@ public function getConfiguration(array $config, ContainerBuilder $container) { $class = static::class; - if (false !== strpos($class, "\0")) { + if (str_contains($class, "\0")) { return null; // ignore anonymous classes } $class = substr_replace($class, '\Configuration', strrpos($class, '\\')); $class = $container->getReflectionClass($class); - $constructor = $class ? $class->getConstructor() : null; - return $class && (!$constructor || !$constructor->getNumberOfRequiredParameters()) ? $class->newInstance() : null; + if (!$class) { + return null; + } + + if (!$class->implementsInterface(ConfigurationInterface::class)) { + @trigger_error(sprintf('Not implementing "%s" in the extension configuration class "%s" is deprecated since Symfony 4.1.', ConfigurationInterface::class, $class->getName()), \E_USER_DEPRECATED); + //throw new LogicException(sprintf('The extension configuration class "%s" must implement "%s".', $class->getName(), ConfigurationInterface::class)); + + return null; + } + + if (!($constructor = $class->getConstructor()) || !$constructor->getNumberOfRequiredParameters()) { + return $class->newInstance(); + } + + return null; } - /** - * @return array - */ - final protected function processConfiguration(ConfigurationInterface $configuration, array $configs) + final protected function processConfiguration(ConfigurationInterface $configuration, array $configs): array { $processor = new Processor(); @@ -105,7 +116,7 @@ final protected function processConfiguration(ConfigurationInterface $configurat /** * @internal */ - final public function getProcessedConfigs() + final public function getProcessedConfigs(): array { try { return $this->processedConfigs; diff --git a/vendor/symfony/dependency-injection/LICENSE b/vendor/symfony/dependency-injection/LICENSE index 9e936ec0..88bf75bb 100644 --- a/vendor/symfony/dependency-injection/LICENSE +++ b/vendor/symfony/dependency-injection/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php b/vendor/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php index 417ab908..96104e4a 100644 --- a/vendor/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php +++ b/vendor/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php @@ -25,10 +25,8 @@ interface InstantiatorInterface /** * Instantiates a proxy object. * - * @param ContainerInterface $container The container from which the service is being requested - * @param Definition $definition The definition of the requested service - * @param string $id Identifier of the requested service - * @param callable $realInstantiator Zero-argument callback that is capable of producing the real service instance + * @param string $id Identifier of the requested service + * @param callable $realInstantiator Zero-argument callback that is capable of producing the real service instance * * @return object */ diff --git a/vendor/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.php b/vendor/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.php index 532e7686..2e367040 100644 --- a/vendor/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.php +++ b/vendor/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.php @@ -28,6 +28,6 @@ class RealServiceInstantiator implements InstantiatorInterface */ public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator) { - return \call_user_func($realInstantiator); + return $realInstantiator(); } } diff --git a/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.php b/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.php index 3946eafa..f592e6cf 100644 --- a/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.php +++ b/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.php @@ -30,11 +30,12 @@ public function isProxyCandidate(Definition $definition); /** * Generates the code to be used to instantiate a proxy in the dumped factory code. * - * @param string $id Service identifier + * @param string $id Service identifier + * @param string $factoryCode The code to execute to create the service * * @return string */ - public function getProxyFactoryCode(Definition $definition, $id/**, $factoryCode = null */); + public function getProxyFactoryCode(Definition $definition, $id, $factoryCode); /** * Generates the code for the lazy proxy. diff --git a/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php b/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php index 67f9fae9..ebc6a5dc 100644 --- a/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php +++ b/vendor/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php @@ -18,14 +18,14 @@ * * @author Marco Pivetta * - * @final since version 3.3 + * @final */ class NullDumper implements DumperInterface { /** * {@inheritdoc} */ - public function isProxyCandidate(Definition $definition) + public function isProxyCandidate(Definition $definition): bool { return false; } @@ -33,7 +33,7 @@ public function isProxyCandidate(Definition $definition) /** * {@inheritdoc} */ - public function getProxyFactoryCode(Definition $definition, $id, $factoryCode = null) + public function getProxyFactoryCode(Definition $definition, $id, $factoryCode = null): string { return ''; } @@ -41,7 +41,7 @@ public function getProxyFactoryCode(Definition $definition, $id, $factoryCode = /** * {@inheritdoc} */ - public function getProxyCode(Definition $definition) + public function getProxyCode(Definition $definition): string { return ''; } diff --git a/vendor/symfony/dependency-injection/LazyProxy/ProxyHelper.php b/vendor/symfony/dependency-injection/LazyProxy/ProxyHelper.php index bfa65f56..32b94df0 100644 --- a/vendor/symfony/dependency-injection/LazyProxy/ProxyHelper.php +++ b/vendor/symfony/dependency-injection/LazyProxy/ProxyHelper.php @@ -21,42 +21,43 @@ class ProxyHelper /** * @return string|null The FQCN or builtin name of the type hint, or null when the type hint references an invalid self|parent context */ - public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionParameter $p = null, $noBuiltin = false) + public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionParameter $p = null, bool $noBuiltin = false): ?string { if ($p instanceof \ReflectionParameter) { - if (method_exists($p, 'getType')) { - $type = $p->getType(); - } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $p, $type)) { - $name = $type = $type[1]; - - if ('callable' === $name || 'array' === $name) { - return $noBuiltin ? null : $name; - } - } + $type = $p->getType(); } else { - $type = method_exists($r, 'getReturnType') ? $r->getReturnType() : null; + $type = $r->getReturnType(); } if (!$type) { return null; } $types = []; + $glue = '|'; + if ($type instanceof \ReflectionUnionType) { + $reflectionTypes = $type->getTypes(); + } elseif ($type instanceof \ReflectionIntersectionType) { + $reflectionTypes = $type->getTypes(); + $glue = '&'; + } elseif ($type instanceof \ReflectionNamedType) { + $reflectionTypes = [$type]; + } else { + return null; + } - foreach ($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type] as $type) { - $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - - if (!\is_string($type) && $type->isBuiltin()) { + foreach ($reflectionTypes as $type) { + if ($type->isBuiltin()) { if (!$noBuiltin) { - $types[] = $name; + $types[] = $type->getName(); } continue; } - $lcName = strtolower($name); + $lcName = strtolower($type->getName()); $prefix = $noBuiltin ? '' : '\\'; if ('self' !== $lcName && 'parent' !== $lcName) { - $types[] = '' !== $prefix ? $prefix.$name : $name; + $types[] = $prefix.$type->getName(); continue; } if (!$r instanceof \ReflectionMethod) { @@ -69,6 +70,6 @@ public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionPa } } - return $types ? implode('|', $types) : null; + return $types ? implode($glue, $types) : null; } } diff --git a/vendor/symfony/dependency-injection/Loader/ClosureLoader.php b/vendor/symfony/dependency-injection/Loader/ClosureLoader.php index 183cacc4..939dd7cb 100644 --- a/vendor/symfony/dependency-injection/Loader/ClosureLoader.php +++ b/vendor/symfony/dependency-injection/Loader/ClosureLoader.php @@ -35,7 +35,7 @@ public function __construct(ContainerBuilder $container) */ public function load($resource, $type = null) { - \call_user_func($resource, $this->container); + $resource($this->container); } /** diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php index 428683ef..a983b502 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/AbstractConfigurator.php @@ -20,7 +20,7 @@ abstract class AbstractConfigurator { - const FACTORY = 'unknown'; + public const FACTORY = 'unknown'; /** @internal */ protected $definition; @@ -28,12 +28,25 @@ abstract class AbstractConfigurator public function __call($method, $args) { if (method_exists($this, 'set'.$method)) { - return \call_user_func_array([$this, 'set'.$method], $args); + return $this->{'set'.$method}(...$args); } throw new \BadMethodCallException(sprintf('Call to undefined method "%s::%s()".', static::class, $method)); } + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + /** * Checks that a value is valid, optionally replacing Definition and Reference configurators by their configure value. * diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/AbstractServiceConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/AbstractServiceConfigurator.php index 0a565787..38e2dd06 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/AbstractServiceConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/AbstractServiceConfigurator.php @@ -20,7 +20,7 @@ abstract class AbstractServiceConfigurator extends AbstractConfigurator protected $id; private $defaultTags = []; - public function __construct(ServicesConfigurator $parent, Definition $definition, $id = null, array $defaultTags = []) + public function __construct(ServicesConfigurator $parent, Definition $definition, string $id = null, array $defaultTags = []) { $this->parent = $parent; $this->definition = $definition; @@ -32,8 +32,8 @@ public function __destruct() { // default tags should be added last foreach ($this->defaultTags as $name => $attributes) { - foreach ($attributes as $attributes) { - $this->definition->addTag($name, $attributes); + foreach ($attributes as $attribute) { + $this->definition->addTag($name, $attribute); } } $this->defaultTags = []; @@ -41,13 +41,8 @@ public function __destruct() /** * Registers a service. - * - * @param string $id - * @param string|null $class - * - * @return ServiceConfigurator */ - final public function set($id, $class = null) + final public function set(?string $id, string $class = null): ServiceConfigurator { $this->__destruct(); @@ -56,13 +51,8 @@ final public function set($id, $class = null) /** * Creates an alias. - * - * @param string $id - * @param string $referencedId - * - * @return AliasConfigurator */ - final public function alias($id, $referencedId) + final public function alias(string $id, string $referencedId): AliasConfigurator { $this->__destruct(); @@ -71,13 +61,8 @@ final public function alias($id, $referencedId) /** * Registers a PSR-4 namespace using a glob pattern. - * - * @param string $namespace - * @param string $resource - * - * @return PrototypeConfigurator */ - final public function load($namespace, $resource) + final public function load(string $namespace, string $resource): PrototypeConfigurator { $this->__destruct(); @@ -87,13 +72,9 @@ final public function load($namespace, $resource) /** * Gets an already defined service definition. * - * @param string $id - * - * @return ServiceConfigurator - * * @throws ServiceNotFoundException if the service definition does not exist */ - final public function get($id) + final public function get(string $id): ServiceConfigurator { $this->__destruct(); @@ -102,13 +83,8 @@ final public function get($id) /** * Registers a service. - * - * @param string $id - * @param string|null $class - * - * @return ServiceConfigurator */ - final public function __invoke($id, $class = null) + final public function __invoke(string $id, string $class = null): ServiceConfigurator { $this->__destruct(); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/AliasConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/AliasConfigurator.php index cb00f58c..650a9568 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/AliasConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/AliasConfigurator.php @@ -18,10 +18,11 @@ */ class AliasConfigurator extends AbstractServiceConfigurator { - const FACTORY = 'alias'; - + use Traits\DeprecateTrait; use Traits\PublicTrait; + public const FACTORY = 'alias'; + public function __construct(ServicesConfigurator $parent, Alias $alias) { $this->parent = $parent; diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php index f2e5ccf8..73d8f559 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/ContainerConfigurator.php @@ -12,10 +12,12 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; use Symfony\Component\ExpressionLanguage\Expression; @@ -24,15 +26,16 @@ */ class ContainerConfigurator extends AbstractConfigurator { - const FACTORY = 'container'; + public const FACTORY = 'container'; private $container; private $loader; private $instanceof; private $path; private $file; + private $anonymousCount = 0; - public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, $path, $file) + public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path, string $file) { $this->container = $container; $this->loader = $loader; @@ -41,71 +44,65 @@ public function __construct(ContainerBuilder $container, PhpFileLoader $loader, $this->file = $file; } - final public function extension($namespace, array $config) + final public function extension(string $namespace, array $config) { if (!$this->container->hasExtension($namespace)) { - $extensions = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions())); + $extensions = array_filter(array_map(function (ExtensionInterface $ext) { return $ext->getAlias(); }, $this->container->getExtensions())); throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $namespace, $this->file, $namespace, $extensions ? implode('", "', $extensions) : 'none')); } $this->container->loadFromExtension($namespace, static::processValue($config)); } - final public function import($resource, $type = null, $ignoreErrors = false) + final public function import(string $resource, string $type = null, $ignoreErrors = false) { $this->loader->setCurrentDir(\dirname($this->path)); $this->loader->import($resource, $type, $ignoreErrors, $this->file); } - /** - * @return ParametersConfigurator - */ - final public function parameters() + final public function parameters(): ParametersConfigurator { return new ParametersConfigurator($this->container); } - /** - * @return ServicesConfigurator - */ - final public function services() + final public function services(): ServicesConfigurator { - return new ServicesConfigurator($this->container, $this->loader, $this->instanceof); + return new ServicesConfigurator($this->container, $this->loader, $this->instanceof, $this->path, $this->anonymousCount); } } /** * Creates a service reference. - * - * @param string $id - * - * @return ReferenceConfigurator */ -function ref($id) +function ref(string $id): ReferenceConfigurator { return new ReferenceConfigurator($id); } /** * Creates an inline service. - * - * @param string|null $class - * - * @return InlineServiceConfigurator */ -function inline($class = null) +function inline(string $class = null): InlineServiceConfigurator { return new InlineServiceConfigurator(new Definition($class)); } /** - * Creates a lazy iterator. + * Creates a service locator. * * @param ReferenceConfigurator[] $values + */ +function service_locator(array $values): ServiceLocatorArgument +{ + return new ServiceLocatorArgument(AbstractConfigurator::processValue($values, true)); +} + +/** + * Creates a lazy iterator. * - * @return IteratorArgument + * @param ReferenceConfigurator[] $values */ -function iterator(array $values) +function iterator(array $values): IteratorArgument { return new IteratorArgument(AbstractConfigurator::processValue($values, true)); } @@ -113,23 +110,35 @@ function iterator(array $values) /** * Creates a lazy iterator by tag name. * - * @param string $tag - * - * @return TaggedIteratorArgument + * @deprecated since Symfony 4.4, to be removed in 5.0, use "tagged_iterator" instead. */ -function tagged($tag) +function tagged(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null): TaggedIteratorArgument { - return new TaggedIteratorArgument($tag); + @trigger_error(__NAMESPACE__.'\tagged() is deprecated since Symfony 4.4 and will be removed in 5.0, use '.__NAMESPACE__.'\tagged_iterator() instead.', \E_USER_DEPRECATED); + + return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod); +} + +/** + * Creates a lazy iterator by tag name. + */ +function tagged_iterator(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null, string $defaultPriorityMethod = null): TaggedIteratorArgument +{ + return new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, false, $defaultPriorityMethod); +} + +/** + * Creates a service locator by tag name. + */ +function tagged_locator(string $tag, string $indexAttribute = null, string $defaultIndexMethod = null): ServiceLocatorArgument +{ + return new ServiceLocatorArgument(new TaggedIteratorArgument($tag, $indexAttribute, $defaultIndexMethod, true)); } /** * Creates an expression. - * - * @param string $expression an expression - * - * @return Expression */ -function expr($expression) +function expr(string $expression): Expression { return new Expression($expression); } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/DefaultsConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/DefaultsConfigurator.php index 662ba95d..49a92e5c 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/DefaultsConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/DefaultsConfigurator.php @@ -11,40 +11,45 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; /** * @author Nicolas Grekas - * - * @method InstanceofConfigurator instanceof(string $fqcn) */ class DefaultsConfigurator extends AbstractServiceConfigurator { - const FACTORY = 'defaults'; - use Traits\AutoconfigureTrait; use Traits\AutowireTrait; use Traits\BindTrait; use Traits\PublicTrait; + public const FACTORY = 'defaults'; + + private $path; + + public function __construct(ServicesConfigurator $parent, Definition $definition, string $path = null) + { + parent::__construct($parent, $definition, null, []); + + $this->path = $path; + } + /** * Adds a tag for this definition. * - * @param string $name The tag name - * @param array $attributes An array of attributes - * * @return $this * * @throws InvalidArgumentException when an invalid tag name or attribute is provided */ - final public function tag($name, array $attributes = []) + final public function tag(string $name, array $attributes = []): self { - if (!\is_string($name) || '' === $name) { + if ('' === $name) { throw new InvalidArgumentException('The tag name in "_defaults" must be a non-empty string.'); } foreach ($attributes as $attribute => $value) { - if (!is_scalar($value) && null !== $value) { + if (null !== $value && !is_scalar($value)) { throw new InvalidArgumentException(sprintf('Tag "%s", attribute "%s" in "_defaults" must be of a scalar-type.', $name, $attribute)); } } @@ -56,12 +61,8 @@ final public function tag($name, array $attributes = []) /** * Defines an instanceof-conditional to be applied to following service definitions. - * - * @param string $fqcn - * - * @return InstanceofConfigurator */ - final protected function setInstanceof($fqcn) + final public function instanceof(string $fqcn): InstanceofConfigurator { return $this->parent->instanceof($fqcn); } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/InlineServiceConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/InlineServiceConfigurator.php index 362b374e..32a703d2 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/InlineServiceConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/InlineServiceConfigurator.php @@ -18,8 +18,6 @@ */ class InlineServiceConfigurator extends AbstractConfigurator { - const FACTORY = 'inline'; - use Traits\ArgumentTrait; use Traits\AutowireTrait; use Traits\BindTrait; @@ -29,6 +27,12 @@ class InlineServiceConfigurator extends AbstractConfigurator use Traits\ParentTrait; use Traits\TagTrait; + public const FACTORY = 'inline'; + + private $id = '[inline]'; + private $allowParent = true; + private $path = null; + public function __construct(Definition $definition) { $this->definition = $definition; diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/InstanceofConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/InstanceofConfigurator.php index 629874d1..fbba6230 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/InstanceofConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/InstanceofConfigurator.php @@ -11,16 +11,15 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\DependencyInjection\Definition; + /** * @author Nicolas Grekas - * - * @method InstanceofConfigurator instanceof(string $fqcn) */ class InstanceofConfigurator extends AbstractServiceConfigurator { - const FACTORY = 'instanceof'; - use Traits\AutowireTrait; + use Traits\BindTrait; use Traits\CallTrait; use Traits\ConfiguratorTrait; use Traits\LazyTrait; @@ -29,14 +28,21 @@ class InstanceofConfigurator extends AbstractServiceConfigurator use Traits\ShareTrait; use Traits\TagTrait; + public const FACTORY = 'instanceof'; + + private $path; + + public function __construct(ServicesConfigurator $parent, Definition $definition, string $id, string $path = null) + { + parent::__construct($parent, $definition, $id, []); + + $this->path = $path; + } + /** * Defines an instanceof-conditional to be applied to following service definitions. - * - * @param string $fqcn - * - * @return self */ - final protected function setInstanceof($fqcn) + final public function instanceof(string $fqcn): self { return $this->parent->instanceof($fqcn); } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/ParametersConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/ParametersConfigurator.php index 9585b1a4..244da04f 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/ParametersConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/ParametersConfigurator.php @@ -18,7 +18,7 @@ */ class ParametersConfigurator extends AbstractConfigurator { - const FACTORY = 'parameters'; + public const FACTORY = 'parameters'; private $container; @@ -30,12 +30,9 @@ public function __construct(ContainerBuilder $container) /** * Creates a parameter. * - * @param string $name - * @param mixed $value - * * @return $this */ - final public function set($name, $value) + final public function set(string $name, $value): self { $this->container->setParameter($name, static::processValue($value, true)); @@ -45,12 +42,9 @@ final public function set($name, $value) /** * Creates a parameter. * - * @param string $name - * @param mixed $value - * * @return $this */ - final public function __invoke($name, $value) + final public function __invoke(string $name, $value): self { return $this->set($name, $value); } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/PrototypeConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/PrototypeConfigurator.php index 3d844798..e1b3702a 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/PrototypeConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/PrototypeConfigurator.php @@ -19,8 +19,6 @@ */ class PrototypeConfigurator extends AbstractServiceConfigurator { - const FACTORY = 'load'; - use Traits\AbstractTrait; use Traits\ArgumentTrait; use Traits\AutoconfigureTrait; @@ -37,12 +35,14 @@ class PrototypeConfigurator extends AbstractServiceConfigurator use Traits\ShareTrait; use Traits\TagTrait; + public const FACTORY = 'load'; + private $loader; private $resource; - private $exclude; + private $excludes; private $allowParent; - public function __construct(ServicesConfigurator $parent, PhpFileLoader $loader, Definition $defaults, $namespace, $resource, $allowParent) + public function __construct(ServicesConfigurator $parent, PhpFileLoader $loader, Definition $defaults, string $namespace, string $resource, bool $allowParent) { $definition = new Definition(); if (!$defaults->isPublic() || !$defaults->isPrivate()) { @@ -66,21 +66,21 @@ public function __destruct() parent::__destruct(); if ($this->loader) { - $this->loader->registerClasses($this->definition, $this->id, $this->resource, $this->exclude); + $this->loader->registerClasses($this->definition, $this->id, $this->resource, $this->excludes); } $this->loader = null; } /** - * Excludes files from registration using a glob pattern. + * Excludes files from registration using glob patterns. * - * @param string $exclude + * @param string[]|string $excludes * * @return $this */ - final public function exclude($exclude) + final public function exclude($excludes): self { - $this->exclude = $exclude; + $this->excludes = (array) $excludes; return $this; } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/ReferenceConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/ReferenceConfigurator.php index 1585c087..fa042538 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/ReferenceConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/ReferenceConfigurator.php @@ -24,7 +24,7 @@ class ReferenceConfigurator extends AbstractConfigurator /** @internal */ protected $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; - public function __construct($id) + public function __construct(string $id) { $this->id = $id; } @@ -32,7 +32,7 @@ public function __construct($id) /** * @return $this */ - final public function ignoreOnInvalid() + final public function ignoreOnInvalid(): self { $this->invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; @@ -42,7 +42,7 @@ final public function ignoreOnInvalid() /** * @return $this */ - final public function nullOnInvalid() + final public function nullOnInvalid(): self { $this->invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; @@ -52,13 +52,16 @@ final public function nullOnInvalid() /** * @return $this */ - final public function ignoreOnUninitialized() + final public function ignoreOnUninitialized(): self { $this->invalidBehavior = ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE; return $this; } + /** + * @return string + */ public function __toString() { return $this->id; diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/ServiceConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/ServiceConfigurator.php index 897dedaa..1dbc0a9a 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/ServiceConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/ServiceConfigurator.php @@ -20,8 +20,6 @@ */ class ServiceConfigurator extends AbstractServiceConfigurator { - const FACTORY = 'services'; - use Traits\AbstractTrait; use Traits\ArgumentTrait; use Traits\AutoconfigureTrait; @@ -42,15 +40,19 @@ class ServiceConfigurator extends AbstractServiceConfigurator use Traits\SyntheticTrait; use Traits\TagTrait; + public const FACTORY = 'services'; + private $container; private $instanceof; private $allowParent; + private $path; - public function __construct(ContainerBuilder $container, array $instanceof, $allowParent, ServicesConfigurator $parent, Definition $definition, $id, array $defaultTags) + public function __construct(ContainerBuilder $container, array $instanceof, bool $allowParent, ServicesConfigurator $parent, Definition $definition, ?string $id, array $defaultTags, string $path = null) { $this->container = $container; $this->instanceof = $instanceof; $this->allowParent = $allowParent; + $this->path = $path; parent::__construct($parent, $definition, $id, $defaultTags); } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/ServicesConfigurator.php b/vendor/symfony/dependency-injection/Loader/Configurator/ServicesConfigurator.php index b6ccbc63..511858f7 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/ServicesConfigurator.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/ServicesConfigurator.php @@ -20,88 +20,88 @@ /** * @author Nicolas Grekas - * - * @method InstanceofConfigurator instanceof($fqcn) */ class ServicesConfigurator extends AbstractConfigurator { - const FACTORY = 'services'; + public const FACTORY = 'services'; private $defaults; private $container; private $loader; private $instanceof; + private $path; + private $anonymousHash; + private $anonymousCount; - public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof) + public function __construct(ContainerBuilder $container, PhpFileLoader $loader, array &$instanceof, string $path = null, int &$anonymousCount = 0) { $this->defaults = new Definition(); $this->container = $container; $this->loader = $loader; $this->instanceof = &$instanceof; + $this->path = $path; + $this->anonymousHash = ContainerBuilder::hash($path ?: mt_rand()); + $this->anonymousCount = &$anonymousCount; $instanceof = []; } /** * Defines a set of defaults for following service definitions. - * - * @return DefaultsConfigurator */ - final public function defaults() + final public function defaults(): DefaultsConfigurator { - return new DefaultsConfigurator($this, $this->defaults = new Definition()); + return new DefaultsConfigurator($this, $this->defaults = new Definition(), $this->path); } /** * Defines an instanceof-conditional to be applied to following service definitions. - * - * @param string $fqcn - * - * @return InstanceofConfigurator */ - final protected function setInstanceof($fqcn) + final public function instanceof(string $fqcn): InstanceofConfigurator { $this->instanceof[$fqcn] = $definition = new ChildDefinition(''); - return new InstanceofConfigurator($this, $definition, $fqcn); + return new InstanceofConfigurator($this, $definition, $fqcn, $this->path); } /** * Registers a service. * - * @param string $id - * @param string|null $class - * - * @return ServiceConfigurator + * @param string|null $id The service id, or null to create an anonymous service + * @param string|null $class The class of the service, or null when $id is also the class name */ - final public function set($id, $class = null) + final public function set(?string $id, string $class = null): ServiceConfigurator { $defaults = $this->defaults; $allowParent = !$defaults->getChanges() && empty($this->instanceof); $definition = new Definition(); - if (!$defaults->isPublic() || !$defaults->isPrivate()) { + + if (null === $id) { + if (!$class) { + throw new \LogicException('Anonymous services must have a class name.'); + } + + $id = sprintf('.%d_%s', ++$this->anonymousCount, preg_replace('/^.*\\\\/', '', $class).'~'.$this->anonymousHash); + $definition->setPublic(false); + } elseif (!$defaults->isPublic() || !$defaults->isPrivate()) { $definition->setPublic($defaults->isPublic() && !$defaults->isPrivate()); } + $definition->setAutowired($defaults->isAutowired()); $definition->setAutoconfigured($defaults->isAutoconfigured()); // deep clone, to avoid multiple process of the same instance in the passes $definition->setBindings(unserialize(serialize($defaults->getBindings()))); $definition->setChanges([]); - $configurator = new ServiceConfigurator($this->container, $this->instanceof, $allowParent, $this, $definition, $id, $defaults->getTags()); + $configurator = new ServiceConfigurator($this->container, $this->instanceof, $allowParent, $this, $definition, $id, $defaults->getTags(), $this->path); return null !== $class ? $configurator->class($class) : $configurator; } /** * Creates an alias. - * - * @param string $id - * @param string $referencedId - * - * @return AliasConfigurator */ - final public function alias($id, $referencedId) + final public function alias(string $id, string $referencedId): AliasConfigurator { $ref = static::processValue($referencedId, true); $alias = new Alias((string) $ref); @@ -115,13 +115,8 @@ final public function alias($id, $referencedId) /** * Registers a PSR-4 namespace using a glob pattern. - * - * @param string $namespace - * @param string $resource - * - * @return PrototypeConfigurator */ - final public function load($namespace, $resource) + final public function load(string $namespace, string $resource): PrototypeConfigurator { $allowParent = !$this->defaults->getChanges() && empty($this->instanceof); @@ -131,13 +126,9 @@ final public function load($namespace, $resource) /** * Gets an already defined service definition. * - * @param string $id - * - * @return ServiceConfigurator - * * @throws ServiceNotFoundException if the service definition does not exist */ - final public function get($id) + final public function get(string $id): ServiceConfigurator { $allowParent = !$this->defaults->getChanges() && empty($this->instanceof); $definition = $this->container->getDefinition($id); @@ -147,14 +138,14 @@ final public function get($id) /** * Registers a service. - * - * @param string $id - * @param string|null $class - * - * @return ServiceConfigurator */ - final public function __invoke($id, $class = null) + final public function __invoke(string $id, string $class = null): ServiceConfigurator { return $this->set($id, $class); } + + public function __destruct() + { + $this->loader->registerAliasesForSinglyImplementedInterfaces(); + } } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AbstractTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AbstractTrait.php index f69a7a5b..82ba21d7 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AbstractTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AbstractTrait.php @@ -11,20 +11,15 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; -/** - * @method $this abstract(bool $abstract = true) - */ trait AbstractTrait { /** * Whether this definition is abstract, that means it merely serves as a * template for other definitions. * - * @param bool $abstract - * * @return $this */ - final protected function setAbstract($abstract = true) + final public function abstract(bool $abstract = true): self { $this->definition->setAbstract($abstract); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ArgumentTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ArgumentTrait.php index 7ec8c51d..5c9a4756 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ArgumentTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ArgumentTrait.php @@ -16,11 +16,9 @@ trait ArgumentTrait /** * Sets the arguments to pass to the service constructor/factory method. * - * @param array $arguments An array of arguments - * * @return $this */ - final public function args(array $arguments) + final public function args(array $arguments): self { $this->definition->setArguments(static::processValue($arguments, true)); @@ -35,7 +33,7 @@ final public function args(array $arguments) * * @return $this */ - final public function arg($key, $value) + final public function arg($key, $value): self { $this->definition->setArgument($key, static::processValue($value, true)); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutoconfigureTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutoconfigureTrait.php index 42a69235..836f4587 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutoconfigureTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutoconfigureTrait.php @@ -19,13 +19,11 @@ trait AutoconfigureTrait /** * Sets whether or not instanceof conditionals should be prepended with a global set. * - * @param bool $autoconfigured - * * @return $this * * @throws InvalidArgumentException when a parent is already set */ - final public function autoconfigure($autoconfigured = true) + final public function autoconfigure(bool $autoconfigured = true): self { if ($autoconfigured && $this->definition instanceof ChildDefinition) { throw new InvalidArgumentException(sprintf('The service "%s" cannot have a "parent" and also have "autoconfigure". Try disabling autoconfiguration for the service.', $this->id)); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutowireTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutowireTrait.php index 3d4b2e85..2837a020 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutowireTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/AutowireTrait.php @@ -16,11 +16,9 @@ trait AutowireTrait /** * Enables/disables autowiring. * - * @param bool $autowired - * * @return $this */ - final public function autowire($autowired = true) + final public function autowire(bool $autowired = true): self { $this->definition->setAutowired($autowired); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/BindTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/BindTrait.php index 4511ed65..3021e070 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/BindTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/BindTrait.php @@ -11,8 +11,9 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; -use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Argument\BoundArgument; +use Symfony\Component\DependencyInjection\Loader\Configurator\DefaultsConfigurator; +use Symfony\Component\DependencyInjection\Loader\Configurator\InstanceofConfigurator; trait BindTrait { @@ -23,19 +24,17 @@ trait BindTrait * injected in the matching parameters (of the constructor, of methods * called and of controller actions). * - * @param string $nameOrFqcn A parameter name with its "$" prefix, or a FQCN + * @param string $nameOrFqcn A parameter name with its "$" prefix, or an FQCN * @param mixed $valueOrRef The value or reference to bind * * @return $this */ - final public function bind($nameOrFqcn, $valueOrRef) + final public function bind(string $nameOrFqcn, $valueOrRef): self { $valueOrRef = static::processValue($valueOrRef, true); - if (isset($nameOrFqcn[0]) && '$' !== $nameOrFqcn[0] && !$valueOrRef instanceof Reference) { - throw new InvalidArgumentException(sprintf('Invalid binding for service "%s": named arguments must start with a "$", and FQCN must map to references. Neither applies to binding "%s".', $this->id, $nameOrFqcn)); - } $bindings = $this->definition->getBindings(); - $bindings[$nameOrFqcn] = $valueOrRef; + $type = $this instanceof DefaultsConfigurator ? BoundArgument::DEFAULTS_BINDING : ($this instanceof InstanceofConfigurator ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING); + $bindings[$nameOrFqcn] = new BoundArgument($valueOrRef, true, $type, $this->path ?? null); $this->definition->setBindings($bindings); return $this; diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/CallTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/CallTrait.php index 8e6b17a1..28f92d27 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/CallTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/CallTrait.php @@ -18,16 +18,17 @@ trait CallTrait /** * Adds a method to call after service initialization. * - * @param string $method The method name to call - * @param array $arguments An array of arguments to pass to the method call + * @param string $method The method name to call + * @param array $arguments An array of arguments to pass to the method call + * @param bool $returnsClone Whether the call returns the service instance or not * * @return $this * * @throws InvalidArgumentException on empty $method param */ - final public function call($method, array $arguments = []) + final public function call(string $method, array $arguments = [], bool $returnsClone = false): self { - $this->definition->addMethodCall($method, static::processValue($arguments, true)); + $this->definition->addMethodCall($method, static::processValue($arguments, true), $returnsClone); return $this; } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ClassTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ClassTrait.php index ae5b1c0a..20da791a 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ClassTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ClassTrait.php @@ -11,19 +11,14 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; -/** - * @method $this class(string $class) - */ trait ClassTrait { /** * Sets the service class. * - * @param string $class The service class - * * @return $this */ - final protected function setClass($class) + final public function class(?string $class): self { $this->definition->setClass($class); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ConfiguratorTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ConfiguratorTrait.php index a38283b0..25d363c9 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ConfiguratorTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ConfiguratorTrait.php @@ -20,7 +20,7 @@ trait ConfiguratorTrait * * @return $this */ - final public function configurator($configurator) + final public function configurator($configurator): self { $this->definition->setConfigurator(static::processValue($configurator, true)); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DecorateTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DecorateTrait.php index 173ad15f..222cf758 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DecorateTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DecorateTrait.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; trait DecorateTrait @@ -18,17 +19,18 @@ trait DecorateTrait /** * Sets the service that this service is decorating. * - * @param string|null $id The decorated service id, use null to remove decoration - * @param string|null $renamedId The new decorated service id - * @param int $priority The priority of decoration + * @param string|null $id The decorated service id, use null to remove decoration + * @param string|null $renamedId The new decorated service id + * @param int $priority The priority of decoration + * @param int $invalidBehavior The behavior to adopt when decorated is invalid * * @return $this * * @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals */ - final public function decorate($id, $renamedId = null, $priority = 0) + final public function decorate(?string $id, string $renamedId = null, int $priority = 0, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE): self { - $this->definition->setDecoratedService($id, $renamedId, $priority); + $this->definition->setDecoratedService($id, $renamedId, $priority, $invalidBehavior); return $this; } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DeprecateTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DeprecateTrait.php index b14a6557..b2d5b0eb 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DeprecateTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/DeprecateTrait.php @@ -24,7 +24,7 @@ trait DeprecateTrait * * @throws InvalidArgumentException when the message template is invalid */ - final public function deprecate($template = null) + final public function deprecate(string $template = null): self { $this->definition->setDeprecated(true, $template); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FactoryTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FactoryTrait.php index 0d50fb74..9968d77a 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FactoryTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FactoryTrait.php @@ -12,22 +12,23 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator; trait FactoryTrait { /** * Sets a factory. * - * @param string|array $factory A PHP callable reference + * @param string|array|ReferenceConfigurator $factory A PHP callable reference * * @return $this */ - final public function factory($factory) + final public function factory($factory): self { if (\is_string($factory) && 1 === substr_count($factory, ':')) { $factoryParts = explode(':', $factory); - throw new InvalidArgumentException(sprintf('Invalid factory "%s": the `service:method` notation is not available when using PHP-based DI configuration. Use "[ref(\'%s\'), \'%s\']" instead.', $factory, $factoryParts[0], $factoryParts[1])); + throw new InvalidArgumentException(sprintf('Invalid factory "%s": the "service:method" notation is not available when using PHP-based DI configuration. Use "[ref(\'%s\'), \'%s\']" instead.', $factory, $factoryParts[0], $factoryParts[1])); } $this->definition->setFactory(static::processValue($factory, true)); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FileTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FileTrait.php index 895f5304..5f42aef8 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FileTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/FileTrait.php @@ -16,11 +16,9 @@ trait FileTrait /** * Sets a file to require before creating the service. * - * @param string $file A full pathname to include - * * @return $this */ - final public function file($file) + final public function file(string $file): self { $this->definition->setFile($file); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/LazyTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/LazyTrait.php index d7ea8b27..2829defb 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/LazyTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/LazyTrait.php @@ -16,13 +16,16 @@ trait LazyTrait /** * Sets the lazy flag of this service. * - * @param bool $lazy + * @param bool|string $lazy A FQCN to derivate the lazy proxy from or `true` to make it extend from the definition's class * * @return $this */ - final public function lazy($lazy = true) + final public function lazy($lazy = true): self { - $this->definition->setLazy($lazy); + $this->definition->setLazy((bool) $lazy); + if (\is_string($lazy)) { + $this->definition->addTag('proxy', ['interface' => $lazy]); + } return $this; } diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ParentTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ParentTrait.php index 43f1223e..7488a38c 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ParentTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ParentTrait.php @@ -14,21 +14,16 @@ use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; -/** - * @method $this parent(string $parent) - */ trait ParentTrait { /** * Sets the Definition to inherit from. * - * @param string $parent - * * @return $this * * @throws InvalidArgumentException when parent cannot be set */ - final protected function setParent($parent) + final public function parent(string $parent): self { if (!$this->allowParent) { throw new InvalidArgumentException(sprintf('A parent cannot be defined when either "_instanceof" or "_defaults" are also defined for service prototype "%s".', $this->id)); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PropertyTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PropertyTrait.php index d5d93870..10fdcfb8 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PropertyTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PropertyTrait.php @@ -16,12 +16,9 @@ trait PropertyTrait /** * Sets a specific property. * - * @param string $name - * @param mixed $value - * * @return $this */ - final public function property($name, $value) + final public function property(string $name, $value): self { $this->definition->setProperty($name, static::processValue($value, true)); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PublicTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PublicTrait.php index 8f7f79f1..f15756c1 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PublicTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/PublicTrait.php @@ -11,16 +11,12 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; -/** - * @method $this public() - * @method $this private() - */ trait PublicTrait { /** * @return $this */ - final protected function setPublic() + final public function public(): self { $this->definition->setPublic(true); @@ -30,7 +26,7 @@ final protected function setPublic() /** * @return $this */ - final protected function setPrivate() + final public function private(): self { $this->definition->setPublic(false); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ShareTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ShareTrait.php index 1c2f97b5..16fde0f2 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ShareTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/ShareTrait.php @@ -16,11 +16,9 @@ trait ShareTrait /** * Sets if the service must be shared or not. * - * @param bool $shared Whether the service must be shared or not - * * @return $this */ - final public function share($shared = true) + final public function share(bool $shared = true): self { $this->definition->setShared($shared); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/SyntheticTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/SyntheticTrait.php index 81eceff4..cb08b113 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/SyntheticTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/SyntheticTrait.php @@ -17,11 +17,9 @@ trait SyntheticTrait * Sets whether this definition is synthetic, that is not constructed by the * container, but dynamically injected. * - * @param bool $synthetic - * * @return $this */ - final public function synthetic($synthetic = true) + final public function synthetic(bool $synthetic = true): self { $this->definition->setSynthetic($synthetic); diff --git a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/TagTrait.php b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/TagTrait.php index d17339f8..f4d5f002 100644 --- a/vendor/symfony/dependency-injection/Loader/Configurator/Traits/TagTrait.php +++ b/vendor/symfony/dependency-injection/Loader/Configurator/Traits/TagTrait.php @@ -18,14 +18,11 @@ trait TagTrait /** * Adds a tag for this definition. * - * @param string $name The tag name - * @param array $attributes An array of attributes - * * @return $this */ - final public function tag($name, array $attributes = []) + final public function tag(string $name, array $attributes = []): self { - if (!\is_string($name) || '' === $name) { + if ('' === $name) { throw new InvalidArgumentException(sprintf('The tag name for service "%s" must be a non-empty string.', $this->id)); } diff --git a/vendor/symfony/dependency-injection/Loader/DirectoryLoader.php b/vendor/symfony/dependency-injection/Loader/DirectoryLoader.php index a57cac3b..15d50a38 100644 --- a/vendor/symfony/dependency-injection/Loader/DirectoryLoader.php +++ b/vendor/symfony/dependency-injection/Loader/DirectoryLoader.php @@ -49,6 +49,6 @@ public function supports($resource, $type = null) return true; } - return null === $type && \is_string($resource) && '/' === substr($resource, -1); + return null === $type && \is_string($resource) && str_ends_with($resource, '/'); } } diff --git a/vendor/symfony/dependency-injection/Loader/FileLoader.php b/vendor/symfony/dependency-injection/Loader/FileLoader.php index 749dd4d0..d5a6e2e5 100644 --- a/vendor/symfony/dependency-injection/Loader/FileLoader.php +++ b/vendor/symfony/dependency-injection/Loader/FileLoader.php @@ -11,8 +11,11 @@ namespace Symfony\Component\DependencyInjection\Loader; +use Symfony\Component\Config\Exception\FileLocatorFileNotFoundException; +use Symfony\Component\Config\Exception\LoaderLoadException; use Symfony\Component\Config\FileLocatorInterface; use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader; +use Symfony\Component\Config\Loader\Loader; use Symfony\Component\Config\Resource\GlobResource; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -26,9 +29,14 @@ */ abstract class FileLoader extends BaseFileLoader { + public const ANONYMOUS_ID_REGEXP = '/^\.\d+_[^~]*+~[._a-zA-Z\d]{7}$/'; + protected $container; protected $isLoadingInstanceof = false; protected $instanceof = []; + protected $interfaces = []; + protected $singlyImplemented = []; + protected $autoRegisterAliasesForSinglyImplementedInterfaces = true; public function __construct(ContainerBuilder $container, FileLocatorInterface $locator) { @@ -37,32 +45,66 @@ public function __construct(ContainerBuilder $container, FileLocatorInterface $l parent::__construct($locator); } + /** + * {@inheritdoc} + * + * @param bool|string $ignoreErrors Whether errors should be ignored; pass "not_found" to ignore only when the loaded resource is not found + * @param string|string[]|null $exclude Glob patterns to exclude from the import + */ + public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null/*, $exclude = null*/) + { + $args = \func_get_args(); + + if ($ignoreNotFound = 'not_found' === $ignoreErrors) { + $args[2] = false; + } elseif (!\is_bool($ignoreErrors)) { + @trigger_error(sprintf('Invalid argument $ignoreErrors provided to %s::import(): boolean or "not_found" expected, %s given.', static::class, \gettype($ignoreErrors)), \E_USER_DEPRECATED); + $args[2] = (bool) $ignoreErrors; + } + + try { + parent::import(...$args); + } catch (LoaderLoadException $e) { + if (!$ignoreNotFound || !($prev = $e->getPrevious()) instanceof FileLocatorFileNotFoundException) { + throw $e; + } + + foreach ($prev->getTrace() as $frame) { + if ('import' === ($frame['function'] ?? null) && is_a($frame['class'] ?? '', Loader::class, true)) { + break; + } + } + + if (__FILE__ !== $frame['file']) { + throw $e; + } + } + } + /** * Registers a set of classes as services using PSR-4 for discovery. * - * @param Definition $prototype A definition to use as template - * @param string $namespace The namespace prefix of classes in the scanned directory - * @param string $resource The directory to look for classes, glob-patterns allowed - * @param string $exclude A globed path of files to exclude + * @param Definition $prototype A definition to use as template + * @param string $namespace The namespace prefix of classes in the scanned directory + * @param string $resource The directory to look for classes, glob-patterns allowed + * @param string|string[]|null $exclude A globbed path of files to exclude or an array of globbed paths of files to exclude */ public function registerClasses(Definition $prototype, $namespace, $resource, $exclude = null) { - if ('\\' !== substr($namespace, -1)) { + if (!str_ends_with($namespace, '\\')) { throw new InvalidArgumentException(sprintf('Namespace prefix must end with a "\\": "%s".', $namespace)); } if (!preg_match('/^(?:[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+\\\\)++$/', $namespace)) { throw new InvalidArgumentException(sprintf('Namespace is not a valid PSR-4 prefix: "%s".', $namespace)); } - $classes = $this->findClasses($namespace, $resource, $exclude); + $classes = $this->findClasses($namespace, $resource, (array) $exclude); // prepare for deep cloning $serializedPrototype = serialize($prototype); - $interfaces = []; - $singlyImplemented = []; foreach ($classes as $class => $errorMessage) { if (interface_exists($class, false)) { - $interfaces[] = $class; + $this->interfaces[] = $class; } else { $this->setDefinition($class, $definition = unserialize($serializedPrototype)); if (null !== $errorMessage) { @@ -71,16 +113,25 @@ public function registerClasses(Definition $prototype, $namespace, $resource, $e continue; } foreach (class_implements($class, false) as $interface) { - $singlyImplemented[$interface] = isset($singlyImplemented[$interface]) ? false : $class; + $this->singlyImplemented[$interface] = ($this->singlyImplemented[$interface] ?? $class) !== $class ? false : $class; } } } - foreach ($interfaces as $interface) { - if (!empty($singlyImplemented[$interface])) { - $this->container->setAlias($interface, $singlyImplemented[$interface]) - ->setPublic(false); + + if ($this->autoRegisterAliasesForSinglyImplementedInterfaces) { + $this->registerAliasesForSinglyImplementedInterfaces(); + } + } + + public function registerAliasesForSinglyImplementedInterfaces() + { + foreach ($this->interfaces as $interface) { + if (!empty($this->singlyImplemented[$interface]) && !$this->container->has($interface)) { + $this->container->setAlias($interface, $this->singlyImplemented[$interface])->setPublic(false); } } + + $this->interfaces = $this->singlyImplemented = []; } /** @@ -102,33 +153,33 @@ protected function setDefinition($id, Definition $definition) } } - private function findClasses($namespace, $pattern, $excludePattern) + private function findClasses(string $namespace, string $pattern, array $excludePatterns): array { $parameterBag = $this->container->getParameterBag(); $excludePaths = []; $excludePrefix = null; - if ($excludePattern) { - $excludePattern = $parameterBag->unescapeValue($parameterBag->resolveValue($excludePattern)); - foreach ($this->glob($excludePattern, true, $resource, true) as $path => $info) { + $excludePatterns = $parameterBag->unescapeValue($parameterBag->resolveValue($excludePatterns)); + foreach ($excludePatterns as $excludePattern) { + foreach ($this->glob($excludePattern, true, $resource, true, true) as $path => $info) { if (null === $excludePrefix) { $excludePrefix = $resource->getPrefix(); } - // normalize Windows slashes - $excludePaths[str_replace('\\', '/', $path)] = true; + // normalize Windows slashes and remove trailing slashes + $excludePaths[rtrim(str_replace('\\', '/', $path), '/')] = true; } } $pattern = $parameterBag->unescapeValue($parameterBag->resolveValue($pattern)); $classes = []; - $extRegexp = \defined('HHVM_VERSION') ? '/\\.(?:php|hh)$/' : '/\\.php$/'; + $extRegexp = '/\\.php$/'; $prefixLen = null; - foreach ($this->glob($pattern, true, $resource) as $path => $info) { + foreach ($this->glob($pattern, true, $resource, false, false, $excludePaths) as $path => $info) { if (null === $prefixLen) { $prefixLen = \strlen($resource->getPrefix()); - if ($excludePrefix && 0 !== strpos($excludePrefix, $resource->getPrefix())) { + if ($excludePrefix && !str_starts_with($excludePrefix, $resource->getPrefix())) { throw new InvalidArgumentException(sprintf('Invalid "exclude" pattern when importing classes for "%s": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s).', $namespace, $excludePattern, $pattern)); } } diff --git a/vendor/symfony/dependency-injection/Loader/IniFileLoader.php b/vendor/symfony/dependency-injection/Loader/IniFileLoader.php index 6c07c673..db2ed51b 100644 --- a/vendor/symfony/dependency-injection/Loader/IniFileLoader.php +++ b/vendor/symfony/dependency-injection/Loader/IniFileLoader.php @@ -66,8 +66,10 @@ public function supports($resource, $type = null) * Note that the following features are not supported: * * strings with escaped quotes are not supported "foo\"bar"; * * string concatenation ("foo" "bar"). + * + * @return mixed */ - private function phpize($value) + private function phpize(string $value) { // trim on the right as comments removal keep whitespaces if ($value !== $v = rtrim($value)) { diff --git a/vendor/symfony/dependency-injection/Loader/PhpFileLoader.php b/vendor/symfony/dependency-injection/Loader/PhpFileLoader.php index ddb671ff..2ace5d57 100644 --- a/vendor/symfony/dependency-injection/Loader/PhpFileLoader.php +++ b/vendor/symfony/dependency-injection/Loader/PhpFileLoader.php @@ -23,6 +23,8 @@ */ class PhpFileLoader extends FileLoader { + protected $autoRegisterAliasesForSinglyImplementedInterfaces = false; + /** * {@inheritdoc} */ @@ -41,10 +43,15 @@ public function load($resource, $type = null) return include $path; }, $this, ProtectedPhpFileLoader::class); - $callback = $load($path); + try { + $callback = $load($path); - if ($callback instanceof \Closure) { - $callback(new ContainerConfigurator($this->container, $this, $this->instanceof, $path, $resource), $this->container, $this); + if (\is_object($callback) && \is_callable($callback)) { + $callback(new ContainerConfigurator($this->container, $this, $this->instanceof, $path, $resource), $this->container, $this); + } + } finally { + $this->instanceof = []; + $this->registerAliasesForSinglyImplementedInterfaces(); } } diff --git a/vendor/symfony/dependency-injection/Loader/XmlFileLoader.php b/vendor/symfony/dependency-injection/Loader/XmlFileLoader.php index 0ff54ee6..fdf4fa1f 100644 --- a/vendor/symfony/dependency-injection/Loader/XmlFileLoader.php +++ b/vendor/symfony/dependency-injection/Loader/XmlFileLoader.php @@ -15,6 +15,8 @@ use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -22,6 +24,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\ExpressionLanguage\Expression; @@ -32,7 +35,9 @@ */ class XmlFileLoader extends FileLoader { - const NS = 'http://symfony.com/schema/dic/services'; + public const NS = 'http://symfony.com/schema/dic/services'; + + protected $autoRegisterAliasesForSinglyImplementedInterfaces = false; /** * {@inheritdoc} @@ -48,7 +53,7 @@ public function load($resource, $type = null) $defaults = $this->getServiceDefaults($xml, $path); // anonymous services - $this->processAnonymousServices($xml, $path, $defaults); + $this->processAnonymousServices($xml, $path); // imports $this->parseImports($xml, $path); @@ -64,6 +69,7 @@ public function load($resource, $type = null) $this->parseDefinitions($xml, $path, $defaults); } finally { $this->instanceof = []; + $this->registerAliasesForSinglyImplementedInterfaces(); } } @@ -83,24 +89,14 @@ public function supports($resource, $type = null) return 'xml' === $type; } - /** - * Parses parameters. - * - * @param string $file - */ - private function parseParameters(\DOMDocument $xml, $file) + private function parseParameters(\DOMDocument $xml, string $file) { if ($parameters = $this->getChildren($xml->documentElement, 'parameters')) { $this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter', $file)); } } - /** - * Parses imports. - * - * @param string $file - */ - private function parseImports(\DOMDocument $xml, $file) + private function parseImports(\DOMDocument $xml, string $file) { $xpath = new \DOMXPath($xml); $xpath->registerNamespace('container', self::NS); @@ -112,16 +108,11 @@ private function parseImports(\DOMDocument $xml, $file) $defaultDirectory = \dirname($file); foreach ($imports as $import) { $this->setCurrentDir($defaultDirectory); - $this->import($import->getAttribute('resource'), XmlUtils::phpize($import->getAttribute('type')) ?: null, (bool) XmlUtils::phpize($import->getAttribute('ignore-errors')), $file); + $this->import($import->getAttribute('resource'), XmlUtils::phpize($import->getAttribute('type')) ?: null, XmlUtils::phpize($import->getAttribute('ignore-errors')) ?: false, $file); } } - /** - * Parses multiple definitions. - * - * @param string $file - */ - private function parseDefinitions(\DOMDocument $xml, $file, $defaults) + private function parseDefinitions(\DOMDocument $xml, string $file, array $defaults) { $xpath = new \DOMXPath($xml); $xpath->registerNamespace('container', self::NS); @@ -142,7 +133,14 @@ private function parseDefinitions(\DOMDocument $xml, $file, $defaults) foreach ($services as $service) { if (null !== $definition = $this->parseDefinition($service, $file, $defaults)) { if ('prototype' === $service->tagName) { - $this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), (string) $service->getAttribute('exclude')); + $excludes = array_column($this->getChildren($service, 'exclude'), 'nodeValue'); + if ($service->hasAttribute('exclude')) { + if (\count($excludes) > 0) { + throw new InvalidArgumentException('You cannot use both the attribute "exclude" and tags at the same time.'); + } + $excludes = [$service->getAttribute('exclude')]; + } + $this->registerClasses($definition, (string) $service->getAttribute('namespace'), (string) $service->getAttribute('resource'), $excludes); } else { $this->setDefinition((string) $service->getAttribute('id'), $definition); } @@ -152,10 +150,8 @@ private function parseDefinitions(\DOMDocument $xml, $file, $defaults) /** * Get service defaults. - * - * @return array */ - private function getServiceDefaults(\DOMDocument $xml, $file) + private function getServiceDefaults(\DOMDocument $xml, string $file): array { $xpath = new \DOMXPath($xml); $xpath->registerNamespace('container', self::NS); @@ -163,9 +159,15 @@ private function getServiceDefaults(\DOMDocument $xml, $file) if (null === $defaultsNode = $xpath->query('//container:services/container:defaults')->item(0)) { return []; } + + $bindings = []; + foreach ($this->getArgumentsAsPhp($defaultsNode, 'bind', $file) as $argument => $value) { + $bindings[$argument] = new BoundArgument($value, true, BoundArgument::DEFAULTS_BINDING, $file); + } + $defaults = [ 'tags' => $this->getChildren($defaultsNode, 'tag'), - 'bind' => array_map(function ($v) { return new BoundArgument($v); }, $this->getArgumentsAsPhp($defaultsNode, 'bind', $file)), + 'bind' => $bindings, ]; foreach ($defaults['tags'] as $tag) { @@ -189,23 +191,23 @@ private function getServiceDefaults(\DOMDocument $xml, $file) /** * Parses an individual Definition. - * - * @param string $file - * - * @return Definition|null */ - private function parseDefinition(\DOMElement $service, $file, array $defaults) + private function parseDefinition(\DOMElement $service, string $file, array $defaults): ?Definition { if ($alias = $service->getAttribute('alias')) { $this->validateAlias($service, $file); - $this->container->setAlias((string) $service->getAttribute('id'), $alias = new Alias($alias)); + $this->container->setAlias($service->getAttribute('id'), $alias = new Alias($alias)); if ($publicAttr = $service->getAttribute('public')) { $alias->setPublic(XmlUtils::phpize($publicAttr)); } elseif (isset($defaults['public'])) { $alias->setPublic($defaults['public']); } + if ($deprecated = $this->getChildren($service, 'deprecated')) { + $alias->setDeprecated(true, $deprecated[0]->nodeValue ?: null); + } + return null; } @@ -251,10 +253,17 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $definition->setChanges([]); } - foreach (['class', 'public', 'shared', 'synthetic', 'lazy', 'abstract'] as $key) { + foreach (['class', 'public', 'shared', 'synthetic', 'abstract'] as $key) { if ($value = $service->getAttribute($key)) { $method = 'set'.$key; - $definition->$method(XmlUtils::phpize($value)); + $definition->$method($value = XmlUtils::phpize($value)); + } + } + + if ($value = $service->getAttribute('lazy')) { + $definition->setLazy((bool) $value = XmlUtils::phpize($value)); + if (\is_string($value)) { + $definition->addTag('proxy', ['interface' => $value]); } } @@ -292,7 +301,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $class = $factory->hasAttribute('class') ? $factory->getAttribute('class') : null; } - $definition->setFactory([$class, $factory->getAttribute('method')]); + $definition->setFactory([$class, $factory->getAttribute('method') ?: '__invoke']); } } @@ -307,12 +316,12 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $class = $configurator->getAttribute('class'); } - $definition->setConfigurator([$class, $configurator->getAttribute('method')]); + $definition->setConfigurator([$class, $configurator->getAttribute('method') ?: '__invoke']); } } foreach ($this->getChildren($service, 'call') as $call) { - $definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument', $file)); + $definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument', $file), XmlUtils::phpize($call->getAttribute('returns-clone'))); } $tags = $this->getChildren($service, 'tag'); @@ -328,7 +337,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) continue; } - if (false !== strpos($name, '-') && false === strpos($name, '_') && !\array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) { + if (str_contains($name, '-') && !str_contains($name, '_') && !\array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) { $parameters[$normalizedName] = XmlUtils::phpize($node->nodeValue); } // keep not normalized key @@ -336,17 +345,18 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) } if ('' === $tag->getAttribute('name')) { - throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', (string) $service->getAttribute('id'), $file)); + throw new InvalidArgumentException(sprintf('The tag name for service "%s" in "%s" must be a non-empty string.', $service->getAttribute('id'), $file)); } $definition->addTag($tag->getAttribute('name'), $parameters); } - foreach ($this->getChildren($service, 'autowiring-type') as $type) { - $definition->addAutowiringType($type->textContent); + $bindings = $this->getArgumentsAsPhp($service, 'bind', $file); + $bindingType = $this->isLoadingInstanceof ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING; + foreach ($bindings as $argument => $value) { + $bindings[$argument] = new BoundArgument($value, true, $bindingType, $file); } - $bindings = $this->getArgumentsAsPhp($service, 'bind', $file); if (isset($defaults['bind'])) { // deep clone, to avoid multiple process of the same instance in the passes $bindings = array_merge(unserialize(serialize($defaults['bind'])), $bindings); @@ -355,25 +365,33 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $definition->setBindings($bindings); } - if ($value = $service->getAttribute('decorates')) { + if ($decorates = $service->getAttribute('decorates')) { + $decorationOnInvalid = $service->getAttribute('decoration-on-invalid') ?: 'exception'; + if ('exception' === $decorationOnInvalid) { + $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + } elseif ('ignore' === $decorationOnInvalid) { + $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; + } elseif ('null' === $decorationOnInvalid) { + $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; + } else { + throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration-on-invalid" on service "%s". Did you mean "exception", "ignore" or "null" in "%s"?', $decorationOnInvalid, $service->getAttribute('id'), $file)); + } + $renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null; $priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0; - $definition->setDecoratedService($value, $renameId, $priority); + + $definition->setDecoratedService($decorates, $renameId, $priority, $invalidBehavior); } return $definition; } /** - * Parses a XML file to a \DOMDocument. - * - * @param string $file Path to a file - * - * @return \DOMDocument + * Parses an XML file to a \DOMDocument. * * @throws InvalidArgumentException When loading of XML file returns error */ - private function parseFileToDOM($file) + private function parseFileToDOM(string $file): \DOMDocument { try { $dom = XmlUtils::loadFile($file, [$this, 'validateSchema']); @@ -388,11 +406,8 @@ private function parseFileToDOM($file) /** * Processes anonymous services. - * - * @param string $file - * @param array $defaults */ - private function processAnonymousServices(\DOMDocument $xml, $file, $defaults) + private function processAnonymousServices(\DOMDocument $xml, string $file) { $definitions = []; $count = 0; @@ -406,11 +421,11 @@ private function processAnonymousServices(\DOMDocument $xml, $file, $defaults) foreach ($nodes as $node) { if ($services = $this->getChildren($node, 'service')) { // give it a unique name - $id = sprintf('%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $services[0]->getAttribute('class')).$suffix); + $id = sprintf('.%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $services[0]->getAttribute('class')).$suffix); $node->setAttribute('id', $id); $node->setAttribute('service', $id); - $definitions[$id] = [$services[0], $file, false]; + $definitions[$id] = [$services[0], $file]; $services[0]->setAttribute('id', $id); // anonymous services are always private @@ -423,39 +438,20 @@ private function processAnonymousServices(\DOMDocument $xml, $file, $defaults) // anonymous services "in the wild" if (false !== $nodes = $xpath->query('//container:services/container:service[not(@id)]')) { foreach ($nodes as $node) { - @trigger_error(sprintf('Top-level anonymous services are deprecated since Symfony 3.4, the "id" attribute will be required in version 4.0 in %s at line %d.', $file, $node->getLineNo()), \E_USER_DEPRECATED); - - // give it a unique name - $id = sprintf('%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $node->getAttribute('class')).$suffix); - $node->setAttribute('id', $id); - $definitions[$id] = [$node, $file, true]; + throw new InvalidArgumentException(sprintf('Top-level services must have "id" attribute, none found in "%s" at line %d.', $file, $node->getLineNo())); } } // resolve definitions uksort($definitions, 'strnatcmp'); - foreach (array_reverse($definitions) as $id => list($domElement, $file, $wild)) { - if (null !== $definition = $this->parseDefinition($domElement, $file, $wild ? $defaults : [])) { + foreach (array_reverse($definitions) as $id => [$domElement, $file]) { + if (null !== $definition = $this->parseDefinition($domElement, $file, [])) { $this->setDefinition($id, $definition); } - - if (true === $wild) { - $tmpDomElement = new \DOMElement('_services', null, self::NS); - $domElement->parentNode->replaceChild($tmpDomElement, $domElement); - $tmpDomElement->setAttribute('id', $id); - } } } - /** - * Returns arguments as valid php types. - * - * @param string $name - * @param string $file - * - * @return mixed - */ - private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $isChildDefinition = false) + private function getArgumentsAsPhp(\DOMElement $node, string $name, string $file, bool $isChildDefinition = false): array { $arguments = []; foreach ($this->getChildren($node, $name) as $arg) { @@ -491,15 +487,12 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $isChildDefi if ('' === $arg->getAttribute('id')) { throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service" has no or empty "id" attribute in "%s".', $name, $file)); } - if ($arg->hasAttribute('strict')) { - @trigger_error(sprintf('The "strict" attribute used when referencing the "%s" service is deprecated since Symfony 3.3 and will be removed in 4.0.', $arg->getAttribute('id')), \E_USER_DEPRECATED); - } $arguments[$key] = new Reference($arg->getAttribute('id'), $invalidBehavior); break; case 'expression': if (!class_exists(Expression::class)) { - throw new \LogicException(sprintf('The type="expression" attribute cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".')); + throw new \LogicException('The type="expression" attribute cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".'); } $arguments[$key] = new Expression($arg->nodeValue); @@ -515,11 +508,42 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $isChildDefi throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="iterator" only accepts collections of type="service" references in "%s".', $name, $file)); } break; + case 'service_closure': + if ('' === $arg->getAttribute('id')) { + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_closure" has no or empty "id" attribute in "%s".', $name, $file)); + } + + $arguments[$key] = new ServiceClosureArgument(new Reference($arg->getAttribute('id'), $invalidBehavior)); + break; + case 'service_locator': + $arg = $this->getArgumentsAsPhp($arg, $name, $file); + try { + $arguments[$key] = new ServiceLocatorArgument($arg); + } catch (InvalidArgumentException $e) { + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="service_locator" only accepts maps of type="service" references in "%s".', $name, $file)); + } + break; case 'tagged': + case 'tagged_iterator': + case 'tagged_locator': + $type = $arg->getAttribute('type'); + $forLocator = 'tagged_locator' === $type; + if (!$arg->getAttribute('tag')) { - throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="tagged" has no or empty "tag" attribute in "%s".', $name, $file)); + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="%s" has no or empty "tag" attribute in "%s".', $name, $type, $file)); + } + + $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag'), $arg->getAttribute('index-by') ?: null, $arg->getAttribute('default-index-method') ?: null, $forLocator, $arg->getAttribute('default-priority-method') ?: null); + + if ($forLocator) { + $arguments[$key] = new ServiceLocatorArgument($arguments[$key]); } - $arguments[$key] = new TaggedIteratorArgument($arg->getAttribute('tag')); + break; + case 'binary': + if (false === $value = base64_decode($arg->nodeValue)) { + throw new InvalidArgumentException(sprintf('Tag "<%s>" with type="binary" is not a valid base64 encoded string.', $name)); + } + $arguments[$key] = $value; break; case 'string': $arguments[$key] = $arg->nodeValue; @@ -538,11 +562,9 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $isChildDefi /** * Get child elements by name. * - * @param mixed $name - * * @return \DOMElement[] */ - private function getChildren(\DOMNode $node, $name) + private function getChildren(\DOMNode $node, string $name): array { $children = []; foreach ($node->childNodes as $child) { @@ -600,6 +622,8 @@ public function validateSchema(\DOMDocument $dom) array_shift($parts); $locationstart = 'phar:///'; } + } elseif ('\\' === \DIRECTORY_SEPARATOR && str_starts_with($location, '\\\\')) { + $locationstart = ''; } $drive = '\\' === \DIRECTORY_SEPARATOR ? array_shift($parts).'/' : ''; $location = $locationstart.$drive.implode('/', array_map('rawurlencode', $parts)); @@ -620,14 +644,13 @@ public function validateSchema(\DOMDocument $dom) EOF ; - if (\LIBXML_VERSION < 20900) { + if ($this->shouldEnableEntityLoader()) { $disableEntities = libxml_disable_entity_loader(false); $valid = @$dom->schemaValidateSource($source); libxml_disable_entity_loader($disableEntities); } else { $valid = @$dom->schemaValidateSource($source); } - foreach ($tmpfiles as $tmpfile) { @unlink($tmpfile); } @@ -635,22 +658,50 @@ public function validateSchema(\DOMDocument $dom) return $valid; } - /** - * Validates an alias. - * - * @param string $file - */ - private function validateAlias(\DOMElement $alias, $file) + private function shouldEnableEntityLoader(): bool + { + // Version prior to 8.0 can be enabled without deprecation + if (\PHP_VERSION_ID < 80000) { + return true; + } + + static $dom, $schema; + if (null === $dom) { + $dom = new \DOMDocument(); + $dom->loadXML(''); + + $tmpfile = tempnam(sys_get_temp_dir(), 'symfony'); + register_shutdown_function(static function () use ($tmpfile) { + @unlink($tmpfile); + }); + $schema = ' + + +'; + file_put_contents($tmpfile, ' + + + +'); + } + + return !@$dom->schemaValidateSource($schema); + } + + private function validateAlias(\DOMElement $alias, string $file) { foreach ($alias->attributes as $name => $node) { if (!\in_array($name, ['alias', 'id', 'public'])) { - @trigger_error(sprintf('Using the attribute "%s" is deprecated for the service "%s" which is defined as an alias in "%s". Allowed attributes for service aliases are "alias", "id" and "public". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.', $name, $alias->getAttribute('id'), $file), \E_USER_DEPRECATED); + throw new InvalidArgumentException(sprintf('Invalid attribute "%s" defined for alias "%s" in "%s".', $name, $alias->getAttribute('id'), $file)); } } foreach ($alias->childNodes as $child) { - if ($child instanceof \DOMElement && self::NS === $child->namespaceURI) { - @trigger_error(sprintf('Using the element "%s" is deprecated for the service "%s" which is defined as an alias in "%s". The XmlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported elements.', $child->localName, $alias->getAttribute('id'), $file), \E_USER_DEPRECATED); + if (!$child instanceof \DOMElement || self::NS !== $child->namespaceURI) { + continue; + } + if (!\in_array($child->localName, ['deprecated'], true)) { + throw new InvalidArgumentException(sprintf('Invalid child element "%s" defined for alias "%s" in "%s".', $child->localName, $alias->getAttribute('id'), $file)); } } } @@ -658,11 +709,9 @@ private function validateAlias(\DOMElement $alias, $file) /** * Validates an extension. * - * @param string $file - * * @throws InvalidArgumentException When no extension is found corresponding to a tag */ - private function validateExtensions(\DOMDocument $dom, $file) + private function validateExtensions(\DOMDocument $dom, string $file) { foreach ($dom->documentElement->childNodes as $node) { if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) { @@ -671,8 +720,8 @@ private function validateExtensions(\DOMDocument $dom, $file) // can it be handled by an extension? if (!$this->container->hasExtension($node->namespaceURI)) { - $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getNamespace(); }, $this->container->getExtensions())); - throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $node->tagName, $file, $node->namespaceURI, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none')); + $extensionNamespaces = array_filter(array_map(function (ExtensionInterface $ext) { return $ext->getNamespace(); }, $this->container->getExtensions())); + throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $node->tagName, $file, $node->namespaceURI, $extensionNamespaces ? implode('", "', $extensionNamespaces) : 'none')); } } } diff --git a/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php b/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php index e598bc4c..66d03352 100644 --- a/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php +++ b/vendor/symfony/dependency-injection/Loader/YamlFileLoader.php @@ -15,6 +15,8 @@ use Symfony\Component\DependencyInjection\Argument\ArgumentInterface; use Symfony\Component\DependencyInjection\Argument\BoundArgument; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument; use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -22,6 +24,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\ExpressionLanguage\Expression; use Symfony\Component\Yaml\Exception\ParseException; @@ -36,7 +39,7 @@ */ class YamlFileLoader extends FileLoader { - private static $serviceKeywords = [ + private const SERVICE_KEYWORDS = [ 'alias' => 'alias', 'parent' => 'parent', 'class' => 'class', @@ -56,13 +59,13 @@ class YamlFileLoader extends FileLoader 'decorates' => 'decorates', 'decoration_inner_name' => 'decoration_inner_name', 'decoration_priority' => 'decoration_priority', + 'decoration_on_invalid' => 'decoration_on_invalid', 'autowire' => 'autowire', - 'autowiring_types' => 'autowiring_types', 'autoconfigure' => 'autoconfigure', 'bind' => 'bind', ]; - private static $prototypeKeywords = [ + private const PROTOTYPE_KEYWORDS = [ 'resource' => 'resource', 'namespace' => 'namespace', 'exclude' => 'exclude', @@ -83,7 +86,7 @@ class YamlFileLoader extends FileLoader 'bind' => 'bind', ]; - private static $instanceofKeywords = [ + private const INSTANCEOF_KEYWORDS = [ 'shared' => 'shared', 'lazy' => 'lazy', 'public' => 'public', @@ -92,9 +95,10 @@ class YamlFileLoader extends FileLoader 'calls' => 'calls', 'tags' => 'tags', 'autowire' => 'autowire', + 'bind' => 'bind', ]; - private static $defaultsKeywords = [ + private const DEFAULTS_KEYWORDS = [ 'public' => 'public', 'tags' => 'tags', 'autowire' => 'autowire', @@ -107,6 +111,8 @@ class YamlFileLoader extends FileLoader private $anonymousServicesCount; private $anonymousServicesSuffix; + protected $autoRegisterAliasesForSinglyImplementedInterfaces = false; + /** * {@inheritdoc} */ @@ -148,6 +154,7 @@ public function load($resource, $type = null) $this->parseDefinitions($content, $path); } finally { $this->instanceof = []; + $this->registerAliasesForSinglyImplementedInterfaces(); } } @@ -167,12 +174,7 @@ public function supports($resource, $type = null) return \in_array($type, ['yaml', 'yml'], true); } - /** - * Parses all imports. - * - * @param string $file - */ - private function parseImports(array $content, $file) + private function parseImports(array $content, string $file) { if (!isset($content['imports'])) { return; @@ -192,16 +194,11 @@ private function parseImports(array $content, $file) } $this->setCurrentDir($defaultDirectory); - $this->import($import['resource'], isset($import['type']) ? $import['type'] : null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file); + $this->import($import['resource'], $import['type'] ?? null, $import['ignore_errors'] ?? false, $file); } } - /** - * Parses definitions. - * - * @param string $file - */ - private function parseDefinitions(array $content, $file) + private function parseDefinitions(array $content, string $file) { if (!isset($content['services'])) { return; @@ -224,7 +221,7 @@ private function parseDefinitions(array $content, $file) if (!$service || !\is_array($service)) { throw new InvalidArgumentException(sprintf('Type definition "%s" must be a non-empty array within "_instanceof" in "%s". Check your YAML syntax.', $id, $file)); } - if (\is_string($service) && 0 === strpos($service, '@')) { + if (\is_string($service) && str_starts_with($service, '@')) { throw new InvalidArgumentException(sprintf('Type definition "%s" cannot be an alias within "_instanceof" in "%s". Check your YAML syntax.', $id, $file)); } $this->parseDefinition($id, $service, $file, []); @@ -239,13 +236,9 @@ private function parseDefinitions(array $content, $file) } /** - * @param string $file - * - * @return array - * * @throws InvalidArgumentException */ - private function parseDefaults(array &$content, $file) + private function parseDefaults(array &$content, string $file): array { if (!\array_key_exists('_defaults', $content['services'])) { return []; @@ -258,8 +251,8 @@ private function parseDefaults(array &$content, $file) } foreach ($defaults as $key => $default) { - if (!isset(self::$defaultsKeywords[$key])) { - throw new InvalidArgumentException(sprintf('The configuration key "%s" cannot be used to define a default value in "%s". Allowed keys are "%s".', $key, $file, implode('", "', self::$defaultsKeywords))); + if (!isset(self::DEFAULTS_KEYWORDS[$key])) { + throw new InvalidArgumentException(sprintf('The configuration key "%s" cannot be used to define a default value in "%s". Allowed keys are "%s".', $key, $file, implode('", "', self::DEFAULTS_KEYWORDS))); } } @@ -296,19 +289,18 @@ private function parseDefaults(array &$content, $file) throw new InvalidArgumentException(sprintf('Parameter "bind" in "_defaults" must be an array in "%s". Check your YAML syntax.', $file)); } - $defaults['bind'] = array_map(function ($v) { return new BoundArgument($v); }, $this->resolveServices($defaults['bind'], $file)); + foreach ($this->resolveServices($defaults['bind'], $file) as $argument => $value) { + $defaults['bind'][$argument] = new BoundArgument($value, true, BoundArgument::DEFAULTS_BINDING, $file); + } } return $defaults; } - /** - * @return bool - */ - private function isUsingShortSyntax(array $service) + private function isUsingShortSyntax(array $service): bool { foreach ($service as $key => $value) { - if (\is_string($key) && ('' === $key || '$' !== $key[0])) { + if (\is_string($key) && ('' === $key || ('$' !== $key[0] && !str_contains($key, '\\')))) { return false; } } @@ -319,18 +311,17 @@ private function isUsingShortSyntax(array $service) /** * Parses a definition. * - * @param string $id - * @param array|string $service - * @param string $file + * @param array|string|null $service * * @throws InvalidArgumentException When tags are invalid */ - private function parseDefinition($id, $service, $file, array $defaults) + private function parseDefinition(string $id, $service, string $file, array $defaults) { if (preg_match('/^_[a-zA-Z0-9_]*$/', $id)) { - @trigger_error(sprintf('Service names that start with an underscore are deprecated since Symfony 3.3 and will be reserved in 4.0. Rename the "%s" service or define it in XML instead.', $id), \E_USER_DEPRECATED); + throw new InvalidArgumentException(sprintf('Service names that start with an underscore are reserved. Rename the "%s" service or define it in XML instead.', $id)); } - if (\is_string($service) && 0 === strpos($service, '@')) { + + if (\is_string($service) && str_starts_with($service, '@')) { $this->container->setAlias($id, $alias = new Alias(substr($service, 1))); if (isset($defaults['public'])) { $alias->setPublic($defaults['public']); @@ -362,8 +353,12 @@ private function parseDefinition($id, $service, $file, array $defaults) } foreach ($service as $key => $value) { - if (!\in_array($key, ['alias', 'public'])) { - @trigger_error(sprintf('The configuration key "%s" is unsupported for the service "%s" which is defined as an alias in "%s". Allowed configuration keys for service aliases are "alias" and "public". The YamlFileLoader will raise an exception in Symfony 4.0, instead of silently ignoring unsupported attributes.', $key, $id, $file), \E_USER_DEPRECATED); + if (!\in_array($key, ['alias', 'public', 'deprecated'])) { + throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for the service "%s" which is defined as an alias in "%s". Allowed configuration keys for service aliases are "alias", "public" and "deprecated".', $key, $id, $file)); + } + + if ('deprecated' === $key) { + $alias->setDeprecated(true, $value); } } @@ -391,6 +386,10 @@ private function parseDefinition($id, $service, $file, array $defaults) } } + if ('' !== $service['parent'] && '@' === $service['parent'][0]) { + throw new InvalidArgumentException(sprintf('The value of the "parent" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['parent'], substr($service['parent'], 1))); + } + $definition = new ChildDefinition($service['parent']); } else { $definition = new Definition(); @@ -421,7 +420,10 @@ private function parseDefinition($id, $service, $file, array $defaults) } if (isset($service['lazy'])) { - $definition->setLazy($service['lazy']); + $definition->setLazy((bool) $service['lazy']); + if (\is_string($service['lazy'])) { + $definition->addTag('proxy', ['interface' => $service['lazy']]); + } } if (isset($service['public'])) { @@ -461,23 +463,53 @@ private function parseDefinition($id, $service, $file, array $defaults) throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in "%s". Check your YAML syntax.', $id, $file)); } - foreach ($service['calls'] as $call) { - if (isset($call['method'])) { + foreach ($service['calls'] as $k => $call) { + if (!\is_array($call) && (!\is_string($k) || !$call instanceof TaggedValue)) { + throw new InvalidArgumentException(sprintf('Invalid method call for service "%s": expected map or array, "%s" given in "%s".', $id, $call instanceof TaggedValue ? '!'.$call->getTag() : \gettype($call), $file)); + } + + if (\is_string($k)) { + throw new InvalidArgumentException(sprintf('Invalid method call for service "%s", did you forgot a leading dash before "%s: ..." in "%s"?', $id, $k, $file)); + } + + if (isset($call['method']) && \is_string($call['method'])) { $method = $call['method']; - $args = isset($call['arguments']) ? $this->resolveServices($call['arguments'], $file) : []; + $args = $call['arguments'] ?? []; + $returnsClone = $call['returns_clone'] ?? false; } else { - $method = $call[0]; - $args = isset($call[1]) ? $this->resolveServices($call[1], $file) : []; + if (1 === \count($call) && \is_string(key($call))) { + $method = key($call); + $args = $call[$method]; + + if ($args instanceof TaggedValue) { + if ('returns_clone' !== $args->getTag()) { + throw new InvalidArgumentException(sprintf('Unsupported tag "!%s", did you mean "!returns_clone" for service "%s" in "%s"?', $args->getTag(), $id, $file)); + } + + $returnsClone = true; + $args = $args->getValue(); + } else { + $returnsClone = false; + } + } elseif (empty($call[0])) { + throw new InvalidArgumentException(sprintf('Invalid call for service "%s": the method must be defined as the first index of an array or as the only key of a map in "%s".', $id, $file)); + } else { + $method = $call[0]; + $args = $call[1] ?? []; + $returnsClone = $call[2] ?? false; + } } if (!\is_array($args)) { throw new InvalidArgumentException(sprintf('The second parameter for function call "%s" must be an array of its arguments for service "%s" in "%s". Check your YAML syntax.', $method, $id, $file)); } - $definition->addMethodCall($method, $args); + + $args = $this->resolveServices($args, $file); + $definition->addMethodCall($method, $args, $returnsClone); } } - $tags = isset($service['tags']) ? $service['tags'] : []; + $tags = $service['tags'] ?? []; if (!\is_array($tags)) { throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in "%s". Check your YAML syntax.', $id, $file)); } @@ -510,38 +542,34 @@ private function parseDefinition($id, $service, $file, array $defaults) $definition->addTag($name, $tag); } - if (isset($service['decorates'])) { - if ('' !== $service['decorates'] && '@' === $service['decorates'][0]) { - throw new InvalidArgumentException(sprintf('The value of the "decorates" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['decorates'], substr($service['decorates'], 1))); + if (null !== $decorates = $service['decorates'] ?? null) { + if ('' !== $decorates && '@' === $decorates[0]) { + throw new InvalidArgumentException(sprintf('The value of the "decorates" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['decorates'], substr($decorates, 1))); + } + + $decorationOnInvalid = \array_key_exists('decoration_on_invalid', $service) ? $service['decoration_on_invalid'] : 'exception'; + if ('exception' === $decorationOnInvalid) { + $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + } elseif ('ignore' === $decorationOnInvalid) { + $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; + } elseif (null === $decorationOnInvalid) { + $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; + } elseif ('null' === $decorationOnInvalid) { + throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration_on_invalid" on service "%s". Did you mean null (without quotes) in "%s"?', $decorationOnInvalid, $id, $file)); + } else { + throw new InvalidArgumentException(sprintf('Invalid value "%s" for attribute "decoration_on_invalid" on service "%s". Did you mean "exception", "ignore" or null in "%s"?', $decorationOnInvalid, $id, $file)); } - $renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null; - $priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0; - $definition->setDecoratedService($service['decorates'], $renameId, $priority); + $renameId = $service['decoration_inner_name'] ?? null; + $priority = $service['decoration_priority'] ?? 0; + + $definition->setDecoratedService($decorates, $renameId, $priority, $invalidBehavior); } if (isset($service['autowire'])) { $definition->setAutowired($service['autowire']); } - if (isset($service['autowiring_types'])) { - if (\is_string($service['autowiring_types'])) { - $definition->addAutowiringType($service['autowiring_types']); - } else { - if (!\is_array($service['autowiring_types'])) { - throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in "%s". Check your YAML syntax.', $id, $file)); - } - - foreach ($service['autowiring_types'] as $autowiringType) { - if (!\is_string($autowiringType)) { - throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in "%s". Check your YAML syntax.', $id, $file)); - } - - $definition->addAutowiringType($autowiringType); - } - } - } - if (isset($defaults['bind']) || isset($service['bind'])) { // deep clone, to avoid multiple process of the same instance in the passes $bindings = isset($defaults['bind']) ? unserialize(serialize($defaults['bind'])) : []; @@ -552,6 +580,12 @@ private function parseDefinition($id, $service, $file, array $defaults) } $bindings = array_merge($bindings, $this->resolveServices($service['bind'], $file)); + $bindingType = $this->isLoadingInstanceof ? BoundArgument::INSTANCEOF_BINDING : BoundArgument::SERVICE_BINDING; + foreach ($bindings as $argument => $value) { + if (!$value instanceof BoundArgument) { + $bindings[$argument] = new BoundArgument($value, true, $bindingType, $file); + } + } } $definition->setBindings($bindings); @@ -573,8 +607,8 @@ private function parseDefinition($id, $service, $file, array $defaults) if (!\is_string($service['resource'])) { throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in "%s". Check your YAML syntax.', $id, $file)); } - $exclude = isset($service['exclude']) ? $service['exclude'] : null; - $namespace = isset($service['namespace']) ? $service['namespace'] : $id; + $exclude = $service['exclude'] ?? null; + $namespace = $service['namespace'] ?? $id; $this->registerClasses($definition, $namespace, $service['resource'], $exclude); } else { $this->setDefinition($id, $definition); @@ -584,25 +618,28 @@ private function parseDefinition($id, $service, $file, array $defaults) /** * Parses a callable. * - * @param string|array $callable A callable - * @param string $parameter A parameter (e.g. 'factory' or 'configurator') - * @param string $id A service identifier - * @param string $file A parsed file + * @param string|array $callable A callable reference * * @throws InvalidArgumentException When errors occur * - * @return string|array A parsed callable + * @return string|array|Reference A parsed callable */ - private function parseCallable($callable, $parameter, $id, $file) + private function parseCallable($callable, string $parameter, string $id, string $file) { if (\is_string($callable)) { if ('' !== $callable && '@' === $callable[0]) { - throw new InvalidArgumentException(sprintf('The value of the "%s" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $parameter, $id, $callable, substr($callable, 1))); + if (!str_contains($callable, ':')) { + return [$this->resolveServices($callable, $file), '__invoke']; + } + + throw new InvalidArgumentException(sprintf('The value of the "%s" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s" in "%s").', $parameter, $id, $callable, substr($callable, 1), $file)); } - if (false !== strpos($callable, ':') && false === strpos($callable, '::')) { + if (str_contains($callable, ':') && !str_contains($callable, '::')) { $parts = explode(':', $callable); + @trigger_error(sprintf('Using short %s syntax for service "%s" is deprecated since Symfony 4.4, use "[\'@%s\', \'%s\']" instead.', $parameter, $id, ...$parts), \E_USER_DEPRECATED); + return [$this->resolveServices('@'.$parts[0], $file), $parts[1]]; } @@ -635,7 +672,7 @@ private function parseCallable($callable, $parameter, $id, $file) */ protected function loadFile($file) { - if (!class_exists('Symfony\Component\Yaml\Parser')) { + if (!class_exists(\Symfony\Component\Yaml\Parser::class)) { throw new RuntimeException('Unable to load YAML config files as the Symfony Yaml Component is not installed.'); } @@ -651,18 +688,10 @@ protected function loadFile($file) $this->yamlParser = new YamlParser(); } - $prevErrorHandler = set_error_handler(function ($level, $message, $script, $line) use ($file, &$prevErrorHandler) { - $message = \E_USER_DEPRECATED === $level ? preg_replace('/ on line \d+/', ' in "'.$file.'"$0', $message) : $message; - - return $prevErrorHandler ? $prevErrorHandler($level, $message, $script, $line) : false; - }); - try { $configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS); } catch (ParseException $e) { throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: ', $file).$e->getMessage(), 0, $e); - } finally { - restore_error_handler(); } return $this->validate($configuration, $file); @@ -671,14 +700,9 @@ protected function loadFile($file) /** * Validates a YAML file. * - * @param mixed $content - * @param string $file - * - * @return array - * * @throws InvalidArgumentException When service file is not valid */ - private function validate($content, $file) + private function validate($content, string $file): ?array { if (null === $content) { return $content; @@ -694,7 +718,7 @@ private function validate($content, $file) } if (!$this->container->hasExtension($namespace)) { - $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions())); + $extensionNamespaces = array_filter(array_map(function (ExtensionInterface $ext) { return $ext->getAlias(); }, $this->container->getExtensions())); throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in "%s"). Looked for namespace "%s", found "%s".', $namespace, $file, $namespace, $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none')); } } @@ -705,13 +729,9 @@ private function validate($content, $file) /** * Resolves services. * - * @param mixed $value - * @param string $file - * @param bool $isParameter - * * @return array|string|Reference|ArgumentInterface */ - private function resolveServices($value, $file, $isParameter = false) + private function resolveServices($value, string $file, bool $isParameter = false) { if ($value instanceof TaggedValue) { $argument = $value->getValue(); @@ -726,12 +746,48 @@ private function resolveServices($value, $file, $isParameter = false) throw new InvalidArgumentException(sprintf('"!iterator" tag only accepts arrays of "@service" references in "%s".', $file)); } } - if ('tagged' === $value->getTag()) { - if (!\is_string($argument) || !$argument) { - throw new InvalidArgumentException(sprintf('"!tagged" tag only accepts non empty string in "%s".', $file)); + if ('service_closure' === $value->getTag()) { + $argument = $this->resolveServices($argument, $file, $isParameter); + + if (!$argument instanceof Reference) { + throw new InvalidArgumentException(sprintf('"!service_closure" tag only accepts service references in "%s".', $file)); } - return new TaggedIteratorArgument($argument); + return new ServiceClosureArgument($argument); + } + if ('service_locator' === $value->getTag()) { + if (!\is_array($argument)) { + throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps in "%s".', $file)); + } + + $argument = $this->resolveServices($argument, $file, $isParameter); + + try { + return new ServiceLocatorArgument($argument); + } catch (InvalidArgumentException $e) { + throw new InvalidArgumentException(sprintf('"!service_locator" tag only accepts maps of "@service" references in "%s".', $file)); + } + } + if (\in_array($value->getTag(), ['tagged', 'tagged_iterator', 'tagged_locator'], true)) { + $forLocator = 'tagged_locator' === $value->getTag(); + + if (\is_array($argument) && isset($argument['tag']) && $argument['tag']) { + if ($diff = array_diff(array_keys($argument), ['tag', 'index_by', 'default_index_method', 'default_priority_method'])) { + throw new InvalidArgumentException(sprintf('"!%s" tag contains unsupported key "%s"; supported ones are "tag", "index_by", "default_index_method", and "default_priority_method".', $value->getTag(), implode('", "', $diff))); + } + + $argument = new TaggedIteratorArgument($argument['tag'], $argument['index_by'] ?? null, $argument['default_index_method'] ?? null, $forLocator, $argument['default_priority_method'] ?? null); + } elseif (\is_string($argument) && $argument) { + $argument = new TaggedIteratorArgument($argument, null, null, $forLocator); + } else { + throw new InvalidArgumentException(sprintf('"!%s" tags only accept a non empty string or an array with a key "tag" in "%s".', $value->getTag(), $file)); + } + + if ($forLocator) { + $argument = new ServiceLocatorArgument($argument); + } + + return $argument; } if ('service' === $value->getTag()) { if ($isParameter) { @@ -743,7 +799,7 @@ private function resolveServices($value, $file, $isParameter = false) $instanceof = $this->instanceof; $this->instanceof = []; - $id = sprintf('%d_%s', ++$this->anonymousServicesCount, preg_replace('/^.*\\\\/', '', isset($argument['class']) ? $argument['class'] : '').$this->anonymousServicesSuffix); + $id = sprintf('.%d_%s', ++$this->anonymousServicesCount, preg_replace('/^.*\\\\/', '', $argument['class'] ?? '').$this->anonymousServicesSuffix); $this->parseDefinition($id, $argument, $file, []); if (!$this->container->hasDefinition($id)) { @@ -765,20 +821,20 @@ private function resolveServices($value, $file, $isParameter = false) foreach ($value as $k => $v) { $value[$k] = $this->resolveServices($v, $file, $isParameter); } - } elseif (\is_string($value) && 0 === strpos($value, '@=')) { + } elseif (\is_string($value) && str_starts_with($value, '@=')) { if (!class_exists(Expression::class)) { - throw new \LogicException(sprintf('The "@=" expression syntax cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".')); + throw new \LogicException('The "@=" expression syntax cannot be used without the ExpressionLanguage component. Try running "composer require symfony/expression-language".'); } return new Expression(substr($value, 2)); - } elseif (\is_string($value) && 0 === strpos($value, '@')) { - if (0 === strpos($value, '@@')) { + } elseif (\is_string($value) && str_starts_with($value, '@')) { + if (str_starts_with($value, '@@')) { $value = substr($value, 1); $invalidBehavior = null; - } elseif (0 === strpos($value, '@!')) { + } elseif (str_starts_with($value, '@!')) { $value = substr($value, 2); $invalidBehavior = ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE; - } elseif (0 === strpos($value, '@?')) { + } elseif (str_starts_with($value, '@?')) { $value = substr($value, 2); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; } else { @@ -786,11 +842,6 @@ private function resolveServices($value, $file, $isParameter = false) $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; } - if ('=' === substr($value, -1)) { - @trigger_error(sprintf('The "=" suffix that used to disable strict references in Symfony 2.x is deprecated since Symfony 3.3 and will be unsupported in 4.0. Remove it in "%s".', $value), \E_USER_DEPRECATED); - $value = substr($value, 0, -1); - } - if (null !== $invalidBehavior) { $value = new Reference($value, $invalidBehavior); } @@ -799,9 +850,6 @@ private function resolveServices($value, $file, $isParameter = false) return $value; } - /** - * Loads from Extensions. - */ private function loadFromExtensions(array $content) { foreach ($content as $namespace => $values) { @@ -817,30 +865,19 @@ private function loadFromExtensions(array $content) } } - /** - * Checks the keywords used to define a service. - * - * @param string $id The service name - * @param array $definition The service definition to check - * @param string $file The loaded YAML file - */ - private function checkDefinition($id, array $definition, $file) + private function checkDefinition(string $id, array $definition, string $file) { - if ($throw = $this->isLoadingInstanceof) { - $keywords = self::$instanceofKeywords; - } elseif ($throw = (isset($definition['resource']) || isset($definition['namespace']))) { - $keywords = self::$prototypeKeywords; + if ($this->isLoadingInstanceof) { + $keywords = self::INSTANCEOF_KEYWORDS; + } elseif (isset($definition['resource']) || isset($definition['namespace'])) { + $keywords = self::PROTOTYPE_KEYWORDS; } else { - $keywords = self::$serviceKeywords; + $keywords = self::SERVICE_KEYWORDS; } foreach ($definition as $key => $value) { if (!isset($keywords[$key])) { - if ($throw) { - throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for definition "%s" in "%s". Allowed configuration keys are "%s".', $key, $id, $file, implode('", "', $keywords))); - } - - @trigger_error(sprintf('The configuration key "%s" is unsupported for service definition "%s" in "%s". Allowed configuration keys are "%s". The YamlFileLoader object will raise an exception instead in Symfony 4.0 when detecting an unsupported service configuration key.', $key, $id, $file, implode('", "', $keywords)), \E_USER_DEPRECATED); + throw new InvalidArgumentException(sprintf('The configuration key "%s" is unsupported for definition "%s" in "%s". Allowed configuration keys are "%s".', $key, $id, $file, implode('", "', $keywords))); } } } diff --git a/vendor/symfony/dependency-injection/Loader/schema/dic/services/services-1.0.xsd b/vendor/symfony/dependency-injection/Loader/schema/dic/services/services-1.0.xsd index 3a55a7df..65466e97 100644 --- a/vendor/symfony/dependency-injection/Loader/schema/dic/services/services-1.0.xsd +++ b/vendor/symfony/dependency-injection/Loader/schema/dic/services/services-1.0.xsd @@ -78,7 +78,7 @@ ]]> - + @@ -117,7 +117,6 @@ - @@ -125,11 +124,12 @@ - + + @@ -142,11 +142,12 @@ + - + @@ -161,13 +162,14 @@ + - + @@ -207,7 +209,6 @@ - @@ -221,6 +222,7 @@ + @@ -233,8 +235,10 @@ - + + + @@ -242,6 +246,7 @@ + @@ -249,6 +254,7 @@ + @@ -259,8 +265,20 @@ + + + + + + + + + + + + @@ -273,6 +291,14 @@ + + + + + + + + diff --git a/vendor/symfony/dependency-injection/Parameter.php b/vendor/symfony/dependency-injection/Parameter.php index cac6f6c4..d484ac0f 100644 --- a/vendor/symfony/dependency-injection/Parameter.php +++ b/vendor/symfony/dependency-injection/Parameter.php @@ -20,10 +20,7 @@ class Parameter { private $id; - /** - * @param string $id The parameter key - */ - public function __construct($id) + public function __construct(string $id) { $this->id = $id; } @@ -33,6 +30,6 @@ public function __construct($id) */ public function __toString() { - return (string) $this->id; + return $this->id; } } diff --git a/vendor/symfony/dependency-injection/ParameterBag/ContainerBag.php b/vendor/symfony/dependency-injection/ParameterBag/ContainerBag.php new file mode 100644 index 00000000..724a94e6 --- /dev/null +++ b/vendor/symfony/dependency-injection/ParameterBag/ContainerBag.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\ParameterBag; + +use Symfony\Component\DependencyInjection\Container; + +/** + * @author Nicolas Grekas + */ +class ContainerBag extends FrozenParameterBag implements ContainerBagInterface +{ + private $container; + + public function __construct(Container $container) + { + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function all() + { + return $this->container->getParameterBag()->all(); + } + + /** + * {@inheritdoc} + * + * @return array|bool|string|int|float|null + */ + public function get($name) + { + return $this->container->getParameter($name); + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function has($name) + { + return $this->container->hasParameter($name); + } +} diff --git a/vendor/symfony/dependency-injection/ParameterBag/ContainerBagInterface.php b/vendor/symfony/dependency-injection/ParameterBag/ContainerBagInterface.php new file mode 100644 index 00000000..1c1227a3 --- /dev/null +++ b/vendor/symfony/dependency-injection/ParameterBag/ContainerBagInterface.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\ParameterBag; + +use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; + +/** + * ContainerBagInterface is the interface implemented by objects that manage service container parameters. + * + * @author Nicolas Grekas + */ +interface ContainerBagInterface extends ContainerInterface +{ + /** + * Gets the service container parameters. + * + * @return array An array of parameters + */ + public function all(); + + /** + * Replaces parameter placeholders (%name%) by their values. + * + * @param mixed $value A value + * + * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist + */ + public function resolveValue($value); + + /** + * Escape parameter placeholders %. + * + * @param mixed $value + * + * @return mixed + */ + public function escapeValue($value); + + /** + * Unescape parameter placeholders %. + * + * @param mixed $value + * + * @return mixed + */ + public function unescapeValue($value); +} diff --git a/vendor/symfony/dependency-injection/ParameterBag/EnvPlaceholderParameterBag.php b/vendor/symfony/dependency-injection/ParameterBag/EnvPlaceholderParameterBag.php index c4e369b0..22f68120 100644 --- a/vendor/symfony/dependency-injection/ParameterBag/EnvPlaceholderParameterBag.php +++ b/vendor/symfony/dependency-injection/ParameterBag/EnvPlaceholderParameterBag.php @@ -19,15 +19,19 @@ */ class EnvPlaceholderParameterBag extends ParameterBag { + private $envPlaceholderUniquePrefix; private $envPlaceholders = []; + private $unusedEnvPlaceholders = []; private $providedTypes = []; + private static $counter = 0; + /** * {@inheritdoc} */ public function get($name) { - if (0 === strpos($name, 'env(') && ')' === substr($name, -1) && 'env()' !== $name) { + if (str_starts_with($name, 'env(') && str_ends_with($name, ')') && 'env()' !== $name) { $env = substr($name, 4, -1); if (isset($this->envPlaceholders[$env])) { @@ -35,20 +39,28 @@ public function get($name) return $placeholder; // return first result } } - if (!preg_match('/^(?:\w++:)*+\w++$/', $env)) { + if (isset($this->unusedEnvPlaceholders[$env])) { + foreach ($this->unusedEnvPlaceholders[$env] as $placeholder) { + return $placeholder; // return first result + } + } + if (!preg_match('/^(?:\w*+:)*+\w++$/', $env)) { throw new InvalidArgumentException(sprintf('Invalid "%s" name: only "word" characters are allowed.', $name)); } if ($this->has($name)) { $defaultValue = parent::get($name); - if (null !== $defaultValue && !is_scalar($defaultValue)) { + if (null !== $defaultValue && !is_scalar($defaultValue)) { // !is_string in 5.0 + //throw new RuntimeException(sprintf('The default value of an env() parameter must be a string or null, but "%s" given to "%s".', \gettype($defaultValue), $name)); throw new RuntimeException(sprintf('The default value of an env() parameter must be scalar or null, but "%s" given to "%s".', \gettype($defaultValue), $name)); + } elseif (is_scalar($defaultValue) && !\is_string($defaultValue)) { + @trigger_error(sprintf('A non-string default value of an env() parameter is deprecated since 4.3, cast "%s" to string instead.', $name), \E_USER_DEPRECATED); } } - $uniqueName = md5($name.uniqid(mt_rand(), true)); - $placeholder = sprintf('env_%s_%s', str_replace(':', '_', $env), $uniqueName); + $uniqueName = md5($name.'_'.self::$counter++); + $placeholder = sprintf('%s_%s_%s', $this->getEnvPlaceholderUniquePrefix(), str_replace(':', '_', $env), $uniqueName); $this->envPlaceholders[$env][$placeholder] = $placeholder; return $placeholder; @@ -57,6 +69,20 @@ public function get($name) return parent::get($name); } + /** + * Gets the common env placeholder prefix for env vars created by this bag. + */ + public function getEnvPlaceholderUniquePrefix(): string + { + if (null === $this->envPlaceholderUniquePrefix) { + $reproducibleEntropy = unserialize(serialize($this->parameters)); + array_walk_recursive($reproducibleEntropy, function (&$v) { $v = null; }); + $this->envPlaceholderUniquePrefix = 'env_'.substr(md5(serialize($reproducibleEntropy)), -16); + } + + return $this->envPlaceholderUniquePrefix; + } + /** * Returns the map of env vars used in the resolved parameter values to their placeholders. * @@ -67,6 +93,16 @@ public function getEnvPlaceholders() return $this->envPlaceholders; } + public function getUnusedEnvPlaceholders(): array + { + return $this->unusedEnvPlaceholders; + } + + public function clearUnusedEnvPlaceholders() + { + $this->unusedEnvPlaceholders = []; + } + /** * Merges the env placeholders of another EnvPlaceholderParameterBag. */ @@ -79,6 +115,14 @@ public function mergeEnvPlaceholders(self $bag) $this->envPlaceholders[$env] += $placeholders; } } + + if ($newUnusedPlaceholders = $bag->getUnusedEnvPlaceholders()) { + $this->unusedEnvPlaceholders += $newUnusedPlaceholders; + + foreach ($newUnusedPlaceholders as $env => $placeholders) { + $this->unusedEnvPlaceholders[$env] += $placeholders; + } + } } /** @@ -114,9 +158,15 @@ public function resolve() continue; } if (is_numeric($default = $this->parameters[$name])) { + if (!\is_string($default)) { + @trigger_error(sprintf('A non-string default value of env parameter "%s" is deprecated since 4.3, cast it to string instead.', $env), \E_USER_DEPRECATED); + } $this->parameters[$name] = (string) $default; - } elseif (null !== $default && !is_scalar($default)) { + } elseif (null !== $default && !is_scalar($default)) { // !is_string in 5.0 + //throw new RuntimeException(sprintf('The default value of env parameter "%s" must be a string or null, "%s" given.', $env, \gettype($default))); throw new RuntimeException(sprintf('The default value of env parameter "%s" must be scalar or null, "%s" given.', $env, \gettype($default))); + } elseif (is_scalar($default) && !\is_string($default)) { + @trigger_error(sprintf('A non-string default value of env parameter "%s" is deprecated since 4.3, cast it to string instead.', $env), \E_USER_DEPRECATED); } } } diff --git a/vendor/symfony/dependency-injection/ParameterBag/ParameterBag.php b/vendor/symfony/dependency-injection/ParameterBag/ParameterBag.php index 24dc8035..7a9f3814 100644 --- a/vendor/symfony/dependency-injection/ParameterBag/ParameterBag.php +++ b/vendor/symfony/dependency-injection/ParameterBag/ParameterBag.php @@ -25,18 +25,13 @@ class ParameterBag implements ParameterBagInterface protected $parameters = []; protected $resolved = false; - private $normalizedNames = []; - - /** - * @param array $parameters An array of parameters - */ public function __construct(array $parameters = []) { $this->add($parameters); } /** - * Clears all parameters. + * {@inheritdoc} */ public function clear() { @@ -44,9 +39,7 @@ public function clear() } /** - * Adds parameters to the service container parameters. - * - * @param array $parameters An array of parameters + * {@inheritdoc} */ public function add(array $parameters) { @@ -68,7 +61,7 @@ public function all() */ public function get($name) { - $name = $this->normalizeName($name); + $name = (string) $name; if (!\array_key_exists($name, $this->parameters)) { if (!$name) { @@ -78,13 +71,13 @@ public function get($name) $alternatives = []; foreach ($this->parameters as $key => $parameterValue) { $lev = levenshtein($name, $key); - if ($lev <= \strlen($name) / 3 || false !== strpos($key, $name)) { + if ($lev <= \strlen($name) / 3 || str_contains($key, $name)) { $alternatives[] = $key; } } $nonNestedAlternative = null; - if (!\count($alternatives) && false !== strpos($name, '.')) { + if (!\count($alternatives) && str_contains($name, '.')) { $namePartsLength = array_map('strlen', explode('.', $name)); $key = substr($name, 0, -1 * (1 + array_pop($namePartsLength))); while (\count($namePartsLength)) { @@ -106,14 +99,11 @@ public function get($name) } /** - * Sets a service container parameter. - * - * @param string $name The parameter name - * @param mixed $value The parameter value + * {@inheritdoc} */ public function set($name, $value) { - $this->parameters[$this->normalizeName($name)] = $value; + $this->parameters[(string) $name] = $value; } /** @@ -121,17 +111,15 @@ public function set($name, $value) */ public function has($name) { - return \array_key_exists($this->normalizeName($name), $this->parameters); + return \array_key_exists((string) $name, $this->parameters); } /** - * Removes a parameter. - * - * @param string $name The parameter name + * {@inheritdoc} */ public function remove($name) { - unset($this->parameters[$this->normalizeName($name)]); + unset($this->parameters[(string) $name]); } /** @@ -208,13 +196,12 @@ public function resolveString($value, array $resolving = []) // a non-string in a parameter value if (preg_match('/^%([^%\s]+)%$/', $value, $match)) { $key = $match[1]; - $lcKey = strtolower($key); // strtolower() to be removed in 4.0 - if (isset($resolving[$lcKey])) { + if (isset($resolving[$key])) { throw new ParameterCircularReferenceException(array_keys($resolving)); } - $resolving[$lcKey] = true; + $resolving[$key] = true; return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving); } @@ -226,8 +213,7 @@ public function resolveString($value, array $resolving = []) } $key = $match[1]; - $lcKey = strtolower($key); // strtolower() to be removed in 4.0 - if (isset($resolving[$lcKey])) { + if (isset($resolving[$key])) { throw new ParameterCircularReferenceException(array_keys($resolving)); } @@ -238,7 +224,7 @@ public function resolveString($value, array $resolving = []) } $resolved = (string) $resolved; - $resolving[$lcKey] = true; + $resolving[$key] = true; return $this->isResolved() ? $resolved : $this->resolveString($resolved, $resolving); }, $value); @@ -290,18 +276,4 @@ public function unescapeValue($value) return $value; } - - private function normalizeName($name) - { - if (isset($this->normalizedNames[$normalizedName = strtolower($name)])) { - $normalizedName = $this->normalizedNames[$normalizedName]; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), \E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } } diff --git a/vendor/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php b/vendor/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php index 7386df06..eb033bf4 100644 --- a/vendor/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php +++ b/vendor/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php @@ -15,7 +15,7 @@ use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; /** - * ParameterBagInterface. + * ParameterBagInterface is the interface implemented by objects that manage service container parameters. * * @author Fabien Potencier */ @@ -31,8 +31,6 @@ public function clear(); /** * Adds parameters to the service container parameters. * - * @param array $parameters An array of parameters - * * @throws LogicException if the parameter can not be added */ public function add(array $parameters); @@ -49,7 +47,7 @@ public function all(); * * @param string $name The parameter name * - * @return mixed The parameter value + * @return array|bool|string|int|float|null * * @throws ParameterNotFoundException if the parameter is not defined */ @@ -65,8 +63,8 @@ public function remove($name); /** * Sets a service container parameter. * - * @param string $name The parameter name - * @param mixed $value The parameter value + * @param string $name The parameter name + * @param array|bool|string|int|float|null $value The parameter value * * @throws LogicException if the parameter can not be set */ diff --git a/vendor/symfony/dependency-injection/README.md b/vendor/symfony/dependency-injection/README.md index cb2d4a11..fa6719a7 100644 --- a/vendor/symfony/dependency-injection/README.md +++ b/vendor/symfony/dependency-injection/README.md @@ -7,8 +7,8 @@ way objects are constructed in your application. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/dependency-injection/Reference.php b/vendor/symfony/dependency-injection/Reference.php index 82906d2b..c13cf6fe 100644 --- a/vendor/symfony/dependency-injection/Reference.php +++ b/vendor/symfony/dependency-injection/Reference.php @@ -21,15 +21,9 @@ class Reference private $id; private $invalidBehavior; - /** - * @param string $id The service identifier - * @param int $invalidBehavior The behavior when the service does not exist - * - * @see Container - */ - public function __construct($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) + public function __construct(string $id, int $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { - $this->id = (string) $id; + $this->id = $id; $this->invalidBehavior = $invalidBehavior; } diff --git a/vendor/symfony/dependency-injection/ResettableContainerInterface.php b/vendor/symfony/dependency-injection/ResettableContainerInterface.php index b74e6762..b9714d25 100644 --- a/vendor/symfony/dependency-injection/ResettableContainerInterface.php +++ b/vendor/symfony/dependency-injection/ResettableContainerInterface.php @@ -11,14 +11,18 @@ namespace Symfony\Component\DependencyInjection; +use Symfony\Contracts\Service\ResetInterface; + /** * ResettableContainerInterface defines additional resetting functionality * for containers, allowing to release shared services when the container is * not needed anymore. * * @author Christophe Coevoet + * + * @deprecated since Symfony 4.2, use "Symfony\Contracts\Service\ResetInterface" instead. */ -interface ResettableContainerInterface extends ContainerInterface +interface ResettableContainerInterface extends ContainerInterface, ResetInterface { /** * Resets shared services from the container. diff --git a/vendor/symfony/dependency-injection/ReverseContainer.php b/vendor/symfony/dependency-injection/ReverseContainer.php new file mode 100644 index 00000000..076e624c --- /dev/null +++ b/vendor/symfony/dependency-injection/ReverseContainer.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection; + +use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; + +/** + * Turns public and "container.reversible" services back to their ids. + * + * @author Nicolas Grekas + */ +final class ReverseContainer +{ + private $serviceContainer; + private $reversibleLocator; + private $tagName; + private $getServiceId; + + public function __construct(Container $serviceContainer, ContainerInterface $reversibleLocator, string $tagName = 'container.reversible') + { + $this->serviceContainer = $serviceContainer; + $this->reversibleLocator = $reversibleLocator; + $this->tagName = $tagName; + $this->getServiceId = \Closure::bind(function ($service): ?string { + return array_search($service, $this->services, true) ?: array_search($service, $this->privates, true) ?: null; + }, $serviceContainer, Container::class); + } + + /** + * Returns the id of the passed object when it exists as a service. + * + * To be reversible, services need to be either public or be tagged with "container.reversible". + * + * @param object $service + */ + public function getId($service): ?string + { + if ($this->serviceContainer === $service) { + return 'service_container'; + } + + if (null === $id = ($this->getServiceId)($service)) { + return null; + } + + if ($this->serviceContainer->has($id) || $this->reversibleLocator->has($id)) { + return $id; + } + + return null; + } + + /** + * @return object + * + * @throws ServiceNotFoundException When the service is not reversible + */ + public function getService(string $id) + { + if ($this->serviceContainer->has($id)) { + return $this->serviceContainer->get($id); + } + + if ($this->reversibleLocator->has($id)) { + return $this->reversibleLocator->get($id); + } + + if (isset($this->serviceContainer->getRemovedIds()[$id])) { + throw new ServiceNotFoundException($id, null, null, [], sprintf('The "%s" service is private and cannot be accessed by reference. You should either make it public, or tag it as "%s".', $id, $this->tagName)); + } + + // will throw a ServiceNotFoundException + $this->serviceContainer->get($id); + } +} diff --git a/vendor/symfony/dependency-injection/ServiceLocator.php b/vendor/symfony/dependency-injection/ServiceLocator.php index 80be44eb..bdd10410 100644 --- a/vendor/symfony/dependency-injection/ServiceLocator.php +++ b/vendor/symfony/dependency-injection/ServiceLocator.php @@ -11,59 +11,54 @@ namespace Symfony\Component\DependencyInjection; -use Psr\Container\ContainerInterface as PsrContainerInterface; +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; +use Symfony\Contracts\Service\ServiceLocatorTrait; +use Symfony\Contracts\Service\ServiceProviderInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; /** * @author Robin Chalas * @author Nicolas Grekas */ -class ServiceLocator implements PsrContainerInterface +class ServiceLocator implements ServiceProviderInterface { - private $factories; - private $loading = []; - private $externalId; - private $container; - - /** - * @param callable[] $factories - */ - public function __construct(array $factories) - { - $this->factories = $factories; + use ServiceLocatorTrait { + get as private doGet; } - /** - * {@inheritdoc} - */ - public function has($id) - { - return isset($this->factories[$id]); - } + private $externalId; + private $container; /** * {@inheritdoc} + * + * @return mixed */ public function get($id) { - if (!isset($this->factories[$id])) { - throw new ServiceNotFoundException($id, end($this->loading) ?: null, null, [], $this->createServiceNotFoundMessage($id)); + if (!$this->externalId) { + return $this->doGet($id); } - if (isset($this->loading[$id])) { - $ids = array_values($this->loading); - $ids = \array_slice($this->loading, array_search($id, $ids)); - $ids[] = $id; + try { + return $this->doGet($id); + } catch (RuntimeException $e) { + $what = sprintf('service "%s" required by "%s"', $id, $this->externalId); + $message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage()); - throw new ServiceCircularReferenceException($id, $ids); - } + if ($e->getMessage() === $message) { + $message = sprintf('Cannot resolve %s: %s', $what, $message); + } - $this->loading[$id] = $id; - try { - return $this->factories[$id](); - } finally { - unset($this->loading[$id]); + $r = new \ReflectionProperty($e, 'message'); + $r->setAccessible(true); + $r->setValue($e, $message); + + throw $e; } } @@ -74,8 +69,10 @@ public function __invoke($id) /** * @internal + * + * @return static */ - public function withContext($externalId, Container $container) + public function withContext(string $externalId, Container $container) { $locator = clone $this; $locator->externalId = $externalId; @@ -84,14 +81,16 @@ public function withContext($externalId, Container $container) return $locator; } - private function createServiceNotFoundMessage($id) + private function createNotFoundException(string $id): NotFoundExceptionInterface { if ($this->loading) { - return sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $this->formatAlternatives()); + $msg = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $this->formatAlternatives()); + + return new ServiceNotFoundException($id, end($this->loading) ?: null, null, [], $msg); } - $class = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 3); - $class = isset($class[2]['object']) ? \get_class($class[2]['object']) : null; + $class = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 4); + $class = isset($class[3]['object']) ? \get_class($class[3]['object']) : null; $externalId = $this->externalId ?: $class; $msg = []; @@ -127,10 +126,15 @@ private function createServiceNotFoundMessage($id) $msg[] = 'Try using dependency injection instead.'; } - return implode(' ', $msg); + return new ServiceNotFoundException($id, end($this->loading) ?: null, null, [], implode(' ', $msg)); + } + + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface + { + return new ServiceCircularReferenceException($id, $path); } - private function formatAlternatives(array $alternatives = null, $separator = 'and') + private function formatAlternatives(array $alternatives = null, string $separator = 'and'): string { $format = '"%s"%s'; if (null === $alternatives) { diff --git a/vendor/symfony/dependency-injection/ServiceSubscriberInterface.php b/vendor/symfony/dependency-injection/ServiceSubscriberInterface.php index 10c23875..a3b6ba79 100644 --- a/vendor/symfony/dependency-injection/ServiceSubscriberInterface.php +++ b/vendor/symfony/dependency-injection/ServiceSubscriberInterface.php @@ -11,40 +11,13 @@ namespace Symfony\Component\DependencyInjection; +use Symfony\Contracts\Service\ServiceSubscriberInterface as BaseServiceSubscriberInterface; + /** - * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. - * - * The getSubscribedServices method returns an array of service types required by such instances, - * optionally keyed by the service names used internally. Service types that start with an interrogation - * mark "?" are optional, while the other ones are mandatory service dependencies. - * - * The injected service locators SHOULD NOT allow access to any other services not specified by the method. - * - * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. - * This interface does not dictate any injection method for these service locators, although constructor - * injection is recommended. + * {@inheritdoc} * - * @author Nicolas Grekas + * @deprecated since Symfony 4.2, use Symfony\Contracts\Service\ServiceSubscriberInterface instead. */ -interface ServiceSubscriberInterface +interface ServiceSubscriberInterface extends BaseServiceSubscriberInterface { - /** - * Returns an array of service types required by such instances, optionally keyed by the service names used internally. - * - * For mandatory dependencies: - * - * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name - * internally to fetch a service which must implement Psr\Log\LoggerInterface. - * * ['Psr\Log\LoggerInterface'] is a shortcut for - * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] - * - * otherwise: - * - * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency - * * ['?Psr\Log\LoggerInterface'] is a shortcut for - * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] - * - * @return array The required service types, optionally keyed by service names - */ - public static function getSubscribedServices(); } diff --git a/vendor/symfony/dependency-injection/Tests/Argument/RewindableGeneratorTest.php b/vendor/symfony/dependency-injection/Tests/Argument/RewindableGeneratorTest.php deleted file mode 100644 index 31e3f11f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Argument/RewindableGeneratorTest.php +++ /dev/null @@ -1,53 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Argument; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; - -class RewindableGeneratorTest extends TestCase -{ - public function testImplementsCountable() - { - $this->assertInstanceOf(\Countable::class, new RewindableGenerator(function () { - yield 1; - }, 1)); - } - - public function testCountUsesProvidedValue() - { - $generator = new RewindableGenerator(function () { - yield 1; - }, 3); - - $this->assertCount(3, $generator); - } - - public function testCountUsesProvidedValueAsCallback() - { - $called = 0; - $generator = new RewindableGenerator(function () { - yield 1; - }, function () use (&$called) { - ++$called; - - return 3; - }); - - $this->assertSame(0, $called, 'Count callback is called lazily'); - $this->assertCount(3, $generator); - - \count($generator); - - $this->assertSame(1, $called, 'Count callback is called only once'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ChildDefinitionTest.php b/vendor/symfony/dependency-injection/Tests/ChildDefinitionTest.php deleted file mode 100644 index 50917483..00000000 --- a/vendor/symfony/dependency-injection/Tests/ChildDefinitionTest.php +++ /dev/null @@ -1,149 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\DefinitionDecorator; - -class ChildDefinitionTest extends TestCase -{ - public function testConstructor() - { - $def = new ChildDefinition('foo'); - - $this->assertSame('foo', $def->getParent()); - $this->assertSame([], $def->getChanges()); - } - - /** - * @dataProvider getPropertyTests - */ - public function testSetProperty($property, $changeKey) - { - $def = new ChildDefinition('foo'); - - $getter = 'get'.ucfirst($property); - $setter = 'set'.ucfirst($property); - - $this->assertNull($def->$getter()); - $this->assertSame($def, $def->$setter('foo')); - $this->assertSame('foo', $def->$getter()); - $this->assertSame([$changeKey => true], $def->getChanges()); - } - - public function getPropertyTests() - { - return [ - ['class', 'class'], - ['factory', 'factory'], - ['configurator', 'configurator'], - ['file', 'file'], - ]; - } - - public function testSetPublic() - { - $def = new ChildDefinition('foo'); - - $this->assertTrue($def->isPublic()); - $this->assertSame($def, $def->setPublic(false)); - $this->assertFalse($def->isPublic()); - $this->assertSame(['public' => true], $def->getChanges()); - } - - public function testSetLazy() - { - $def = new ChildDefinition('foo'); - - $this->assertFalse($def->isLazy()); - $this->assertSame($def, $def->setLazy(false)); - $this->assertFalse($def->isLazy()); - $this->assertSame(['lazy' => true], $def->getChanges()); - } - - public function testSetAutowired() - { - $def = new ChildDefinition('foo'); - - $this->assertFalse($def->isAutowired()); - $this->assertSame($def, $def->setAutowired(true)); - $this->assertTrue($def->isAutowired()); - $this->assertSame(['autowired' => true], $def->getChanges()); - } - - public function testSetArgument() - { - $def = new ChildDefinition('foo'); - - $this->assertSame([], $def->getArguments()); - $this->assertSame($def, $def->replaceArgument(0, 'foo')); - $this->assertSame(['index_0' => 'foo'], $def->getArguments()); - } - - public function testReplaceArgumentShouldRequireIntegerIndex() - { - $this->expectException('InvalidArgumentException'); - $def = new ChildDefinition('foo'); - - $def->replaceArgument('0', 'foo'); - } - - public function testReplaceArgument() - { - $def = new ChildDefinition('foo'); - - $def->setArguments([0 => 'foo', 1 => 'bar']); - $this->assertSame('foo', $def->getArgument(0)); - $this->assertSame('bar', $def->getArgument(1)); - - $this->assertSame($def, $def->replaceArgument(1, 'baz')); - $this->assertSame('foo', $def->getArgument(0)); - $this->assertSame('baz', $def->getArgument(1)); - - $this->assertSame([0 => 'foo', 1 => 'bar', 'index_1' => 'baz'], $def->getArguments()); - - $this->assertSame($def, $def->replaceArgument('$bar', 'val')); - $this->assertSame('val', $def->getArgument('$bar')); - $this->assertSame([0 => 'foo', 1 => 'bar', 'index_1' => 'baz', '$bar' => 'val'], $def->getArguments()); - } - - public function testGetArgumentShouldCheckBounds() - { - $this->expectException('OutOfBoundsException'); - $def = new ChildDefinition('foo'); - - $def->setArguments([0 => 'foo']); - $def->replaceArgument(0, 'foo'); - - $def->getArgument(1); - } - - public function testDefinitionDecoratorAliasExistsForBackwardsCompatibility() - { - $this->assertInstanceOf(ChildDefinition::class, new DefinitionDecorator('foo')); - } - - public function testCannotCallSetAutoconfigured() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\BadMethodCallException'); - $def = new ChildDefinition('foo'); - $def->setAutoconfigured(true); - } - - public function testCannotCallSetInstanceofConditionals() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\BadMethodCallException'); - $def = new ChildDefinition('foo'); - $def->setInstanceofConditionals(['Foo' => new ChildDefinition('')]); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php deleted file mode 100644 index 66b6e19c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php +++ /dev/null @@ -1,215 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; -use Symfony\Component\DependencyInjection\Compiler\RepeatedPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class AnalyzeServiceReferencesPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $container - ->register('a') - ->addArgument($ref1 = new Reference('b')) - ; - - $container - ->register('b') - ->addMethodCall('setA', [$ref2 = new Reference('a')]) - ; - - $container - ->register('c') - ->addArgument($ref3 = new Reference('a')) - ->addArgument($ref4 = new Reference('b')) - ; - - $container - ->register('d') - ->setProperty('foo', $ref5 = new Reference('b')) - ; - - $container - ->register('e') - ->setConfigurator([$ref6 = new Reference('b'), 'methodName']) - ; - - $graph = $this->process($container); - - $this->assertCount(4, $edges = $graph->getNode('b')->getInEdges()); - - $this->assertSame($ref1, $edges[0]->getValue()); - $this->assertSame($ref4, $edges[1]->getValue()); - $this->assertSame($ref5, $edges[2]->getValue()); - $this->assertSame($ref6, $edges[3]->getValue()); - } - - public function testProcessMarksEdgesLazyWhenReferencedServiceIsLazy() - { - $container = new ContainerBuilder(); - - $container - ->register('a') - ->setLazy(true) - ->addArgument($ref1 = new Reference('b')) - ; - - $container - ->register('b') - ->addArgument($ref2 = new Reference('a')) - ; - - $graph = $this->process($container); - - $this->assertCount(1, $graph->getNode('b')->getInEdges()); - $this->assertCount(1, $edges = $graph->getNode('a')->getInEdges()); - - $this->assertSame($ref2, $edges[0]->getValue()); - $this->assertTrue($edges[0]->isLazy()); - } - - public function testProcessMarksEdgesLazyWhenReferencedFromIteratorArgument() - { - $container = new ContainerBuilder(); - $container->register('a'); - $container->register('b'); - - $container - ->register('c') - ->addArgument($ref1 = new Reference('a')) - ->addArgument(new IteratorArgument([$ref2 = new Reference('b')])) - ; - - $graph = $this->process($container); - - $this->assertCount(1, $graph->getNode('a')->getInEdges()); - $this->assertCount(1, $graph->getNode('b')->getInEdges()); - $this->assertCount(2, $edges = $graph->getNode('c')->getOutEdges()); - - $this->assertSame($ref1, $edges[0]->getValue()); - $this->assertFalse($edges[0]->isLazy()); - $this->assertSame($ref2, $edges[1]->getValue()); - $this->assertTrue($edges[1]->isLazy()); - } - - public function testProcessDetectsReferencesFromInlinedDefinitions() - { - $container = new ContainerBuilder(); - - $container - ->register('a') - ; - - $container - ->register('b') - ->addArgument(new Definition(null, [$ref = new Reference('a')])) - ; - - $graph = $this->process($container); - - $this->assertCount(1, $refs = $graph->getNode('a')->getInEdges()); - $this->assertSame($ref, $refs[0]->getValue()); - } - - public function testProcessDetectsReferencesFromIteratorArguments() - { - $container = new ContainerBuilder(); - - $container - ->register('a') - ; - - $container - ->register('b') - ->addArgument(new IteratorArgument([$ref = new Reference('a')])) - ; - - $graph = $this->process($container); - - $this->assertCount(1, $refs = $graph->getNode('a')->getInEdges()); - $this->assertSame($ref, $refs[0]->getValue()); - } - - public function testProcessDetectsReferencesFromInlinedFactoryDefinitions() - { - $container = new ContainerBuilder(); - - $container - ->register('a') - ; - - $factory = new Definition(); - $factory->setFactory([new Reference('a'), 'a']); - - $container - ->register('b') - ->addArgument($factory) - ; - - $graph = $this->process($container); - - $this->assertTrue($graph->hasNode('a')); - $this->assertCount(1, $refs = $graph->getNode('a')->getInEdges()); - } - - public function testProcessDoesNotSaveDuplicateReferences() - { - $container = new ContainerBuilder(); - - $container - ->register('a') - ; - $container - ->register('b') - ->addArgument(new Definition(null, [$ref1 = new Reference('a')])) - ->addArgument(new Definition(null, [$ref2 = new Reference('a')])) - ; - - $graph = $this->process($container); - - $this->assertCount(2, $graph->getNode('a')->getInEdges()); - } - - public function testProcessDetectsFactoryReferences() - { - $container = new ContainerBuilder(); - - $container - ->register('foo', 'stdClass') - ->setFactory(['stdClass', 'getInstance']); - - $container - ->register('bar', 'stdClass') - ->setFactory([new Reference('foo'), 'getInstance']); - - $graph = $this->process($container); - - $this->assertTrue($graph->hasNode('foo')); - $this->assertCount(1, $graph->getNode('foo')->getInEdges()); - } - - protected function process(ContainerBuilder $container) - { - $pass = new RepeatedPass([new AnalyzeServiceReferencesPass()]); - $pass->process($container); - - return $container->getCompiler()->getServiceReferenceGraph(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/AutoAliasServicePassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/AutoAliasServicePassTest.php deleted file mode 100644 index 4e17778f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/AutoAliasServicePassTest.php +++ /dev/null @@ -1,108 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\AutoAliasServicePass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class AutoAliasServicePassTest extends TestCase -{ - public function testProcessWithMissingParameter() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException'); - $container = new ContainerBuilder(); - - $container->register('example') - ->addTag('auto_alias', ['format' => '%non_existing%.example']); - - $pass = new AutoAliasServicePass(); - $pass->process($container); - } - - public function testProcessWithMissingFormat() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $container = new ContainerBuilder(); - - $container->register('example') - ->addTag('auto_alias', []); - $container->setParameter('existing', 'mysql'); - - $pass = new AutoAliasServicePass(); - $pass->process($container); - } - - public function testProcessWithNonExistingAlias() - { - $container = new ContainerBuilder(); - - $container->register('example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassDefault') - ->addTag('auto_alias', ['format' => '%existing%.example']); - $container->setParameter('existing', 'mysql'); - - $pass = new AutoAliasServicePass(); - $pass->process($container); - - $this->assertEquals('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassDefault', $container->getDefinition('example')->getClass()); - } - - public function testProcessWithExistingAlias() - { - $container = new ContainerBuilder(); - - $container->register('example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassDefault') - ->addTag('auto_alias', ['format' => '%existing%.example']); - - $container->register('mysql.example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMysql'); - $container->setParameter('existing', 'mysql'); - - $pass = new AutoAliasServicePass(); - $pass->process($container); - - $this->assertTrue($container->hasAlias('example')); - $this->assertEquals('mysql.example', $container->getAlias('example')); - $this->assertSame('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMysql', $container->getDefinition('mysql.example')->getClass()); - } - - public function testProcessWithManualAlias() - { - $container = new ContainerBuilder(); - - $container->register('example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassDefault') - ->addTag('auto_alias', ['format' => '%existing%.example']); - - $container->register('mysql.example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMysql'); - $container->register('mariadb.example', 'Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMariaDb'); - $container->setAlias('example', 'mariadb.example'); - $container->setParameter('existing', 'mysql'); - - $pass = new AutoAliasServicePass(); - $pass->process($container); - - $this->assertTrue($container->hasAlias('example')); - $this->assertEquals('mariadb.example', $container->getAlias('example')); - $this->assertSame('Symfony\Component\DependencyInjection\Tests\Compiler\ServiceClassMariaDb', $container->getDefinition('mariadb.example')->getClass()); - } -} - -class ServiceClassDefault -{ -} - -class ServiceClassMysql extends ServiceClassDefault -{ -} - -class ServiceClassMariaDb extends ServiceClassMysql -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/AutowireExceptionPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/AutowireExceptionPassTest.php deleted file mode 100644 index c5ba149a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/AutowireExceptionPassTest.php +++ /dev/null @@ -1,145 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\AutowireExceptionPass; -use Symfony\Component\DependencyInjection\Compiler\AutowirePass; -use Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException; - -/** - * @group legacy - */ -class AutowireExceptionPassTest extends TestCase -{ - public function testThrowsException() - { - $autowirePass = $this->getMockBuilder(AutowirePass::class) - ->getMock(); - - $autowireException = new AutowiringFailedException('foo_service_id', 'An autowiring exception message'); - $autowirePass->expects($this->any()) - ->method('getAutowiringExceptions') - ->willReturn([$autowireException]); - - $inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class) - ->getMock(); - $inlinePass->expects($this->any()) - ->method('getInlinedServiceIds') - ->willReturn([]); - - $container = new ContainerBuilder(); - $container->register('foo_service_id'); - - $pass = new AutowireExceptionPass($autowirePass, $inlinePass); - - try { - $pass->process($container); - $this->fail('->process() should throw the exception if the service id exists'); - } catch (\Exception $e) { - $this->assertSame($autowireException, $e); - } - } - - public function testThrowExceptionIfServiceInlined() - { - $autowirePass = $this->getMockBuilder(AutowirePass::class) - ->getMock(); - - $autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message'); - $autowirePass->expects($this->any()) - ->method('getAutowiringExceptions') - ->willReturn([$autowireException]); - - $inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class) - ->getMock(); - $inlinePass->expects($this->any()) - ->method('getInlinedServiceIds') - ->willReturn([ - // a_service inlined into b_service - 'a_service' => ['b_service'], - // b_service inlined into c_service - 'b_service' => ['c_service'], - ]); - - $container = new ContainerBuilder(); - // ONLY register c_service in the final container - $container->register('c_service', 'stdClass'); - - $pass = new AutowireExceptionPass($autowirePass, $inlinePass); - - try { - $pass->process($container); - $this->fail('->process() should throw the exception if the service id exists'); - } catch (\Exception $e) { - $this->assertSame($autowireException, $e); - } - } - - public function testDoNotThrowExceptionIfServiceInlinedButRemoved() - { - $autowirePass = $this->getMockBuilder(AutowirePass::class) - ->getMock(); - - $autowireException = new AutowiringFailedException('a_service', 'An autowiring exception message'); - $autowirePass->expects($this->any()) - ->method('getAutowiringExceptions') - ->willReturn([$autowireException]); - - $inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class) - ->getMock(); - $inlinePass->expects($this->any()) - ->method('getInlinedServiceIds') - ->willReturn([ - // a_service inlined into b_service - 'a_service' => ['b_service'], - // b_service inlined into c_service - 'b_service' => ['c_service'], - ]); - - // do NOT register c_service in the container - $container = new ContainerBuilder(); - - $pass = new AutowireExceptionPass($autowirePass, $inlinePass); - - $pass->process($container); - // mark the test as passed - $this->assertTrue(true); - } - - public function testNoExceptionIfServiceRemoved() - { - $autowirePass = $this->getMockBuilder(AutowirePass::class) - ->getMock(); - - $autowireException = new AutowiringFailedException('non_existent_service'); - $autowirePass->expects($this->any()) - ->method('getAutowiringExceptions') - ->willReturn([$autowireException]); - - $inlinePass = $this->getMockBuilder(InlineServiceDefinitionsPass::class) - ->getMock(); - $inlinePass->expects($this->any()) - ->method('getInlinedServiceIds') - ->willReturn([]); - - $container = new ContainerBuilder(); - - $pass = new AutowireExceptionPass($autowirePass, $inlinePass); - - $pass->process($container); - // mark the test as passed - $this->assertTrue(true); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/AutowirePassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/AutowirePassTest.php deleted file mode 100644 index 6c11a94c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/AutowirePassTest.php +++ /dev/null @@ -1,988 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\Compiler\AutowirePass; -use Symfony\Component\DependencyInjection\Compiler\AutowireRequiredMethodsPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Exception\AutowiringFailedException; -use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic; -use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\MultipleArgumentsOptionalScalarNotReallyOptional; -use Symfony\Component\DependencyInjection\TypedReference; - -require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php'; - -/** - * @author Kévin Dunglas - */ -class AutowirePassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $container->register(Foo::class); - $barDefinition = $container->register('bar', Bar::class); - $barDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(1, $container->getDefinition('bar')->getArguments()); - $this->assertEquals(Foo::class, (string) $container->getDefinition('bar')->getArgument(0)); - } - - /** - * @requires PHP 5.6 - */ - public function testProcessVariadic() - { - $container = new ContainerBuilder(); - $container->register(Foo::class); - $definition = $container->register('fooVariadic', FooVariadic::class); - $definition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(1, $container->getDefinition('fooVariadic')->getArguments()); - $this->assertEquals(Foo::class, (string) $container->getDefinition('fooVariadic')->getArgument(0)); - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should alias the "Symfony\Component\DependencyInjection\Tests\Compiler\B" service to "Symfony\Component\DependencyInjection\Tests\Compiler\A" instead. - * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessageInSymfony4 Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service. - */ - public function testProcessAutowireParent() - { - $container = new ContainerBuilder(); - - $container->register(B::class); - $cDefinition = $container->register('c', C::class); - $cDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(1, $container->getDefinition('c')->getArguments()); - $this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0)); - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" to "Symfony\Component\DependencyInjection\Tests\Compiler\AInterface" instead. - * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessageInSymfony4 Cannot autowire service "c": argument "$a" of method "Symfony\Component\DependencyInjection\Tests\Compiler\C::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\B" service. - */ - public function testProcessLegacyAutowireWithAvailableInterface() - { - $container = new ContainerBuilder(); - - $container->setAlias(AInterface::class, B::class); - $container->register(B::class); - $cDefinition = $container->register('c', C::class); - $cDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(1, $container->getDefinition('c')->getArguments()); - $this->assertEquals(B::class, (string) $container->getDefinition('c')->getArgument(0)); - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should alias the "Symfony\Component\DependencyInjection\Tests\Compiler\F" service to "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" instead. - * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessageInSymfony4 Cannot autowire service "g": argument "$d" of method "Symfony\Component\DependencyInjection\Tests\Compiler\G::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DInterface" but no such service exists. You should maybe alias this interface to the existing "Symfony\Component\DependencyInjection\Tests\Compiler\F" service. - */ - public function testProcessAutowireInterface() - { - $container = new ContainerBuilder(); - - $container->register(F::class); - $gDefinition = $container->register('g', G::class); - $gDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(3, $container->getDefinition('g')->getArguments()); - $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(0)); - $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(1)); - $this->assertEquals(F::class, (string) $container->getDefinition('g')->getArgument(2)); - } - - public function testCompleteExistingDefinition() - { - $container = new ContainerBuilder(); - - $container->register('b', B::class); - $container->register(DInterface::class, F::class); - $hDefinition = $container->register('h', H::class)->addArgument(new Reference('b')); - $hDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(2, $container->getDefinition('h')->getArguments()); - $this->assertEquals('b', (string) $container->getDefinition('h')->getArgument(0)); - $this->assertEquals(DInterface::class, (string) $container->getDefinition('h')->getArgument(1)); - } - - public function testCompleteExistingDefinitionWithNotDefinedArguments() - { - $container = new ContainerBuilder(); - - $container->register(B::class); - $container->register(DInterface::class, F::class); - $hDefinition = $container->register('h', H::class)->addArgument('')->addArgument(''); - $hDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(2, $container->getDefinition('h')->getArguments()); - $this->assertEquals(B::class, (string) $container->getDefinition('h')->getArgument(0)); - $this->assertEquals(DInterface::class, (string) $container->getDefinition('h')->getArgument(1)); - } - - /** - * @group legacy - */ - public function testExceptionsAreStored() - { - $container = new ContainerBuilder(); - - $container->register('c1', CollisionA::class); - $container->register('c2', CollisionB::class); - $container->register('c3', CollisionB::class); - $aDefinition = $container->register('a', CannotBeAutowired::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(false); - $pass->process($container); - $this->assertCount(1, $pass->getAutowiringExceptions()); - } - - public function testPrivateConstructorThrowsAutowireException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Invalid service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public.'); - $container = new ContainerBuilder(); - - $container->autowire('private_service', PrivateConstructor::class); - - $pass = new AutowirePass(true); - $pass->process($container); - } - - public function testTypeCollision() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2", "c3".'); - $container = new ContainerBuilder(); - - $container->register('c1', CollisionA::class); - $container->register('c2', CollisionB::class); - $container->register('c3', CollisionB::class); - $aDefinition = $container->register('a', CannotBeAutowired::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testTypeNotGuessable() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".'); - $container = new ContainerBuilder(); - - $container->register('a1', Foo::class); - $container->register('a2', Foo::class); - $aDefinition = $container->register('a', NotGuessableArgument::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testTypeNotGuessableWithSubclass() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".'); - $container = new ContainerBuilder(); - - $container->register('a1', B::class); - $container->register('a2', B::class); - $aDefinition = $container->register('a', NotGuessableArgumentForSubclass::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testTypeNotGuessableNoServicesFound() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists.'); - $container = new ContainerBuilder(); - - $aDefinition = $container->register('a', CannotBeAutowired::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - /** - * @requires PHP 8 - */ - public function testTypeNotGuessableUnionType() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\UnionClasses::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA|Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB" but this class was not found.'); - $container = new ContainerBuilder(); - - $container->register(CollisionA::class); - $container->register(CollisionB::class); - - $aDefinition = $container->register('a', UnionClasses::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testTypeNotGuessableWithTypeSet() - { - $container = new ContainerBuilder(); - - $container->register('a1', Foo::class); - $container->register('a2', Foo::class); - $container->register(Foo::class, Foo::class); - $aDefinition = $container->register('a', NotGuessableArgument::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertCount(1, $container->getDefinition('a')->getArguments()); - $this->assertEquals(Foo::class, (string) $container->getDefinition('a')->getArgument(0)); - } - - public function testWithTypeSet() - { - $container = new ContainerBuilder(); - - $container->register('c1', CollisionA::class); - $container->register('c2', CollisionB::class); - $container->setAlias(CollisionInterface::class, 'c2'); - $aDefinition = $container->register('a', CannotBeAutowired::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertCount(1, $container->getDefinition('a')->getArguments()); - $this->assertEquals(CollisionInterface::class, (string) $container->getDefinition('a')->getArgument(0)); - } - - /** - * @group legacy - * @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" is deprecated since Symfony 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" instead. - * @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" is deprecated since Symfony 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" instead. - */ - public function testCreateDefinition() - { - $container = new ContainerBuilder(); - - $coopTilleulsDefinition = $container->register('coop_tilleuls', LesTilleuls::class); - $coopTilleulsDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertCount(2, $container->getDefinition('coop_tilleuls')->getArguments()); - $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0)); - $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas', $container->getDefinition('coop_tilleuls')->getArgument(1)); - - $dunglasDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas'); - $this->assertEquals(Dunglas::class, $dunglasDefinition->getClass()); - $this->assertFalse($dunglasDefinition->isPublic()); - $this->assertCount(1, $dunglasDefinition->getArguments()); - $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille', $dunglasDefinition->getArgument(0)); - - $lilleDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille'); - $this->assertEquals(Lille::class, $lilleDefinition->getClass()); - } - - public function testResolveParameter() - { - $container = new ContainerBuilder(); - - $container->setParameter('class_name', Bar::class); - $container->register(Foo::class); - $barDefinition = $container->register('bar', '%class_name%'); - $barDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertEquals(Foo::class, $container->getDefinition('bar')->getArgument(0)); - } - - public function testOptionalParameter() - { - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Foo::class); - $optDefinition = $container->register('opt', OptionalParameter::class); - $optDefinition->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('opt'); - $this->assertNull($definition->getArgument(0)); - $this->assertEquals(A::class, $definition->getArgument(1)); - $this->assertEquals(Foo::class, $definition->getArgument(2)); - } - - /** - * @requires PHP 8 - */ - public function testParameterWithNullUnionIsSkipped() - { - $container = new ContainerBuilder(); - - $optDefinition = $container->register('opt', UnionNull::class); - $optDefinition->setAutowired(true); - - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('opt'); - $this->assertNull($definition->getArgument(0)); - } - - /** - * @requires PHP 8 - */ - public function testParameterWithNullUnionIsAutowired() - { - $container = new ContainerBuilder(); - - $container->register(CollisionInterface::class, CollisionA::class); - - $optDefinition = $container->register('opt', UnionNull::class); - $optDefinition->setAutowired(true); - - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('opt'); - $this->assertEquals(CollisionInterface::class, $definition->getArgument(0)); - } - - public function testDontTriggerAutowiring() - { - $container = new ContainerBuilder(); - - $container->register(Foo::class); - $container->register('bar', Bar::class); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertCount(0, $container->getDefinition('bar')->getArguments()); - } - - public function testClassNotFoundThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class was not found.'); - $container = new ContainerBuilder(); - - $aDefinition = $container->register('a', BadTypeHintedArgument::class); - $aDefinition->setAutowired(true); - - $container->register(Dunglas::class, Dunglas::class); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testParentClassNotFoundThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessageMatches('{^Cannot autowire service "a": argument "\$r" of method "(Symfony\\\\Component\\\\DependencyInjection\\\\Tests\\\\Compiler\\\\)BadParentTypeHintedArgument::__construct\(\)" has type "\1OptionalServiceClass" but this class is missing a parent class \(Class "?Symfony\\\\Bug\\\\NotExistClass"? not found}'); - - $container = new ContainerBuilder(); - - $aDefinition = $container->register('a', BadParentTypeHintedArgument::class); - $aDefinition->setAutowired(true); - - $container->register(Dunglas::class, Dunglas::class); - - $pass = new AutowirePass(); - $pass->process($container); - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead. - * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException - * @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but this service is abstract. You should maybe alias this class to the existing "foo" service. - */ - public function testDontUseAbstractServices() - { - $container = new ContainerBuilder(); - - $container->register(Foo::class)->setAbstract(true); - $container->register('foo', Foo::class); - $container->register('bar', Bar::class)->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - } - - public function testSomeSpecificArgumentsAreSet() - { - $container = new ContainerBuilder(); - - $container->register('foo', Foo::class); - $container->register(A::class); - $container->register(Dunglas::class); - $container->register('multiple', MultipleArguments::class) - ->setAutowired(true) - // set the 2nd (index 1) argument only: autowire the first and third - // args are: A, Foo, Dunglas - ->setArguments([ - 1 => new Reference('foo'), - 3 => ['bar'], - ]); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('multiple'); - $this->assertEquals( - [ - new TypedReference(A::class, A::class, MultipleArguments::class), - new Reference('foo'), - new TypedReference(Dunglas::class, Dunglas::class, MultipleArguments::class), - ['bar'], - ], - $definition->getArguments() - ); - } - - public function testScalarArgsCannotBeAutowired() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "arg_no_type_hint": argument "$bar" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" is type-hinted "array", you should configure its value explicitly.'); - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Dunglas::class); - $container->register('arg_no_type_hint', MultipleArguments::class) - ->setArguments([1 => 'foo']) - ->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - } - - /** - * @requires PHP 8 - */ - public function testUnionScalarArgsCannotBeAutowired() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "union_scalars": argument "$timeout" of method "Symfony\Component\DependencyInjection\Tests\Compiler\UnionScalars::__construct()" is type-hinted "int|float", you should configure its value explicitly.'); - $container = new ContainerBuilder(); - - $container->register('union_scalars', UnionScalars::class) - ->setAutowired(true); - - (new AutowirePass())->process($container); - } - - public function testNoTypeArgsCannotBeAutowired() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "arg_no_type_hint": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\MultipleArguments::__construct()" has no type-hint, you should configure its value explicitly.'); - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Dunglas::class); - $container->register('arg_no_type_hint', MultipleArguments::class) - ->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - } - - /** - * @requires PHP < 8 - */ - public function testOptionalScalarNotReallyOptionalUsesDefaultValue() - { - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Lille::class); - $definition = $container->register('not_really_optional_scalar', MultipleArgumentsOptionalScalarNotReallyOptional::class) - ->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertSame('default_val', $definition->getArgument(1)); - } - - public function testOptionalScalarArgsDontMessUpOrder() - { - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Lille::class); - $container->register('with_optional_scalar', MultipleArgumentsOptionalScalar::class) - ->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('with_optional_scalar'); - $this->assertEquals( - [ - new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalar::class), - // use the default value - 'default_val', - new TypedReference(Lille::class, Lille::class), - ], - $definition->getArguments() - ); - } - - public function testOptionalScalarArgsNotPassedIfLast() - { - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Lille::class); - $container->register('with_optional_scalar_last', MultipleArgumentsOptionalScalarLast::class) - ->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('with_optional_scalar_last'); - $this->assertEquals( - [ - new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalarLast::class), - new TypedReference(Lille::class, Lille::class, MultipleArgumentsOptionalScalarLast::class), - ], - $definition->getArguments() - ); - } - - public function testOptionalArgsNoRequiredForCoreClasses() - { - $container = new ContainerBuilder(); - - $container->register('foo', \SplFileObject::class) - ->addArgument('foo.txt') - ->setAutowired(true); - - (new AutowirePass())->process($container); - - $definition = $container->getDefinition('foo'); - $this->assertEquals( - ['foo.txt'], - $definition->getArguments() - ); - } - - public function testSetterInjection() - { - $container = new ContainerBuilder(); - $container->register(Foo::class); - $container->register(A::class); - $container->register(CollisionA::class); - $container->register(CollisionB::class); - - // manually configure *one* call, to override autowiring - $container - ->register('setter_injection', SetterInjection::class) - ->setAutowired(true) - ->addMethodCall('setWithCallsConfigured', ['manual_arg1', 'manual_arg2']) - ; - - (new ResolveClassPass())->process($container); - (new AutowireRequiredMethodsPass())->process($container); - (new AutowirePass())->process($container); - - $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); - - $this->assertEquals( - ['setWithCallsConfigured', 'setFoo', 'setDependencies', 'setChildMethodWithoutDocBlock'], - array_column($methodCalls, 0) - ); - - // test setWithCallsConfigured args - $this->assertEquals( - ['manual_arg1', 'manual_arg2'], - $methodCalls[0][1] - ); - // test setFoo args - $this->assertEquals( - [new TypedReference(Foo::class, Foo::class, SetterInjection::class)], - $methodCalls[1][1] - ); - } - - public function testWithNonExistingSetterAndAutowiring() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass": method "setLogger()" does not exist.'); - $container = new ContainerBuilder(); - - $definition = $container->register(CaseSensitiveClass::class, CaseSensitiveClass::class)->setAutowired(true); - $definition->addMethodCall('setLogger'); - - (new ResolveClassPass())->process($container); - (new AutowireRequiredMethodsPass())->process($container); - (new AutowirePass())->process($container); - } - - public function testExplicitMethodInjection() - { - $container = new ContainerBuilder(); - $container->register(Foo::class); - $container->register(A::class); - $container->register(CollisionA::class); - $container->register(CollisionB::class); - - $container - ->register('setter_injection', SetterInjection::class) - ->setAutowired(true) - ->addMethodCall('notASetter', []) - ; - - (new ResolveClassPass())->process($container); - (new AutowireRequiredMethodsPass())->process($container); - (new AutowirePass())->process($container); - - $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); - - $this->assertEquals( - ['notASetter', 'setFoo', 'setDependencies', 'setWithCallsConfigured', 'setChildMethodWithoutDocBlock'], - array_column($methodCalls, 0) - ); - $this->assertEquals( - [new TypedReference(A::class, A::class, SetterInjection::class)], - $methodCalls[0][1] - ); - } - - /** - * @group legacy - * @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\A" is deprecated since Symfony 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\A" instead. - */ - public function testTypedReference() - { - $container = new ContainerBuilder(); - - $container - ->register('bar', Bar::class) - ->setProperty('a', [new TypedReference(A::class, A::class, Bar::class)]) - ; - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertSame(A::class, $container->getDefinition('autowired.'.A::class)->getClass()); - } - - /** - * @dataProvider getCreateResourceTests - * @group legacy - */ - public function testCreateResourceForClass($className, $isEqual) - { - $startingResource = AutowirePass::createResourceForClass( - new \ReflectionClass(ClassForResource::class) - ); - $newResource = AutowirePass::createResourceForClass( - new \ReflectionClass(__NAMESPACE__.'\\'.$className) - ); - - // hack so the objects don't differ by the class name - $startingReflObject = new \ReflectionObject($startingResource); - $reflProp = $startingReflObject->getProperty('class'); - $reflProp->setAccessible(true); - $reflProp->setValue($startingResource, __NAMESPACE__.'\\'.$className); - - if ($isEqual) { - $this->assertEquals($startingResource, $newResource); - } else { - $this->assertNotEquals($startingResource, $newResource); - } - } - - public function getCreateResourceTests() - { - return [ - ['IdenticalClassResource', true], - ['ClassChangedConstructorArgs', false], - ]; - } - - public function testIgnoreServiceWithClassNotExisting() - { - $container = new ContainerBuilder(); - - $container->register('class_not_exist', OptionalServiceClass::class); - - $barDefinition = $container->register('bar', Bar::class); - $barDefinition->setAutowired(true); - - $container->register(Foo::class, Foo::class); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertTrue($container->hasDefinition('bar')); - } - - public function testSetterInjectionCollisionThrowsException() - { - $container = new ContainerBuilder(); - - $container->register('c1', CollisionA::class); - $container->register('c2', CollisionB::class); - $aDefinition = $container->register('setter_injection_collision', SetterInjectionCollision::class); - $aDefinition->setAutowired(true); - - (new AutowireRequiredMethodsPass())->process($container); - - $pass = new AutowirePass(); - - try { - $pass->process($container); - } catch (AutowiringFailedException $e) { - } - - $this->assertNotNull($e); - $this->assertSame('Cannot autowire service "setter_injection_collision": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\SetterInjectionCollision::setMultipleInstancesForOneArg()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2".', $e->getMessage()); - } - - public function testInterfaceWithNoImplementationSuggestToWriteOne() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "my_service": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\K::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" but no such service exists. Did you create a class that implements this interface?'); - $container = new ContainerBuilder(); - - $aDefinition = $container->register('my_service', K::class); - $aDefinition->setAutowired(true); - - (new AutowireRequiredMethodsPass())->process($container); - - $pass = new AutowirePass(); - $pass->process($container); - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. You should rename (or alias) the "foo" service to "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" instead. - * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException - * @expectedExceptionMessageInSymfony4 Cannot autowire service "bar": argument "$foo" of method "Symfony\Component\DependencyInjection\Tests\Compiler\Bar::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to the existing "foo" service. - */ - public function testProcessDoesNotTriggerDeprecations() - { - $container = new ContainerBuilder(); - $container->register('deprecated', 'Symfony\Component\DependencyInjection\Tests\Fixtures\DeprecatedClass')->setDeprecated(true); - $container->register('foo', Foo::class); - $container->register('bar', Bar::class)->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertTrue($container->hasDefinition('deprecated')); - $this->assertTrue($container->hasDefinition('foo')); - $this->assertTrue($container->hasDefinition('bar')); - } - - public function testEmptyStringIsKept() - { - $container = new ContainerBuilder(); - - $container->register(A::class); - $container->register(Lille::class); - $container->register('foo', MultipleArgumentsOptionalScalar::class) - ->setAutowired(true) - ->setArguments(['', '']); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertEquals([new TypedReference(A::class, A::class, MultipleArgumentsOptionalScalar::class), '', new TypedReference(Lille::class, Lille::class)], $container->getDefinition('foo')->getArguments()); - } - - public function testWithFactory() - { - $container = new ContainerBuilder(); - - $container->register(Foo::class); - $definition = $container->register('a', A::class) - ->setFactory([A::class, 'create']) - ->setAutowired(true); - - (new ResolveClassPass())->process($container); - (new AutowirePass())->process($container); - - $this->assertEquals([new TypedReference(Foo::class, Foo::class, A::class)], $definition->getArguments()); - } - - /** - * @dataProvider provideNotWireableCalls - */ - public function testNotWireableCalls($method, $expectedMsg) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $container = new ContainerBuilder(); - - $foo = $container->register('foo', NotWireable::class)->setAutowired(true) - ->addMethodCall('setBar', []) - ->addMethodCall('setOptionalNotAutowireable', []) - ->addMethodCall('setOptionalNoTypeHint', []) - ->addMethodCall('setOptionalArgNoAutowireable', []) - ; - - if ($method) { - $foo->addMethodCall($method, []); - } - - $this->expectException(RuntimeException::class); - $this->expectExceptionMessage($expectedMsg); - - (new ResolveClassPass())->process($container); - (new AutowireRequiredMethodsPass())->process($container); - (new AutowirePass())->process($container); - } - - public function provideNotWireableCalls() - { - return [ - ['setNotAutowireable', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setNotAutowireable()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class was not found.'], - ['setDifferentNamespace', 'Cannot autowire service "foo": argument "$n" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setDifferentNamespace()" references class "stdClass" but no such service exists. It cannot be auto-registered because it is from a different root namespace.'], - [null, 'Invalid service "foo": method "Symfony\Component\DependencyInjection\Tests\Compiler\NotWireable::setProtectedMethod()" must be public.'], - ]; - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead. - * @expectedExceptionInSymfony4 \Symfony\Component\DependencyInjection\Exception\AutowiringFailedException - * @expectedExceptionMessageInSymfony4 Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead. - */ - public function testByIdAlternative() - { - $container = new ContainerBuilder(); - - $container->setAlias(IInterface::class, 'i'); - $container->register('i', I::class); - $container->register('j', J::class) - ->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - /** - * @group legacy - * @expectedDeprecation Autowiring services based on the types they implement is deprecated since Symfony 3.3 and won't be supported in version 4.0. Try changing the type-hint for "Symfony\Component\DependencyInjection\Tests\Compiler\A" in "Symfony\Component\DependencyInjection\Tests\Compiler\Bar" to "Symfony\Component\DependencyInjection\Tests\Compiler\AInterface" instead. - */ - public function testTypedReferenceDeprecationNotice() - { - $container = new ContainerBuilder(); - - $container->register('aClass', A::class); - $container->setAlias(AInterface::class, 'aClass'); - $container - ->register('bar', Bar::class) - ->setProperty('a', [new TypedReference(A::class, A::class, Bar::class)]) - ; - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testExceptionWhenAliasExists() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. Try changing the type-hint to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface" instead.'); - $container = new ContainerBuilder(); - - // multiple I services... but there *is* IInterface available - $container->setAlias(IInterface::class, 'i'); - $container->register('i', I::class); - $container->register('i2', I::class); - // J type-hints against I concretely - $container->register('j', J::class) - ->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testExceptionWhenAliasDoesNotExist() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); - $this->expectExceptionMessage('Cannot autowire service "j": argument "$i" of method "Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. You should maybe alias this class to one of these existing services: "i", "i2".'); - - $container = new ContainerBuilder(); - - // multiple I instances... but no IInterface alias - $container->register('i', I::class); - $container->register('i2', I::class); - // J type-hints against I concretely - $container->register('j', J::class) - ->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } - - public function testInlineServicesAreNotCandidates() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(realpath(__DIR__.'/../Fixtures/xml'))); - $loader->load('services_inline_not_candidate.xml'); - - $pass = new AutowirePass(); - $pass->process($container); - - $this->assertSame([], $container->getDefinition('autowired')->getArguments()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/AutowireRequiredMethodsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/AutowireRequiredMethodsPassTest.php deleted file mode 100644 index 644b32d2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/AutowireRequiredMethodsPassTest.php +++ /dev/null @@ -1,80 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\AutowireRequiredMethodsPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php'; - -class AutowireRequiredMethodsPassTest extends TestCase -{ - public function testSetterInjection() - { - $container = new ContainerBuilder(); - $container->register(Foo::class); - $container->register(A::class); - $container->register(CollisionA::class); - $container->register(CollisionB::class); - - // manually configure *one* call, to override autowiring - $container - ->register('setter_injection', SetterInjection::class) - ->setAutowired(true) - ->addMethodCall('setWithCallsConfigured', ['manual_arg1', 'manual_arg2']); - - (new ResolveClassPass())->process($container); - (new AutowireRequiredMethodsPass())->process($container); - - $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); - - $this->assertEquals( - ['setWithCallsConfigured', 'setFoo', 'setDependencies', 'setChildMethodWithoutDocBlock'], - array_column($methodCalls, 0) - ); - - // test setWithCallsConfigured args - $this->assertEquals( - ['manual_arg1', 'manual_arg2'], - $methodCalls[0][1] - ); - // test setFoo args - $this->assertEquals([], $methodCalls[1][1]); - } - - public function testExplicitMethodInjection() - { - $container = new ContainerBuilder(); - $container->register(Foo::class); - $container->register(A::class); - $container->register(CollisionA::class); - $container->register(CollisionB::class); - - $container - ->register('setter_injection', SetterInjection::class) - ->setAutowired(true) - ->addMethodCall('notASetter', []); - - (new ResolveClassPass())->process($container); - (new AutowireRequiredMethodsPass())->process($container); - - $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); - - $this->assertEquals( - ['notASetter', 'setFoo', 'setDependencies', 'setWithCallsConfigured', 'setChildMethodWithoutDocBlock'], - array_column($methodCalls, 0) - ); - $this->assertEquals([], $methodCalls[0][1]); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/CheckArgumentsValidityPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/CheckArgumentsValidityPassTest.php deleted file mode 100644 index 9554c23b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/CheckArgumentsValidityPassTest.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\CheckArgumentsValidityPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -/** - * @author Kévin Dunglas - */ -class CheckArgumentsValidityPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $definition = $container->register('foo'); - $definition->setArguments([null, 1, 'a']); - $definition->setMethodCalls([ - ['bar', ['a', 'b']], - ['baz', ['c', 'd']], - ]); - - $pass = new CheckArgumentsValidityPass(); - $pass->process($container); - - $this->assertEquals([null, 1, 'a'], $container->getDefinition('foo')->getArguments()); - $this->assertEquals([ - ['bar', ['a', 'b']], - ['baz', ['c', 'd']], - ], $container->getDefinition('foo')->getMethodCalls()); - } - - /** - * @dataProvider definitionProvider - */ - public function testException(array $arguments, array $methodCalls) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - $definition = $container->register('foo'); - $definition->setArguments($arguments); - $definition->setMethodCalls($methodCalls); - - $pass = new CheckArgumentsValidityPass(); - $pass->process($container); - } - - public function definitionProvider() - { - return [ - [[null, 'a' => 'a'], []], - [[1 => 1], []], - [[], [['baz', [null, 'a' => 'a']]]], - [[], [['baz', [1 => 1]]]], - ]; - } - - public function testNoException() - { - $container = new ContainerBuilder(); - $definition = $container->register('foo'); - $definition->setArguments([null, 'a' => 'a']); - - $pass = new CheckArgumentsValidityPass(false); - $pass->process($container); - $this->assertCount(1, $definition->getErrors()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/CheckCircularReferencesPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/CheckCircularReferencesPassTest.php deleted file mode 100644 index 8d501368..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/CheckCircularReferencesPassTest.php +++ /dev/null @@ -1,146 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; -use Symfony\Component\DependencyInjection\Compiler\CheckCircularReferencesPass; -use Symfony\Component\DependencyInjection\Compiler\Compiler; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; - -class CheckCircularReferencesPassTest extends TestCase -{ - public function testProcess() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->register('b')->addArgument(new Reference('a')); - - $this->process($container); - } - - public function testProcessWithAliases() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->setAlias('b', 'c'); - $container->setAlias('c', 'a'); - - $this->process($container); - } - - public function testProcessWithFactory() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - - $container - ->register('a', 'stdClass') - ->setFactory([new Reference('b'), 'getInstance']); - - $container - ->register('b', 'stdClass') - ->setFactory([new Reference('a'), 'getInstance']); - - $this->process($container); - } - - public function testProcessDetectsIndirectCircularReference() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->register('b')->addArgument(new Reference('c')); - $container->register('c')->addArgument(new Reference('a')); - - $this->process($container); - } - - public function testProcessDetectsIndirectCircularReferenceWithFactory() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - - $container->register('a')->addArgument(new Reference('b')); - - $container - ->register('b', 'stdClass') - ->setFactory([new Reference('c'), 'getInstance']); - - $container->register('c')->addArgument(new Reference('a')); - - $this->process($container); - } - - public function testDeepCircularReference() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->register('b')->addArgument(new Reference('c')); - $container->register('c')->addArgument(new Reference('b')); - - $this->process($container); - } - - public function testProcessIgnoresMethodCalls() - { - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->register('b')->addMethodCall('setA', [new Reference('a')]); - - $this->process($container); - - $this->addToAssertionCount(1); - } - - public function testProcessIgnoresLazyServices() - { - $container = new ContainerBuilder(); - $container->register('a')->setLazy(true)->addArgument(new Reference('b')); - $container->register('b')->addArgument(new Reference('a')); - - $this->process($container); - - // just make sure that a lazily loaded service does not trigger a CircularReferenceException - $this->addToAssertionCount(1); - } - - public function testProcessIgnoresIteratorArguments() - { - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->register('b')->addArgument(new IteratorArgument([new Reference('a')])); - - $this->process($container); - - // just make sure that an IteratorArgument does not trigger a CircularReferenceException - $this->addToAssertionCount(1); - } - - protected function process(ContainerBuilder $container) - { - $compiler = new Compiler(); - $passConfig = $compiler->getPassConfig(); - $passConfig->setOptimizationPasses([ - new AnalyzeServiceReferencesPass(true), - new CheckCircularReferencesPass(), - ]); - $passConfig->setRemovingPasses([]); - - $compiler->compile($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/CheckDefinitionValidityPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/CheckDefinitionValidityPassTest.php deleted file mode 100644 index 6caa38c7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/CheckDefinitionValidityPassTest.php +++ /dev/null @@ -1,110 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\CheckDefinitionValidityPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class CheckDefinitionValidityPassTest extends TestCase -{ - public function testProcessDetectsSyntheticNonPublicDefinitions() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - $container->register('a')->setSynthetic(true)->setPublic(false); - - $this->process($container); - } - - public function testProcessDetectsNonSyntheticNonAbstractDefinitionWithoutClass() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - $container->register('a')->setSynthetic(false)->setAbstract(false); - - $this->process($container); - } - - public function testProcess() - { - $container = new ContainerBuilder(); - $container->register('a', 'class'); - $container->register('b', 'class')->setSynthetic(true)->setPublic(true); - $container->register('c', 'class')->setAbstract(true); - $container->register('d', 'class')->setSynthetic(true); - - $this->process($container); - - $this->addToAssertionCount(1); - } - - public function testValidTags() - { - $container = new ContainerBuilder(); - $container->register('a', 'class')->addTag('foo', ['bar' => 'baz']); - $container->register('b', 'class')->addTag('foo', ['bar' => null]); - $container->register('c', 'class')->addTag('foo', ['bar' => 1]); - $container->register('d', 'class')->addTag('foo', ['bar' => 1.1]); - - $this->process($container); - - $this->addToAssertionCount(1); - } - - public function testInvalidTags() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - $container->register('a', 'class')->addTag('foo', ['bar' => ['baz' => 'baz']]); - - $this->process($container); - } - - public function testDynamicPublicServiceName() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\EnvParameterException'); - $container = new ContainerBuilder(); - $env = $container->getParameterBag()->get('env(BAR)'); - $container->register("foo.$env", 'class')->setPublic(true); - - $this->process($container); - } - - public function testDynamicPublicAliasName() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\EnvParameterException'); - $container = new ContainerBuilder(); - $env = $container->getParameterBag()->get('env(BAR)'); - $container->setAlias("foo.$env", 'class')->setPublic(true); - - $this->process($container); - } - - public function testDynamicPrivateName() - { - $container = new ContainerBuilder(); - $env = $container->getParameterBag()->get('env(BAR)'); - $container->register("foo.$env", 'class'); - $container->setAlias("bar.$env", 'class'); - - $this->process($container); - - $this->addToAssertionCount(1); - } - - protected function process(ContainerBuilder $container) - { - $pass = new CheckDefinitionValidityPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php deleted file mode 100644 index c4f331b1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/CheckExceptionOnInvalidReferenceBehaviorPassTest.php +++ /dev/null @@ -1,86 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\BoundArgument; -use Symfony\Component\DependencyInjection\Compiler\CheckExceptionOnInvalidReferenceBehaviorPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class CheckExceptionOnInvalidReferenceBehaviorPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $container - ->register('a', '\stdClass') - ->addArgument(new Reference('b')) - ; - $container->register('b', '\stdClass'); - - $this->process($container); - - $this->addToAssertionCount(1); - } - - public function testProcessThrowsExceptionOnInvalidReference() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException'); - $container = new ContainerBuilder(); - - $container - ->register('a', '\stdClass') - ->addArgument(new Reference('b')) - ; - - $this->process($container); - } - - public function testProcessThrowsExceptionOnInvalidReferenceFromInlinedDefinition() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException'); - $container = new ContainerBuilder(); - - $def = new Definition(); - $def->addArgument(new Reference('b')); - - $container - ->register('a', '\stdClass') - ->addArgument($def) - ; - - $this->process($container); - } - - public function testProcessDefinitionWithBindings() - { - $container = new ContainerBuilder(); - - $container - ->register('b') - ->setBindings([new BoundArgument(new Reference('a'))]) - ; - - $this->process($container); - - $this->addToAssertionCount(1); - } - - private function process(ContainerBuilder $container) - { - $pass = new CheckExceptionOnInvalidReferenceBehaviorPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/CheckReferenceValidityPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/CheckReferenceValidityPassTest.php deleted file mode 100644 index 85a8a40f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/CheckReferenceValidityPassTest.php +++ /dev/null @@ -1,48 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\CheckReferenceValidityPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; - -class CheckReferenceValidityPassTest extends TestCase -{ - public function testProcessDetectsReferenceToAbstractDefinition() - { - $this->expectException('RuntimeException'); - $container = new ContainerBuilder(); - - $container->register('a')->setAbstract(true); - $container->register('b')->addArgument(new Reference('a')); - - $this->process($container); - } - - public function testProcess() - { - $container = new ContainerBuilder(); - $container->register('a')->addArgument(new Reference('b')); - $container->register('b'); - - $this->process($container); - - $this->addToAssertionCount(1); - } - - protected function process(ContainerBuilder $container) - { - $pass = new CheckReferenceValidityPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/DecoratorServicePassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/DecoratorServicePassTest.php deleted file mode 100644 index 29fc5cc5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/DecoratorServicePassTest.php +++ /dev/null @@ -1,199 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Alias; -use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class DecoratorServicePassTest extends TestCase -{ - public function testProcessWithoutAlias() - { - $container = new ContainerBuilder(); - $fooDefinition = $container - ->register('foo') - ->setPublic(false) - ; - $fooExtendedDefinition = $container - ->register('foo.extended') - ->setPublic(true) - ->setDecoratedService('foo') - ; - $barDefinition = $container - ->register('bar') - ->setPublic(true) - ; - $barExtendedDefinition = $container - ->register('bar.extended') - ->setPublic(true) - ->setDecoratedService('bar', 'bar.yoo') - ; - - $this->process($container); - - $this->assertEquals('foo.extended', $container->getAlias('foo')); - $this->assertFalse($container->getAlias('foo')->isPublic()); - - $this->assertEquals('bar.extended', $container->getAlias('bar')); - $this->assertTrue($container->getAlias('bar')->isPublic()); - - $this->assertSame($fooDefinition, $container->getDefinition('foo.extended.inner')); - $this->assertFalse($container->getDefinition('foo.extended.inner')->isPublic()); - - $this->assertSame($barDefinition, $container->getDefinition('bar.yoo')); - $this->assertFalse($container->getDefinition('bar.yoo')->isPublic()); - - $this->assertNull($fooExtendedDefinition->getDecoratedService()); - $this->assertNull($barExtendedDefinition->getDecoratedService()); - } - - public function testProcessWithAlias() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(true) - ; - $container->setAlias('foo.alias', new Alias('foo', false)); - $fooExtendedDefinition = $container - ->register('foo.extended') - ->setPublic(true) - ->setDecoratedService('foo.alias') - ; - - $this->process($container); - - $this->assertEquals('foo.extended', $container->getAlias('foo.alias')); - $this->assertFalse($container->getAlias('foo.alias')->isPublic()); - - $this->assertEquals('foo', $container->getAlias('foo.extended.inner')); - $this->assertFalse($container->getAlias('foo.extended.inner')->isPublic()); - - $this->assertNull($fooExtendedDefinition->getDecoratedService()); - } - - public function testProcessWithPriority() - { - $container = new ContainerBuilder(); - $fooDefinition = $container - ->register('foo') - ->setPublic(false) - ; - $barDefinition = $container - ->register('bar') - ->setPublic(true) - ->setDecoratedService('foo') - ; - $bazDefinition = $container - ->register('baz') - ->setPublic(true) - ->setDecoratedService('foo', null, 5) - ; - $quxDefinition = $container - ->register('qux') - ->setPublic(true) - ->setDecoratedService('foo', null, 3) - ; - - $this->process($container); - - $this->assertEquals('bar', $container->getAlias('foo')); - $this->assertFalse($container->getAlias('foo')->isPublic()); - - $this->assertSame($fooDefinition, $container->getDefinition('baz.inner')); - $this->assertFalse($container->getDefinition('baz.inner')->isPublic()); - - $this->assertEquals('qux', $container->getAlias('bar.inner')); - $this->assertFalse($container->getAlias('bar.inner')->isPublic()); - - $this->assertEquals('baz', $container->getAlias('qux.inner')); - $this->assertFalse($container->getAlias('qux.inner')->isPublic()); - - $this->assertNull($barDefinition->getDecoratedService()); - $this->assertNull($bazDefinition->getDecoratedService()); - $this->assertNull($quxDefinition->getDecoratedService()); - } - - public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinition() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setTags(['bar' => ['attr' => 'baz']]) - ; - $container - ->register('baz') - ->setTags(['foobar' => ['attr' => 'bar']]) - ->setDecoratedService('foo') - ; - - $this->process($container); - - $this->assertEmpty($container->getDefinition('baz.inner')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); - } - - /** - * @group legacy - */ - public function testProcessMergesAutowiringTypesInDecoratingDefinitionAndRemoveThemFromDecoratedDefinition() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addAutowiringType('Bar') - ; - - $container - ->register('child') - ->setDecoratedService('parent') - ->addAutowiringType('Foo') - ; - - $this->process($container); - - $this->assertEquals(['Bar', 'Foo'], $container->getDefinition('child')->getAutowiringTypes()); - $this->assertEmpty($container->getDefinition('child.inner')->getAutowiringTypes()); - } - - public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitionMultipleTimes() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(true) - ->setTags(['bar' => ['attr' => 'baz']]) - ; - $container - ->register('deco1') - ->setDecoratedService('foo', null, 50) - ; - $container - ->register('deco2') - ->setDecoratedService('foo', null, 2) - ; - - $this->process($container); - - $this->assertEmpty($container->getDefinition('deco1')->getTags()); - $this->assertEquals(['bar' => ['attr' => 'baz']], $container->getDefinition('deco2')->getTags()); - } - - protected function process(ContainerBuilder $container) - { - $repeatedPass = new DecoratorServicePass(); - $repeatedPass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/DefinitionErrorExceptionPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/DefinitionErrorExceptionPassTest.php deleted file mode 100644 index 27326197..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/DefinitionErrorExceptionPassTest.php +++ /dev/null @@ -1,51 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\DefinitionErrorExceptionPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; - -class DefinitionErrorExceptionPassTest extends TestCase -{ - public function testThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Things went wrong!'); - $container = new ContainerBuilder(); - $def = new Definition(); - $def->addError('Things went wrong!'); - $def->addError('Now something else!'); - $container->register('foo_service_id') - ->setArguments([ - $def, - ]); - - $pass = new DefinitionErrorExceptionPass(); - $pass->process($container); - } - - public function testNoExceptionThrown() - { - $container = new ContainerBuilder(); - $def = new Definition(); - $container->register('foo_service_id') - ->setArguments([ - $def, - ]); - - $pass = new DefinitionErrorExceptionPass(); - $pass->process($container); - $this->assertSame($def, $container->getDefinition('foo_service_id')->getArgument(0)); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ExtensionCompilerPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ExtensionCompilerPassTest.php deleted file mode 100644 index 810fbe48..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ExtensionCompilerPassTest.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Compiler\ExtensionCompilerPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Extension\Extension; - -/** - * @author Wouter J - */ -class ExtensionCompilerPassTest extends TestCase -{ - private $container; - private $pass; - - protected function setUp() - { - $this->container = new ContainerBuilder(); - $this->pass = new ExtensionCompilerPass(); - } - - public function testProcess() - { - $extension1 = new CompilerPassExtension('extension1'); - $extension2 = new DummyExtension('extension2'); - $extension3 = new DummyExtension('extension3'); - $extension4 = new CompilerPassExtension('extension4'); - - $this->container->registerExtension($extension1); - $this->container->registerExtension($extension2); - $this->container->registerExtension($extension3); - $this->container->registerExtension($extension4); - - $this->pass->process($this->container); - - $this->assertTrue($this->container->hasDefinition('extension1')); - $this->assertFalse($this->container->hasDefinition('extension2')); - $this->assertFalse($this->container->hasDefinition('extension3')); - $this->assertTrue($this->container->hasDefinition('extension4')); - } -} - -class DummyExtension extends Extension -{ - private $alias; - - public function __construct($alias) - { - $this->alias = $alias; - } - - public function getAlias() - { - return $this->alias; - } - - public function load(array $configs, ContainerBuilder $container) - { - } - - public function process(ContainerBuilder $container) - { - $container->register($this->alias); - } -} - -class CompilerPassExtension extends DummyExtension implements CompilerPassInterface -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/FactoryReturnTypePassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/FactoryReturnTypePassTest.php deleted file mode 100644 index 87f07c70..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/FactoryReturnTypePassTest.php +++ /dev/null @@ -1,123 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\FactoryReturnTypePass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy; -use Symfony\Component\DependencyInjection\Tests\Fixtures\factoryFunction; -use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryParent; - -/** - * @author Guilhem N. - * - * @group legacy - */ -class FactoryReturnTypePassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $factory = $container->register('factory'); - $factory->setFactory([FactoryDummy::class, 'createFactory']); - - $container->setAlias('alias_factory', 'factory'); - - $foo = $container->register('foo'); - $foo->setFactory([new Reference('alias_factory'), 'create']); - - $bar = $container->register('bar', __CLASS__); - $bar->setFactory([new Reference('factory'), 'create']); - - $pass = new FactoryReturnTypePass(); - $pass->process($container); - - if (method_exists(\ReflectionMethod::class, 'getReturnType')) { - $this->assertEquals(FactoryDummy::class, $factory->getClass()); - $this->assertEquals(\stdClass::class, $foo->getClass()); - } else { - $this->assertNull($factory->getClass()); - $this->assertNull($foo->getClass()); - } - $this->assertEquals(__CLASS__, $bar->getClass()); - } - - /** - * @dataProvider returnTypesProvider - */ - public function testReturnTypes($factory, $returnType, $hhvmSupport = true) - { - if (!$hhvmSupport && \defined('HHVM_VERSION')) { - $this->markTestSkipped('Scalar typehints not supported by hhvm.'); - } - - $container = new ContainerBuilder(); - - $service = $container->register('service'); - $service->setFactory($factory); - - $pass = new FactoryReturnTypePass(); - $pass->process($container); - - if (method_exists(\ReflectionMethod::class, 'getReturnType')) { - $this->assertEquals($returnType, $service->getClass()); - } else { - $this->assertNull($service->getClass()); - } - } - - public function returnTypesProvider() - { - return [ - // must be loaded before the function as they are in the same file - [[FactoryDummy::class, 'createBuiltin'], null, false], - [[FactoryDummy::class, 'createParent'], FactoryParent::class], - [[FactoryDummy::class, 'createSelf'], FactoryDummy::class], - [factoryFunction::class, FactoryDummy::class], - ]; - } - - public function testCircularReference() - { - $container = new ContainerBuilder(); - - $factory = $container->register('factory'); - $factory->setFactory([new Reference('factory2'), 'createSelf']); - - $factory2 = $container->register('factory2'); - $factory2->setFactory([new Reference('factory'), 'create']); - - $pass = new FactoryReturnTypePass(); - $pass->process($container); - - $this->assertNull($factory->getClass()); - $this->assertNull($factory2->getClass()); - } - - /** - * @requires function ReflectionMethod::getReturnType - * @expectedDeprecation Relying on its factory's return-type to define the class of service "factory" is deprecated since Symfony 3.3 and won't work in 4.0. Set the "class" attribute to "Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummy" on the service definition instead. - */ - public function testCompile() - { - $container = new ContainerBuilder(); - - $factory = $container->register('factory'); - $factory->setFactory([FactoryDummy::class, 'createFactory']); - $container->compile(); - - $this->assertEquals(FactoryDummy::class, $container->getDefinition('factory')->getClass()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/InlineServiceDefinitionsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/InlineServiceDefinitionsPassTest.php deleted file mode 100644 index d98db640..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/InlineServiceDefinitionsPassTest.php +++ /dev/null @@ -1,358 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; -use Symfony\Component\DependencyInjection\Compiler\InlineServiceDefinitionsPass; -use Symfony\Component\DependencyInjection\Compiler\RepeatedPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class InlineServiceDefinitionsPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container - ->register('inlinable.service') - ->setPublic(false) - ; - - $container - ->register('service') - ->setArguments([new Reference('inlinable.service')]) - ; - - $this->process($container); - - $arguments = $container->getDefinition('service')->getArguments(); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $arguments[0]); - $this->assertSame($container->getDefinition('inlinable.service'), $arguments[0]); - } - - public function testProcessDoesNotInlinesWhenAliasedServiceIsShared() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(false) - ; - $container->setAlias('moo', 'foo'); - - $container - ->register('service') - ->setArguments([$ref = new Reference('foo')]) - ; - - $this->process($container); - - $arguments = $container->getDefinition('service')->getArguments(); - $this->assertSame($ref, $arguments[0]); - } - - public function testProcessDoesInlineNonSharedService() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setShared(false) - ; - $container - ->register('bar') - ->setPublic(false) - ->setShared(false) - ; - $container->setAlias('moo', 'bar'); - - $container - ->register('service') - ->setArguments([new Reference('foo'), $ref = new Reference('moo'), new Reference('bar')]) - ; - - $this->process($container); - - $arguments = $container->getDefinition('service')->getArguments(); - $this->assertEquals($container->getDefinition('foo'), $arguments[0]); - $this->assertNotSame($container->getDefinition('foo'), $arguments[0]); - $this->assertSame($ref, $arguments[1]); - $this->assertEquals($container->getDefinition('bar'), $arguments[2]); - $this->assertNotSame($container->getDefinition('bar'), $arguments[2]); - } - - public function testProcessDoesNotInlineMixedServicesLoop() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->addArgument(new Reference('bar')) - ->setShared(false) - ; - $container - ->register('bar') - ->setPublic(false) - ->addMethodCall('setFoo', [new Reference('foo')]) - ; - - $this->process($container); - - $this->assertEquals(new Reference('bar'), $container->getDefinition('foo')->getArgument(0)); - } - - public function testProcessThrowsOnNonSharedLoops() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> foo -> bar".'); - $container = new ContainerBuilder(); - $container - ->register('foo') - ->addArgument(new Reference('bar')) - ->setShared(false) - ; - $container - ->register('bar') - ->setShared(false) - ->addMethodCall('setFoo', [new Reference('foo')]) - ; - - $this->process($container); - } - - public function testProcessNestedNonSharedServices() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->addArgument(new Reference('bar1')) - ->addArgument(new Reference('bar2')) - ; - $container - ->register('bar1') - ->setShared(false) - ->addArgument(new Reference('baz')) - ; - $container - ->register('bar2') - ->setShared(false) - ->addArgument(new Reference('baz')) - ; - $container - ->register('baz') - ->setShared(false) - ; - - $this->process($container); - - $baz1 = $container->getDefinition('foo')->getArgument(0)->getArgument(0); - $baz2 = $container->getDefinition('foo')->getArgument(1)->getArgument(0); - - $this->assertEquals($container->getDefinition('baz'), $baz1); - $this->assertEquals($container->getDefinition('baz'), $baz2); - $this->assertNotSame($baz1, $baz2); - } - - public function testProcessInlinesIfMultipleReferencesButAllFromTheSameDefinition() - { - $container = new ContainerBuilder(); - - $a = $container->register('a')->setPublic(false); - $b = $container - ->register('b') - ->addArgument(new Reference('a')) - ->addArgument(new Definition(null, [new Reference('a')])) - ; - - $this->process($container); - - $arguments = $b->getArguments(); - $this->assertSame($a, $arguments[0]); - - $inlinedArguments = $arguments[1]->getArguments(); - $this->assertSame($a, $inlinedArguments[0]); - } - - public function testProcessInlinesPrivateFactoryReference() - { - $container = new ContainerBuilder(); - - $container->register('a')->setPublic(false); - $b = $container - ->register('b') - ->setPublic(false) - ->setFactory([new Reference('a'), 'a']) - ; - - $container - ->register('foo') - ->setArguments([ - $ref = new Reference('b'), - ]); - - $this->process($container); - - $inlinedArguments = $container->getDefinition('foo')->getArguments(); - $this->assertSame($b, $inlinedArguments[0]); - } - - public function testProcessDoesNotInlinePrivateFactoryIfReferencedMultipleTimesWithinTheSameDefinition() - { - $container = new ContainerBuilder(); - $container - ->register('a') - ; - $container - ->register('b') - ->setPublic(false) - ->setFactory([new Reference('a'), 'a']) - ; - - $container - ->register('foo') - ->setArguments([ - $ref1 = new Reference('b'), - $ref2 = new Reference('b'), - ]) - ; - $this->process($container); - - $args = $container->getDefinition('foo')->getArguments(); - $this->assertSame($ref1, $args[0]); - $this->assertSame($ref2, $args[1]); - } - - public function testProcessDoesNotInlineReferenceWhenUsedByInlineFactory() - { - $container = new ContainerBuilder(); - $container - ->register('a') - ; - $container - ->register('b') - ->setPublic(false) - ->setFactory([new Reference('a'), 'a']) - ; - - $inlineFactory = new Definition(); - $inlineFactory->setPublic(false); - $inlineFactory->setFactory([new Reference('b'), 'b']); - - $container - ->register('foo') - ->setArguments([ - $ref = new Reference('b'), - $inlineFactory, - ]) - ; - $this->process($container); - - $args = $container->getDefinition('foo')->getArguments(); - $this->assertSame($ref, $args[0]); - } - - public function testProcessDoesNotInlineWhenServiceIsPrivateButLazy() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(false) - ->setLazy(true) - ; - - $container - ->register('service') - ->setArguments([$ref = new Reference('foo')]) - ; - - $this->process($container); - - $arguments = $container->getDefinition('service')->getArguments(); - $this->assertSame($ref, $arguments[0]); - } - - public function testProcessDoesNotInlineWhenServiceReferencesItself() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(false) - ->addMethodCall('foo', [$ref = new Reference('foo')]) - ; - - $this->process($container); - - $calls = $container->getDefinition('foo')->getMethodCalls(); - $this->assertSame($ref, $calls[0][1][0]); - } - - public function testProcessDoesNotSetLazyArgumentValuesAfterInlining() - { - $container = new ContainerBuilder(); - $container - ->register('inline') - ->setShared(false) - ; - $container - ->register('service-closure') - ->setArguments([new ServiceClosureArgument(new Reference('inline'))]) - ; - $container - ->register('iterator') - ->setArguments([new IteratorArgument([new Reference('inline')])]) - ; - - $this->process($container); - - $values = $container->getDefinition('service-closure')->getArgument(0)->getValues(); - $this->assertInstanceOf(Reference::class, $values[0]); - $this->assertSame('inline', (string) $values[0]); - - $values = $container->getDefinition('iterator')->getArgument(0)->getValues(); - $this->assertInstanceOf(Reference::class, $values[0]); - $this->assertSame('inline', (string) $values[0]); - } - - /** - * @group legacy - */ - public function testGetInlinedServiceIdData() - { - $container = new ContainerBuilder(); - $container - ->register('inlinable.service') - ->setPublic(false) - ; - $container - ->register('non_inlinable.service') - ->setPublic(true) - ; - - $container - ->register('other_service') - ->setArguments([new Reference('inlinable.service')]) - ; - - $inlinePass = new InlineServiceDefinitionsPass(); - $repeatedPass = new RepeatedPass([new AnalyzeServiceReferencesPass(), $inlinePass]); - $repeatedPass->process($container); - - $this->assertEquals(['inlinable.service' => ['other_service']], $inlinePass->getInlinedServiceIds()); - } - - protected function process(ContainerBuilder $container) - { - $repeatedPass = new RepeatedPass([new AnalyzeServiceReferencesPass(), new InlineServiceDefinitionsPass()]); - $repeatedPass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/IntegrationTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/IntegrationTest.php deleted file mode 100644 index 348d1d7f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/IntegrationTest.php +++ /dev/null @@ -1,252 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\Alias; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; - -/** - * This class tests the integration of the different compiler passes. - */ -class IntegrationTest extends TestCase -{ - /** - * This tests that dependencies are correctly processed. - * - * We're checking that: - * - * * A is public, B/C are private - * * A -> C - * * B -> C - */ - public function testProcessRemovesAndInlinesRecursively() - { - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - - $a = $container - ->register('a', '\stdClass') - ->addArgument(new Reference('c')) - ; - - $container - ->register('b', '\stdClass') - ->addArgument(new Reference('c')) - ->setPublic(false) - ; - - $c = $container - ->register('c', '\stdClass') - ->setPublic(false) - ; - - $container->compile(); - - $this->assertTrue($container->hasDefinition('a')); - $arguments = $a->getArguments(); - $this->assertSame($c, $arguments[0]); - $this->assertFalse($container->hasDefinition('b')); - $this->assertFalse($container->hasDefinition('c')); - } - - public function testProcessInlinesReferencesToAliases() - { - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - - $a = $container - ->register('a', '\stdClass') - ->addArgument(new Reference('b')) - ; - - $container->setAlias('b', new Alias('c', false)); - - $c = $container - ->register('c', '\stdClass') - ->setPublic(false) - ; - - $container->compile(); - - $this->assertTrue($container->hasDefinition('a')); - $arguments = $a->getArguments(); - $this->assertSame($c, $arguments[0]); - $this->assertFalse($container->hasAlias('b')); - $this->assertFalse($container->hasDefinition('c')); - } - - public function testProcessInlinesWhenThereAreMultipleReferencesButFromTheSameDefinition() - { - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - - $container - ->register('a', '\stdClass') - ->addArgument(new Reference('b')) - ->addMethodCall('setC', [new Reference('c')]) - ; - - $container - ->register('b', '\stdClass') - ->addArgument(new Reference('c')) - ->setPublic(false) - ; - - $container - ->register('c', '\stdClass') - ->setPublic(false) - ; - - $container->compile(); - - $this->assertTrue($container->hasDefinition('a')); - $this->assertFalse($container->hasDefinition('b')); - $this->assertFalse($container->hasDefinition('c'), 'Service C was not inlined.'); - } - - public function testCanDecorateServiceSubscriber() - { - $container = new ContainerBuilder(); - $container->register(ServiceSubscriberStub::class) - ->addTag('container.service_subscriber') - ->setPublic(true); - - $container->register(DecoratedServiceSubscriber::class) - ->setDecoratedService(ServiceSubscriberStub::class); - - $container->compile(); - - $this->assertInstanceOf(DecoratedServiceSubscriber::class, $container->get(ServiceSubscriberStub::class)); - } - - /** - * @dataProvider getYamlCompileTests - */ - public function testYamlContainerCompiles($directory, $actualServiceId, $expectedServiceId, ContainerBuilder $mainContainer = null) - { - // allow a container to be passed in, which might have autoconfigure settings - $container = $mainContainer ?: new ContainerBuilder(); - $container->setResourceTracking(false); - $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Fixtures/yaml/integration/'.$directory)); - $loader->load('main.yml'); - $container->compile(); - $actualService = $container->getDefinition($actualServiceId); - - // create a fresh ContainerBuilder, to avoid autoconfigure stuff - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Fixtures/yaml/integration/'.$directory)); - $loader->load('expected.yml'); - $container->compile(); - $expectedService = $container->getDefinition($expectedServiceId); - - // reset changes, we don't care if these differ - $actualService->setChanges([]); - $expectedService->setChanges([]); - - $this->assertEquals($expectedService, $actualService); - } - - public function getYamlCompileTests() - { - $container = new ContainerBuilder(); - $container->registerForAutoconfiguration(IntegrationTestStub::class); - yield [ - 'autoconfigure_child_not_applied', - 'child_service', - 'child_service_expected', - $container, - ]; - - $container = new ContainerBuilder(); - $container->registerForAutoconfiguration(IntegrationTestStub::class); - yield [ - 'autoconfigure_parent_child', - 'child_service', - 'child_service_expected', - $container, - ]; - - $container = new ContainerBuilder(); - $container->registerForAutoconfiguration(IntegrationTestStub::class) - ->addTag('from_autoconfigure'); - yield [ - 'autoconfigure_parent_child_tags', - 'child_service', - 'child_service_expected', - $container, - ]; - - yield [ - 'child_parent', - 'child_service', - 'child_service_expected', - ]; - - yield [ - 'defaults_child_tags', - 'child_service', - 'child_service_expected', - ]; - - yield [ - 'defaults_instanceof_importance', - 'main_service', - 'main_service_expected', - ]; - - yield [ - 'defaults_parent_child', - 'child_service', - 'child_service_expected', - ]; - - yield [ - 'instanceof_parent_child', - 'child_service', - 'child_service_expected', - ]; - } -} - -class ServiceSubscriberStub implements ServiceSubscriberInterface -{ - public static function getSubscribedServices() - { - return []; - } -} - -class DecoratedServiceSubscriber -{ -} - -class IntegrationTestStub extends IntegrationTestStubParent -{ -} - -class IntegrationTestStubParent -{ - public function enableSummer($enable) - { - // methods used in calls - added here to prevent errors for not existing - } - - public function setSunshine($type) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/MergeExtensionConfigurationPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/MergeExtensionConfigurationPassTest.php deleted file mode 100644 index 13692657..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/MergeExtensionConfigurationPassTest.php +++ /dev/null @@ -1,197 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Definition\Builder\TreeBuilder; -use Symfony\Component\Config\Definition\ConfigurationInterface; -use Symfony\Component\Config\Resource\FileResource; -use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationContainerBuilder; -use Symfony\Component\DependencyInjection\Compiler\MergeExtensionConfigurationPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Extension\Extension; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; - -class MergeExtensionConfigurationPassTest extends TestCase -{ - public function testExpressionLanguageProviderForwarding() - { - $tmpProviders = []; - - $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock(); - $extension->expects($this->any()) - ->method('getXsdValidationBasePath') - ->willReturn(false); - $extension->expects($this->any()) - ->method('getNamespace') - ->willReturn('http://example.org/schema/dic/foo'); - $extension->expects($this->any()) - ->method('getAlias') - ->willReturn('foo'); - $extension->expects($this->once()) - ->method('load') - ->willReturnCallback(function (array $config, ContainerBuilder $container) use (&$tmpProviders) { - $tmpProviders = $container->getExpressionLanguageProviders(); - }); - - $provider = $this->getMockBuilder('Symfony\\Component\\ExpressionLanguage\\ExpressionFunctionProviderInterface')->getMock(); - $container = new ContainerBuilder(new ParameterBag()); - $container->registerExtension($extension); - $container->prependExtensionConfig('foo', ['bar' => true]); - $container->addExpressionLanguageProvider($provider); - - $pass = new MergeExtensionConfigurationPass(); - $pass->process($container); - - $this->assertEquals([$provider], $tmpProviders); - } - - public function testExtensionLoadGetAMergeExtensionConfigurationContainerBuilderInstance() - { - $extension = $this->getMockBuilder(FooExtension::class)->setMethods(['load'])->getMock(); - $extension->expects($this->once()) - ->method('load') - ->with($this->isType('array'), $this->isInstanceOf(MergeExtensionConfigurationContainerBuilder::class)) - ; - - $container = new ContainerBuilder(new ParameterBag()); - $container->registerExtension($extension); - $container->prependExtensionConfig('foo', []); - - $pass = new MergeExtensionConfigurationPass(); - $pass->process($container); - } - - public function testExtensionConfigurationIsTrackedByDefault() - { - $extension = $this->getMockBuilder(FooExtension::class)->setMethods(['getConfiguration'])->getMock(); - $extension->expects($this->exactly(2)) - ->method('getConfiguration') - ->willReturn(new FooConfiguration()); - - $container = new ContainerBuilder(new ParameterBag()); - $container->registerExtension($extension); - $container->prependExtensionConfig('foo', ['bar' => true]); - - $pass = new MergeExtensionConfigurationPass(); - $pass->process($container); - - $this->assertContainsEquals(new FileResource(__FILE__), $container->getResources()); - } - - public function testOverriddenEnvsAreMerged() - { - $container = new ContainerBuilder(); - $container->registerExtension(new FooExtension()); - $container->prependExtensionConfig('foo', ['bar' => '%env(FOO)%']); - $container->prependExtensionConfig('foo', ['bar' => '%env(BAR)%', 'baz' => '%env(BAZ)%']); - - $pass = new MergeExtensionConfigurationPass(); - $pass->process($container); - - $this->assertSame(['BAZ', 'FOO'], array_keys($container->getParameterBag()->getEnvPlaceholders())); - $this->assertSame(['BAZ' => 1, 'FOO' => 0], $container->getEnvCounters()); - } - - public function testProcessedEnvsAreIncompatibleWithResolve() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Using a cast in "env(int:FOO)" is incompatible with resolution at compile time in "Symfony\Component\DependencyInjection\Tests\Compiler\BarExtension". The logic in the extension should be moved to a compiler pass, or an env parameter with no cast should be used instead.'); - $container = new ContainerBuilder(); - $container->registerExtension(new BarExtension()); - $container->prependExtensionConfig('bar', []); - - (new MergeExtensionConfigurationPass())->process($container); - } - - public function testThrowingExtensionsGetMergedBag() - { - $container = new ContainerBuilder(); - $container->registerExtension(new ThrowingExtension()); - $container->prependExtensionConfig('throwing', ['bar' => '%env(FOO)%']); - - try { - $pass = new MergeExtensionConfigurationPass(); - $pass->process($container); - $this->fail('An exception should have been thrown.'); - } catch (\Exception $e) { - } - - $this->assertSame(['FOO'], array_keys($container->getParameterBag()->getEnvPlaceholders())); - } -} - -class FooConfiguration implements ConfigurationInterface -{ - public function getConfigTreeBuilder() - { - $treeBuilder = new TreeBuilder(); - $rootNode = $treeBuilder->root('foo'); - $rootNode - ->children() - ->scalarNode('bar')->end() - ->scalarNode('baz')->end() - ->end(); - - return $treeBuilder; - } -} - -class FooExtension extends Extension -{ - public function getAlias() - { - return 'foo'; - } - - public function getConfiguration(array $config, ContainerBuilder $container) - { - return new FooConfiguration(); - } - - public function load(array $configs, ContainerBuilder $container) - { - $configuration = $this->getConfiguration($configs, $container); - $config = $this->processConfiguration($configuration, $configs); - - if (isset($config['baz'])) { - $container->getParameterBag()->get('env(BOZ)'); - $container->resolveEnvPlaceholders($config['baz']); - } - } -} - -class BarExtension extends Extension -{ - public function load(array $configs, ContainerBuilder $container) - { - $container->resolveEnvPlaceholders('%env(int:FOO)%', true); - } -} - -class ThrowingExtension extends Extension -{ - public function getAlias() - { - return 'throwing'; - } - - public function getConfiguration(array $config, ContainerBuilder $container) - { - return new FooConfiguration(); - } - - public function load(array $configs, ContainerBuilder $container) - { - throw new \Exception(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/OptionalServiceClass.php b/vendor/symfony/dependency-injection/Tests/Compiler/OptionalServiceClass.php deleted file mode 100644 index 7e9238f2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/OptionalServiceClass.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use Symfony\Bug\NotExistClass; - -class OptionalServiceClass extends NotExistClass -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/PassConfigTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/PassConfigTest.php deleted file mode 100644 index 9470e526..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/PassConfigTest.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\Compiler\PassConfig; - -/** - * @author Guilhem N - */ -class PassConfigTest extends TestCase -{ - public function testPassOrdering() - { - $config = new PassConfig(); - $config->setBeforeOptimizationPasses([]); - - $pass1 = $this->getMockBuilder(CompilerPassInterface::class)->getMock(); - $config->addPass($pass1, PassConfig::TYPE_BEFORE_OPTIMIZATION, 10); - - $pass2 = $this->getMockBuilder(CompilerPassInterface::class)->getMock(); - $config->addPass($pass2, PassConfig::TYPE_BEFORE_OPTIMIZATION, 30); - - $passes = $config->getBeforeOptimizationPasses(); - $this->assertSame($pass2, $passes[0]); - $this->assertSame($pass1, $passes[1]); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/PriorityTaggedServiceTraitTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/PriorityTaggedServiceTraitTest.php deleted file mode 100644 index 57682b5d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/PriorityTaggedServiceTraitTest.php +++ /dev/null @@ -1,91 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; - -class PriorityTaggedServiceTraitTest extends TestCase -{ - public function testThatCacheWarmersAreProcessedInPriorityOrder() - { - $services = [ - 'my_service1' => ['my_custom_tag' => ['priority' => 100]], - 'my_service2' => ['my_custom_tag' => ['priority' => 200]], - 'my_service3' => ['my_custom_tag' => ['priority' => -501]], - 'my_service4' => ['my_custom_tag' => []], - 'my_service5' => ['my_custom_tag' => ['priority' => -1]], - 'my_service6' => ['my_custom_tag' => ['priority' => -500]], - 'my_service7' => ['my_custom_tag' => ['priority' => -499]], - 'my_service8' => ['my_custom_tag' => ['priority' => 1]], - 'my_service9' => ['my_custom_tag' => ['priority' => -2]], - 'my_service10' => ['my_custom_tag' => ['priority' => -1000]], - 'my_service11' => ['my_custom_tag' => ['priority' => -1001]], - 'my_service12' => ['my_custom_tag' => ['priority' => -1002]], - 'my_service13' => ['my_custom_tag' => ['priority' => -1003]], - 'my_service14' => ['my_custom_tag' => ['priority' => -1000]], - 'my_service15' => ['my_custom_tag' => ['priority' => 1]], - 'my_service16' => ['my_custom_tag' => ['priority' => -1]], - 'my_service17' => ['my_custom_tag' => ['priority' => 200]], - 'my_service18' => ['my_custom_tag' => ['priority' => 100]], - 'my_service19' => ['my_custom_tag' => []], - ]; - - $container = new ContainerBuilder(); - - foreach ($services as $id => $tags) { - $definition = $container->register($id); - - foreach ($tags as $name => $attributes) { - $definition->addTag($name, $attributes); - } - } - - $expected = [ - new Reference('my_service2'), - new Reference('my_service17'), - new Reference('my_service1'), - new Reference('my_service18'), - new Reference('my_service8'), - new Reference('my_service15'), - new Reference('my_service4'), - new Reference('my_service19'), - new Reference('my_service5'), - new Reference('my_service16'), - new Reference('my_service9'), - new Reference('my_service7'), - new Reference('my_service6'), - new Reference('my_service3'), - new Reference('my_service10'), - new Reference('my_service14'), - new Reference('my_service11'), - new Reference('my_service12'), - new Reference('my_service13'), - ]; - - $priorityTaggedServiceTraitImplementation = new PriorityTaggedServiceTraitImplementation(); - - $this->assertEquals($expected, $priorityTaggedServiceTraitImplementation->test('my_custom_tag', $container)); - } -} - -class PriorityTaggedServiceTraitImplementation -{ - use PriorityTaggedServiceTrait; - - public function test($tagName, ContainerBuilder $container) - { - return $this->findAndSortTaggedServices($tagName, $container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php deleted file mode 100644 index 2c42ba0c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/RegisterEnvVarProcessorsPassTest.php +++ /dev/null @@ -1,86 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\RegisterEnvVarProcessorsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\EnvVarProcessorInterface; - -class RegisterEnvVarProcessorsPassTest extends TestCase -{ - public function testSimpleProcessor() - { - $container = new ContainerBuilder(); - $container->register('foo', SimpleProcessor::class)->addTag('container.env_var_processor'); - - (new RegisterEnvVarProcessorsPass())->process($container); - - $this->assertTrue($container->has('container.env_var_processors_locator')); - $this->assertInstanceOf(SimpleProcessor::class, $container->get('container.env_var_processors_locator')->get('foo')); - - $expected = [ - 'foo' => ['string'], - 'base64' => ['string'], - 'bool' => ['bool'], - 'const' => ['bool', 'int', 'float', 'string', 'array'], - 'file' => ['string'], - 'float' => ['float'], - 'int' => ['int'], - 'json' => ['array'], - 'resolve' => ['string'], - 'string' => ['string'], - ]; - - $this->assertSame($expected, $container->getParameterBag()->getProvidedTypes()); - } - - public function testNoProcessor() - { - $container = new ContainerBuilder(); - - (new RegisterEnvVarProcessorsPass())->process($container); - - $this->assertFalse($container->has('container.env_var_processors_locator')); - } - - public function testBadProcessor() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid type "foo" returned by "Symfony\Component\DependencyInjection\Tests\Compiler\BadProcessor::getProvidedTypes()", expected one of "array", "bool", "float", "int", "string".'); - $container = new ContainerBuilder(); - $container->register('foo', BadProcessor::class)->addTag('container.env_var_processor'); - - (new RegisterEnvVarProcessorsPass())->process($container); - } -} - -class SimpleProcessor implements EnvVarProcessorInterface -{ - public function getEnv($prefix, $name, \Closure $getEnv) - { - return $getEnv($name); - } - - public static function getProvidedTypes() - { - return ['foo' => 'string']; - } -} - -class BadProcessor extends SimpleProcessor -{ - public static function getProvidedTypes() - { - return ['foo' => 'string|foo']; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/RegisterServiceSubscribersPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/RegisterServiceSubscribersPassTest.php deleted file mode 100644 index a16bfc16..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/RegisterServiceSubscribersPassTest.php +++ /dev/null @@ -1,133 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface as PsrContainerInterface; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\Compiler\RegisterServiceSubscribersPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveServiceSubscribersPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; -use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber; -use Symfony\Component\DependencyInjection\TypedReference; - -require_once __DIR__.'/../Fixtures/includes/classes.php'; - -class RegisterServiceSubscribersPassTest extends TestCase -{ - public function testInvalidClass() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Service "foo" must implement interface "Symfony\Component\DependencyInjection\ServiceSubscriberInterface".'); - $container = new ContainerBuilder(); - - $container->register('foo', CustomDefinition::class) - ->addTag('container.service_subscriber') - ; - - (new RegisterServiceSubscribersPass())->process($container); - (new ResolveServiceSubscribersPass())->process($container); - } - - public function testInvalidAttributes() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "bar" given for service "foo".'); - $container = new ContainerBuilder(); - - $container->register('foo', TestServiceSubscriber::class) - ->addTag('container.service_subscriber', ['bar' => '123']) - ; - - (new RegisterServiceSubscribersPass())->process($container); - (new ResolveServiceSubscribersPass())->process($container); - } - - public function testNoAttributes() - { - $container = new ContainerBuilder(); - - $container->register('foo', TestServiceSubscriber::class) - ->addArgument(new Reference(PsrContainerInterface::class)) - ->addTag('container.service_subscriber') - ; - - (new RegisterServiceSubscribersPass())->process($container); - (new ResolveServiceSubscribersPass())->process($container); - - $foo = $container->getDefinition('foo'); - $locator = $container->getDefinition((string) $foo->getArgument(0)); - - $this->assertFalse($locator->isPublic()); - $this->assertSame(ServiceLocator::class, $locator->getClass()); - - $expected = [ - TestServiceSubscriber::class => new ServiceClosureArgument(new TypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class, TestServiceSubscriber::class)), - CustomDefinition::class => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)), - 'bar' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class)), - 'baz' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)), - ]; - - $this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0)); - } - - public function testWithAttributes() - { - $container = new ContainerBuilder(); - - $container->register('foo', TestServiceSubscriber::class) - ->setAutowired(true) - ->addArgument(new Reference(PsrContainerInterface::class)) - ->addTag('container.service_subscriber', ['key' => 'bar', 'id' => 'bar']) - ->addTag('container.service_subscriber', ['key' => 'bar', 'id' => 'baz']) // should be ignored: the first wins - ; - - (new RegisterServiceSubscribersPass())->process($container); - (new ResolveServiceSubscribersPass())->process($container); - - $foo = $container->getDefinition('foo'); - $locator = $container->getDefinition((string) $foo->getArgument(0)); - - $this->assertFalse($locator->isPublic()); - $this->assertSame(ServiceLocator::class, $locator->getClass()); - - $expected = [ - TestServiceSubscriber::class => new ServiceClosureArgument(new TypedReference(TestServiceSubscriber::class, TestServiceSubscriber::class, TestServiceSubscriber::class)), - CustomDefinition::class => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)), - 'bar' => new ServiceClosureArgument(new TypedReference('bar', CustomDefinition::class, TestServiceSubscriber::class)), - 'baz' => new ServiceClosureArgument(new TypedReference(CustomDefinition::class, CustomDefinition::class, TestServiceSubscriber::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE)), - ]; - - $this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0)); - } - - public function testExtraServiceSubscriber() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Service key "test" does not exist in the map returned by "Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber::getSubscribedServices()" for service "foo_service".'); - $container = new ContainerBuilder(); - $container->register('foo_service', TestServiceSubscriber::class) - ->setAutowired(true) - ->addArgument(new Reference(PsrContainerInterface::class)) - ->addTag('container.service_subscriber', [ - 'key' => 'test', - 'id' => TestServiceSubscriber::class, - ]) - ; - $container->register(TestServiceSubscriber::class, TestServiceSubscriber::class); - $container->compile(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/RemoveUnusedDefinitionsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/RemoveUnusedDefinitionsPassTest.php deleted file mode 100644 index 1dfdd9dd..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/RemoveUnusedDefinitionsPassTest.php +++ /dev/null @@ -1,137 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass; -use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; -use Symfony\Component\DependencyInjection\Compiler\RepeatedPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class RemoveUnusedDefinitionsPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(false) - ; - $container - ->register('bar') - ->setPublic(false) - ; - $container - ->register('moo') - ->setArguments([new Reference('bar')]) - ; - - $this->process($container); - - $this->assertFalse($container->hasDefinition('foo')); - $this->assertTrue($container->hasDefinition('bar')); - $this->assertTrue($container->hasDefinition('moo')); - } - - public function testProcessRemovesUnusedDefinitionsRecursively() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(false) - ; - $container - ->register('bar') - ->setArguments([new Reference('foo')]) - ->setPublic(false) - ; - - $this->process($container); - - $this->assertFalse($container->hasDefinition('foo')); - $this->assertFalse($container->hasDefinition('bar')); - } - - public function testProcessWorksWithInlinedDefinitions() - { - $container = new ContainerBuilder(); - $container - ->register('foo') - ->setPublic(false) - ; - $container - ->register('bar') - ->setArguments([new Definition(null, [new Reference('foo')])]) - ; - - $this->process($container); - - $this->assertTrue($container->hasDefinition('foo')); - $this->assertTrue($container->hasDefinition('bar')); - } - - public function testProcessWontRemovePrivateFactory() - { - $container = new ContainerBuilder(); - - $container - ->register('foo', 'stdClass') - ->setFactory(['stdClass', 'getInstance']) - ->setPublic(false); - - $container - ->register('bar', 'stdClass') - ->setFactory([new Reference('foo'), 'getInstance']) - ->setPublic(false); - - $container - ->register('foobar') - ->addArgument(new Reference('bar')); - - $this->process($container); - - $this->assertTrue($container->hasDefinition('foo')); - $this->assertTrue($container->hasDefinition('bar')); - $this->assertTrue($container->hasDefinition('foobar')); - } - - public function testProcessConsiderEnvVariablesAsUsedEvenInPrivateServices() - { - $container = new ContainerBuilder(); - $container->setParameter('env(FOOBAR)', 'test'); - $container - ->register('foo') - ->setArguments(['%env(FOOBAR)%']) - ->setPublic(false) - ; - - $resolvePass = new ResolveParameterPlaceHoldersPass(); - $resolvePass->process($container); - - $this->process($container); - - $this->assertFalse($container->hasDefinition('foo')); - - $envCounters = $container->getEnvCounters(); - $this->assertArrayHasKey('FOOBAR', $envCounters); - $this->assertSame(1, $envCounters['FOOBAR']); - } - - protected function process(ContainerBuilder $container) - { - $repeatedPass = new RepeatedPass([new AnalyzeServiceReferencesPass(), new RemoveUnusedDefinitionsPass()]); - $repeatedPass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php deleted file mode 100644 index 2f0a413c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\ReplaceAliasByActualDefinitionPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -require_once __DIR__.'/../Fixtures/includes/foo.php'; - -class ReplaceAliasByActualDefinitionPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $aDefinition = $container->register('a', '\stdClass'); - $aDefinition->setFactory([new Reference('b'), 'createA']); - - $bDefinition = new Definition('\stdClass'); - $bDefinition->setPublic(false); - $container->setDefinition('b', $bDefinition); - - $container->setAlias('a_alias', 'a'); - $container->setAlias('b_alias', 'b'); - - $container->setAlias('container', 'service_container'); - - $this->process($container); - - $this->assertTrue($container->has('a'), '->process() does nothing to public definitions.'); - $this->assertTrue($container->hasAlias('a_alias')); - $this->assertFalse($container->has('b'), '->process() removes non-public definitions.'); - $this->assertTrue( - $container->has('b_alias') && !$container->hasAlias('b_alias'), - '->process() replaces alias to actual.' - ); - - $this->assertTrue($container->has('container')); - - $resolvedFactory = $aDefinition->getFactory(); - $this->assertSame('b_alias', (string) $resolvedFactory[0]); - } - - public function testProcessWithInvalidAlias() - { - $this->expectException('InvalidArgumentException'); - $container = new ContainerBuilder(); - $container->setAlias('a_alias', 'a'); - $this->process($container); - } - - protected function process(ContainerBuilder $container) - { - $pass = new ReplaceAliasByActualDefinitionPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveBindingsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveBindingsPassTest.php deleted file mode 100644 index 7e5994af..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveBindingsPassTest.php +++ /dev/null @@ -1,152 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\BoundArgument; -use Symfony\Component\DependencyInjection\Compiler\AutowireRequiredMethodsPass; -use Symfony\Component\DependencyInjection\Compiler\DefinitionErrorExceptionPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; -use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists; -use Symfony\Component\DependencyInjection\TypedReference; - -require_once __DIR__.'/../Fixtures/includes/autowiring_classes.php'; - -class ResolveBindingsPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $bindings = [CaseSensitiveClass::class => new BoundArgument(new Reference('foo'))]; - - $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); - $definition->setArguments([1 => '123']); - $definition->addMethodCall('setSensitiveClass'); - $definition->setBindings($bindings); - - $container->register('foo', CaseSensitiveClass::class) - ->setBindings($bindings); - - $pass = new ResolveBindingsPass(); - $pass->process($container); - - $this->assertEquals([new Reference('foo'), '123'], $definition->getArguments()); - $this->assertEquals([['setSensitiveClass', [new Reference('foo')]]], $definition->getMethodCalls()); - } - - public function testUnusedBinding() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Unused binding "$quz" in service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy".'); - $container = new ContainerBuilder(); - - $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); - $definition->setBindings(['$quz' => '123']); - - $pass = new ResolveBindingsPass(); - $pass->process($container); - } - - public function testMissingParent() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Unused binding "\$quz" in service [\s\S]+/'); - - $container = new ContainerBuilder(); - - $definition = $container->register(ParentNotExists::class, ParentNotExists::class); - $definition->setBindings(['$quz' => '123']); - - $pass = new ResolveBindingsPass(); - $pass->process($container); - } - - public function testTypedReferenceSupport() - { - $container = new ContainerBuilder(); - - $bindings = [CaseSensitiveClass::class => new BoundArgument(new Reference('foo'))]; - - // Explicit service id - $definition1 = $container->register('def1', NamedArgumentsDummy::class); - $definition1->addArgument($typedRef = new TypedReference('bar', CaseSensitiveClass::class)); - $definition1->setBindings($bindings); - - $definition2 = $container->register('def2', NamedArgumentsDummy::class); - $definition2->addArgument(new TypedReference(CaseSensitiveClass::class, CaseSensitiveClass::class)); - $definition2->setBindings($bindings); - - $pass = new ResolveBindingsPass(); - $pass->process($container); - - $this->assertEquals([$typedRef], $container->getDefinition('def1')->getArguments()); - $this->assertEquals([new Reference('foo')], $container->getDefinition('def2')->getArguments()); - } - - public function testScalarSetter() - { - $container = new ContainerBuilder(); - - $definition = $container->autowire('foo', ScalarSetter::class); - $definition->setBindings(['$defaultLocale' => 'fr']); - - (new AutowireRequiredMethodsPass())->process($container); - (new ResolveBindingsPass())->process($container); - - $this->assertEquals([['setDefaultLocale', ['fr']]], $definition->getMethodCalls()); - } - - public function testWithNonExistingSetterAndBinding() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy": method "setLogger()" does not exist.'); - $container = new ContainerBuilder(); - - $bindings = [ - '$c' => (new Definition('logger'))->setFactory('logger'), - ]; - - $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); - $definition->addMethodCall('setLogger'); - $definition->setBindings($bindings); - - $pass = new ResolveBindingsPass(); - $pass->process($container); - } - - public function testSyntheticServiceWithBind() - { - $container = new ContainerBuilder(); - $argument = new BoundArgument('bar'); - - $container->register('foo', 'stdClass') - ->addArgument(new Reference('synthetic.service')); - - $container->register('synthetic.service') - ->setSynthetic(true) - ->setBindings(['$apiKey' => $argument]); - - $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class) - ->setBindings(['$apiKey' => $argument]); - - (new ResolveBindingsPass())->process($container); - (new DefinitionErrorExceptionPass())->process($container); - - $this->assertSame([1 => 'bar'], $container->getDefinition(NamedArgumentsDummy::class)->getArguments()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveChildDefinitionsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveChildDefinitionsPassTest.php deleted file mode 100644 index f3cd9fa1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveChildDefinitionsPassTest.php +++ /dev/null @@ -1,449 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class ResolveChildDefinitionsPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container->register('parent', 'foo')->setArguments(['moo', 'b'])->setProperty('foo', 'moo'); - $container->setDefinition('child', new ChildDefinition('parent')) - ->replaceArgument(0, 'a') - ->setProperty('foo', 'bar') - ->setClass('bar') - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertNotInstanceOf(ChildDefinition::class, $def); - $this->assertEquals('bar', $def->getClass()); - $this->assertEquals(['a', 'b'], $def->getArguments()); - $this->assertEquals(['foo' => 'bar'], $def->getProperties()); - } - - public function testProcessAppendsMethodCallsAlways() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addMethodCall('foo', ['bar']) - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ->addMethodCall('bar', ['foo']) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertEquals([ - ['foo', ['bar']], - ['bar', ['foo']], - ], $def->getMethodCalls()); - } - - public function testProcessDoesNotCopyAbstract() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->setAbstract(true) - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertFalse($def->isAbstract()); - } - - public function testProcessDoesNotCopyShared() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->setShared(false) - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertTrue($def->isShared()); - } - - public function testProcessDoesNotCopyTags() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addTag('foo') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertEquals([], $def->getTags()); - } - - public function testProcessDoesNotCopyDecoratedService() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->setDecoratedService('foo') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertNull($def->getDecoratedService()); - } - - public function testProcessDoesNotDropShared() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ->setShared(false) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertFalse($def->isShared()); - } - - public function testProcessHandlesMultipleInheritance() - { - $container = new ContainerBuilder(); - - $container - ->register('parent', 'foo') - ->setArguments(['foo', 'bar', 'c']) - ; - - $container - ->setDefinition('child2', new ChildDefinition('child1')) - ->replaceArgument(1, 'b') - ; - - $container - ->setDefinition('child1', new ChildDefinition('parent')) - ->replaceArgument(0, 'a') - ; - - $this->process($container); - - $def = $container->getDefinition('child2'); - $this->assertEquals(['a', 'b', 'c'], $def->getArguments()); - $this->assertEquals('foo', $def->getClass()); - } - - public function testSetLazyOnServiceHasParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass'); - - $container->setDefinition('child1', new ChildDefinition('parent')) - ->setLazy(true) - ; - - $this->process($container); - - $this->assertTrue($container->getDefinition('child1')->isLazy()); - } - - public function testSetLazyOnServiceIsParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setLazy(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')); - - $this->process($container); - - $this->assertTrue($container->getDefinition('child1')->isLazy()); - } - - public function testSetAutowiredOnServiceHasParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setAutowired(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')) - ->setAutowired(false) - ; - - $this->process($container); - - $this->assertFalse($container->getDefinition('child1')->isAutowired()); - } - - public function testSetAutowiredOnServiceIsParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setAutowired(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')); - - $this->process($container); - - $this->assertTrue($container->getDefinition('child1')->isAutowired()); - } - - public function testDeepDefinitionsResolving() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'parentClass'); - $container->register('sibling', 'siblingClass') - ->setConfigurator(new ChildDefinition('parent'), 'foo') - ->setFactory([new ChildDefinition('parent'), 'foo']) - ->addArgument(new ChildDefinition('parent')) - ->setProperty('prop', new ChildDefinition('parent')) - ->addMethodCall('meth', [new ChildDefinition('parent')]) - ; - - $this->process($container); - - $configurator = $container->getDefinition('sibling')->getConfigurator(); - $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($configurator)); - $this->assertSame('parentClass', $configurator->getClass()); - - $factory = $container->getDefinition('sibling')->getFactory(); - $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($factory[0])); - $this->assertSame('parentClass', $factory[0]->getClass()); - - $argument = $container->getDefinition('sibling')->getArgument(0); - $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($argument)); - $this->assertSame('parentClass', $argument->getClass()); - - $properties = $container->getDefinition('sibling')->getProperties(); - $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($properties['prop'])); - $this->assertSame('parentClass', $properties['prop']->getClass()); - - $methodCalls = $container->getDefinition('sibling')->getMethodCalls(); - $this->assertSame('Symfony\Component\DependencyInjection\Definition', \get_class($methodCalls[0][1][0])); - $this->assertSame('parentClass', $methodCalls[0][1][0]->getClass()); - } - - public function testSetDecoratedServiceOnServiceHasParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass'); - - $container->setDefinition('child1', new ChildDefinition('parent')) - ->setDecoratedService('foo', 'foo_inner', 5) - ; - - $this->process($container); - - $this->assertEquals(['foo', 'foo_inner', 5], $container->getDefinition('child1')->getDecoratedService()); - } - - public function testDecoratedServiceCopiesDeprecatedStatusFromParent() - { - $container = new ContainerBuilder(); - $container->register('deprecated_parent') - ->setDeprecated(true) - ; - - $container->setDefinition('decorated_deprecated_parent', new ChildDefinition('deprecated_parent')); - - $this->process($container); - - $this->assertTrue($container->getDefinition('decorated_deprecated_parent')->isDeprecated()); - } - - public function testDecoratedServiceCanOverwriteDeprecatedParentStatus() - { - $container = new ContainerBuilder(); - $container->register('deprecated_parent') - ->setDeprecated(true) - ; - - $container->setDefinition('decorated_deprecated_parent', new ChildDefinition('deprecated_parent')) - ->setDeprecated(false) - ; - - $this->process($container); - - $this->assertFalse($container->getDefinition('decorated_deprecated_parent')->isDeprecated()); - } - - /** - * @group legacy - */ - public function testProcessMergeAutowiringTypes() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addAutowiringType('Foo') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ->addAutowiringType('Bar') - ; - - $this->process($container); - - $childDef = $container->getDefinition('child'); - $this->assertEquals(['Foo', 'Bar'], $childDef->getAutowiringTypes()); - - $parentDef = $container->getDefinition('parent'); - $this->assertSame(['Foo'], $parentDef->getAutowiringTypes()); - } - - public function testProcessResolvesAliases() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'ParentClass'); - $container->setAlias('parent_alias', 'parent'); - $container->setDefinition('child', new ChildDefinition('parent_alias')); - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertSame('ParentClass', $def->getClass()); - } - - public function testProcessSetsArguments() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'ParentClass')->setArguments([0]); - $container->setDefinition('child', (new ChildDefinition('parent'))->setArguments([ - 1, - 'index_0' => 2, - 'foo' => 3, - ])); - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertSame([2, 1, 'foo' => 3], $def->getArguments()); - } - - public function testBindings() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setBindings(['a' => '1', 'b' => '2']) - ; - - $container->setDefinition('child', new ChildDefinition('parent')) - ->setBindings(['b' => 'B', 'c' => 'C']) - ; - - $this->process($container); - - $bindings = []; - foreach ($container->getDefinition('child')->getBindings() as $k => $v) { - $bindings[$k] = $v->getValues()[0]; - } - $this->assertEquals(['b' => 'B', 'c' => 'C', 'a' => '1'], $bindings); - } - - public function testSetAutoconfiguredOnServiceIsParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setAutoconfigured(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')); - - $this->process($container); - - $this->assertFalse($container->getDefinition('child1')->isAutoconfigured()); - } - - /** - * @group legacy - */ - public function testAliasExistsForBackwardsCompatibility() - { - $this->assertInstanceOf(ResolveChildDefinitionsPass::class, new ResolveDefinitionTemplatesPass()); - } - - protected function process(ContainerBuilder $container) - { - $pass = new ResolveChildDefinitionsPass(); - $pass->process($container); - } - - public function testProcessDetectsChildDefinitionIndirectCircularReference() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $this->expectExceptionMessageMatches('/^Circular reference detected for service "c", path: "c -> b -> a -> c"./'); - $container = new ContainerBuilder(); - - $container->register('a'); - - $container->setDefinition('b', new ChildDefinition('a')); - $container->setDefinition('c', new ChildDefinition('b')); - $container->setDefinition('a', new ChildDefinition('c')); - - $this->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveClassPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveClassPassTest.php deleted file mode 100644 index 81e05fb2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveClassPassTest.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\Compiler\ResolveClassPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; - -class ResolveClassPassTest extends TestCase -{ - /** - * @dataProvider provideValidClassId - */ - public function testResolveClassFromId($serviceId) - { - $container = new ContainerBuilder(); - $def = $container->register($serviceId); - - (new ResolveClassPass())->process($container); - - $this->assertSame($serviceId, $def->getClass()); - } - - public function provideValidClassId() - { - yield ['Acme\UnknownClass']; - yield [CaseSensitiveClass::class]; - } - - /** - * @dataProvider provideInvalidClassId - */ - public function testWontResolveClassFromId($serviceId) - { - $container = new ContainerBuilder(); - $def = $container->register($serviceId); - - (new ResolveClassPass())->process($container); - - $this->assertNull($def->getClass()); - } - - public function provideInvalidClassId() - { - yield [\stdClass::class]; - yield ['bar']; - yield ['\DateTime']; - } - - public function testNonFqcnChildDefinition() - { - $container = new ContainerBuilder(); - $parent = $container->register('App\Foo', null); - $child = $container->setDefinition('App\Foo.child', new ChildDefinition('App\Foo')); - - (new ResolveClassPass())->process($container); - - $this->assertSame('App\Foo', $parent->getClass()); - $this->assertNull($child->getClass()); - } - - public function testClassFoundChildDefinition() - { - $container = new ContainerBuilder(); - $parent = $container->register('App\Foo', null); - $child = $container->setDefinition(self::class, new ChildDefinition('App\Foo')); - - (new ResolveClassPass())->process($container); - - $this->assertSame('App\Foo', $parent->getClass()); - $this->assertSame(self::class, $child->getClass()); - } - - public function testAmbiguousChildDefinition() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Service definition "App\Foo\Child" has a parent but no class, and its name looks like a FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.'); - $container = new ContainerBuilder(); - $container->register('App\Foo', null); - $container->setDefinition('App\Foo\Child', new ChildDefinition('App\Foo')); - - (new ResolveClassPass())->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php deleted file mode 100644 index 407c803c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveDefinitionTemplatesPassTest.php +++ /dev/null @@ -1,407 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\Compiler\ResolveDefinitionTemplatesPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -/** - * @group legacy - */ -class ResolveDefinitionTemplatesPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container->register('parent', 'foo')->setArguments(['moo', 'b'])->setProperty('foo', 'moo'); - $container->setDefinition('child', new ChildDefinition('parent')) - ->replaceArgument(0, 'a') - ->setProperty('foo', 'bar') - ->setClass('bar') - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertNotInstanceOf(ChildDefinition::class, $def); - $this->assertEquals('bar', $def->getClass()); - $this->assertEquals(['a', 'b'], $def->getArguments()); - $this->assertEquals(['foo' => 'bar'], $def->getProperties()); - } - - public function testProcessAppendsMethodCallsAlways() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addMethodCall('foo', ['bar']) - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ->addMethodCall('bar', ['foo']) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertEquals([ - ['foo', ['bar']], - ['bar', ['foo']], - ], $def->getMethodCalls()); - } - - public function testProcessDoesNotCopyAbstract() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->setAbstract(true) - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertFalse($def->isAbstract()); - } - - public function testProcessDoesNotCopyShared() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->setShared(false) - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertTrue($def->isShared()); - } - - public function testProcessDoesNotCopyTags() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addTag('foo') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertEquals([], $def->getTags()); - } - - public function testProcessDoesNotCopyDecoratedService() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->setDecoratedService('foo') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertNull($def->getDecoratedService()); - } - - public function testProcessDoesNotDropShared() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ->setShared(false) - ; - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertFalse($def->isShared()); - } - - public function testProcessHandlesMultipleInheritance() - { - $container = new ContainerBuilder(); - - $container - ->register('parent', 'foo') - ->setArguments(['foo', 'bar', 'c']) - ; - - $container - ->setDefinition('child2', new ChildDefinition('child1')) - ->replaceArgument(1, 'b') - ; - - $container - ->setDefinition('child1', new ChildDefinition('parent')) - ->replaceArgument(0, 'a') - ; - - $this->process($container); - - $def = $container->getDefinition('child2'); - $this->assertEquals(['a', 'b', 'c'], $def->getArguments()); - $this->assertEquals('foo', $def->getClass()); - } - - public function testSetLazyOnServiceHasParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass'); - - $container->setDefinition('child1', new ChildDefinition('parent')) - ->setLazy(true) - ; - - $this->process($container); - - $this->assertTrue($container->getDefinition('child1')->isLazy()); - } - - public function testSetLazyOnServiceIsParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setLazy(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')); - - $this->process($container); - - $this->assertTrue($container->getDefinition('child1')->isLazy()); - } - - public function testSetAutowiredOnServiceHasParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setAutowired(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')) - ->setAutowired(false) - ; - - $this->process($container); - - $this->assertFalse($container->getDefinition('child1')->isAutowired()); - } - - public function testSetAutowiredOnServiceIsParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setAutowired(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')); - - $this->process($container); - - $this->assertTrue($container->getDefinition('child1')->isAutowired()); - } - - public function testDeepDefinitionsResolving() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'parentClass'); - $container->register('sibling', 'siblingClass') - ->setConfigurator(new ChildDefinition('parent'), 'foo') - ->setFactory([new ChildDefinition('parent'), 'foo']) - ->addArgument(new ChildDefinition('parent')) - ->setProperty('prop', new ChildDefinition('parent')) - ->addMethodCall('meth', [new ChildDefinition('parent')]) - ; - - $this->process($container); - - $configurator = $container->getDefinition('sibling')->getConfigurator(); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $configurator); - $this->assertSame('parentClass', $configurator->getClass()); - - $factory = $container->getDefinition('sibling')->getFactory(); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $factory[0]); - $this->assertSame('parentClass', $factory[0]->getClass()); - - $argument = $container->getDefinition('sibling')->getArgument(0); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $argument); - $this->assertSame('parentClass', $argument->getClass()); - - $properties = $container->getDefinition('sibling')->getProperties(); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $properties['prop']); - $this->assertSame('parentClass', $properties['prop']->getClass()); - - $methodCalls = $container->getDefinition('sibling')->getMethodCalls(); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $methodCalls[0][1][0]); - $this->assertSame('parentClass', $methodCalls[0][1][0]->getClass()); - } - - public function testSetDecoratedServiceOnServiceHasParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass'); - - $container->setDefinition('child1', new ChildDefinition('parent')) - ->setDecoratedService('foo', 'foo_inner', 5) - ; - - $this->process($container); - - $this->assertEquals(['foo', 'foo_inner', 5], $container->getDefinition('child1')->getDecoratedService()); - } - - public function testDecoratedServiceCopiesDeprecatedStatusFromParent() - { - $container = new ContainerBuilder(); - $container->register('deprecated_parent') - ->setDeprecated(true) - ; - - $container->setDefinition('decorated_deprecated_parent', new ChildDefinition('deprecated_parent')); - - $this->process($container); - - $this->assertTrue($container->getDefinition('decorated_deprecated_parent')->isDeprecated()); - } - - public function testDecoratedServiceCanOverwriteDeprecatedParentStatus() - { - $container = new ContainerBuilder(); - $container->register('deprecated_parent') - ->setDeprecated(true) - ; - - $container->setDefinition('decorated_deprecated_parent', new ChildDefinition('deprecated_parent')) - ->setDeprecated(false) - ; - - $this->process($container); - - $this->assertFalse($container->getDefinition('decorated_deprecated_parent')->isDeprecated()); - } - - /** - * @group legacy - */ - public function testProcessMergeAutowiringTypes() - { - $container = new ContainerBuilder(); - - $container - ->register('parent') - ->addAutowiringType('Foo') - ; - - $container - ->setDefinition('child', new ChildDefinition('parent')) - ->addAutowiringType('Bar') - ; - - $this->process($container); - - $childDef = $container->getDefinition('child'); - $this->assertEquals(['Foo', 'Bar'], $childDef->getAutowiringTypes()); - - $parentDef = $container->getDefinition('parent'); - $this->assertSame(['Foo'], $parentDef->getAutowiringTypes()); - } - - public function testProcessResolvesAliases() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'ParentClass'); - $container->setAlias('parent_alias', 'parent'); - $container->setDefinition('child', new ChildDefinition('parent_alias')); - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertSame('ParentClass', $def->getClass()); - } - - public function testProcessSetsArguments() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'ParentClass')->setArguments([0]); - $container->setDefinition('child', (new ChildDefinition('parent'))->setArguments([ - 1, - 'index_0' => 2, - 'foo' => 3, - ])); - - $this->process($container); - - $def = $container->getDefinition('child'); - $this->assertSame([2, 1, 'foo' => 3], $def->getArguments()); - } - - public function testSetAutoconfiguredOnServiceIsParent() - { - $container = new ContainerBuilder(); - - $container->register('parent', 'stdClass') - ->setAutoconfigured(true) - ; - - $container->setDefinition('child1', new ChildDefinition('parent')); - - $this->process($container); - - $this->assertFalse($container->getDefinition('child1')->isAutoconfigured()); - } - - protected function process(ContainerBuilder $container) - { - $pass = new ResolveDefinitionTemplatesPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveFactoryClassPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveFactoryClassPassTest.php deleted file mode 100644 index b87fb3db..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveFactoryClassPassTest.php +++ /dev/null @@ -1,86 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\ResolveFactoryClassPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class ResolveFactoryClassPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $factory = $container->register('factory', 'Foo\Bar'); - $factory->setFactory([null, 'create']); - - $pass = new ResolveFactoryClassPass(); - $pass->process($container); - - $this->assertSame(['Foo\Bar', 'create'], $factory->getFactory()); - } - - public function testInlinedDefinitionFactoryIsProcessed() - { - $container = new ContainerBuilder(); - - $factory = $container->register('factory'); - $factory->setFactory([(new Definition('Baz\Qux'))->setFactory([null, 'getInstance']), 'create']); - - $pass = new ResolveFactoryClassPass(); - $pass->process($container); - - $this->assertSame(['Baz\Qux', 'getInstance'], $factory->getFactory()[0]->getFactory()); - } - - public function provideFulfilledFactories() - { - return [ - [['Foo\Bar', 'create']], - [[new Reference('foo'), 'create']], - [[new Definition('Baz'), 'create']], - ]; - } - - /** - * @dataProvider provideFulfilledFactories - */ - public function testIgnoresFulfilledFactories($factory) - { - $container = new ContainerBuilder(); - $definition = new Definition(); - $definition->setFactory($factory); - - $container->setDefinition('factory', $definition); - - $pass = new ResolveFactoryClassPass(); - $pass->process($container); - - $this->assertSame($factory, $container->getDefinition('factory')->getFactory()); - } - - public function testNotAnyClassThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The "factory" service is defined to be created by a factory, but is missing the factory class. Did you forget to define the factory or service class?'); - $container = new ContainerBuilder(); - - $factory = $container->register('factory'); - $factory->setFactory([null, 'create']); - - $pass = new ResolveFactoryClassPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveHotPathPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveHotPathPassTest.php deleted file mode 100644 index a2fece05..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveHotPathPassTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\ResolveHotPathPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class ResolveHotPathPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $container->register('foo') - ->addTag('container.hot_path') - ->addArgument(new IteratorArgument([new Reference('lazy')])) - ->addArgument(new Reference('service_container')) - ->addArgument(new Definition('', [new Reference('bar')])) - ->addArgument(new Reference('baz', ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE)) - ->addArgument(new Reference('missing')) - ; - - $container->register('lazy'); - $container->register('bar') - ->addArgument(new Reference('buz')) - ->addArgument(new Reference('deprec_ref_notag')); - $container->register('baz') - ->addArgument(new Reference('lazy')) - ->addArgument(new Reference('lazy')); - $container->register('buz'); - $container->register('deprec_with_tag')->setDeprecated()->addTag('container.hot_path'); - $container->register('deprec_ref_notag')->setDeprecated(); - - (new ResolveHotPathPass())->process($container); - - $this->assertFalse($container->getDefinition('lazy')->hasTag('container.hot_path')); - $this->assertTrue($container->getDefinition('bar')->hasTag('container.hot_path')); - $this->assertTrue($container->getDefinition('buz')->hasTag('container.hot_path')); - $this->assertFalse($container->getDefinition('baz')->hasTag('container.hot_path')); - $this->assertFalse($container->getDefinition('service_container')->hasTag('container.hot_path')); - $this->assertFalse($container->getDefinition('deprec_with_tag')->hasTag('container.hot_path')); - $this->assertFalse($container->getDefinition('deprec_ref_notag')->hasTag('container.hot_path')); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php deleted file mode 100644 index 0d81cdf3..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php +++ /dev/null @@ -1,262 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\BoundArgument; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass; -use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class ResolveInstanceofConditionalsPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $def = $container->register('foo', self::class)->addTag('tag')->setAutowired(true)->setChanges([]); - $def->setInstanceofConditionals([ - parent::class => (new ChildDefinition(''))->setProperty('foo', 'bar')->addTag('baz', ['attr' => 123]), - ]); - - (new ResolveInstanceofConditionalsPass())->process($container); - - $parent = 'instanceof.'.parent::class.'.0.foo'; - $def = $container->getDefinition('foo'); - $this->assertEmpty($def->getInstanceofConditionals()); - $this->assertInstanceOf(ChildDefinition::class, $def); - $this->assertTrue($def->isAutowired()); - $this->assertSame($parent, $def->getParent()); - $this->assertSame(['tag' => [[]], 'baz' => [['attr' => 123]]], $def->getTags()); - - $parent = $container->getDefinition($parent); - $this->assertSame(['foo' => 'bar'], $parent->getProperties()); - $this->assertSame([], $parent->getTags()); - } - - public function testProcessInheritance() - { - $container = new ContainerBuilder(); - - $def = $container - ->register('parent', parent::class) - ->addMethodCall('foo', ['foo']); - $def->setInstanceofConditionals([ - parent::class => (new ChildDefinition(''))->addMethodCall('foo', ['bar']), - ]); - - $def = (new ChildDefinition('parent'))->setClass(self::class); - $container->setDefinition('child', $def); - - (new ResolveInstanceofConditionalsPass())->process($container); - (new ResolveChildDefinitionsPass())->process($container); - - $expected = [ - ['foo', ['bar']], - ['foo', ['foo']], - ]; - - $this->assertSame($expected, $container->getDefinition('parent')->getMethodCalls()); - $this->assertSame($expected, $container->getDefinition('child')->getMethodCalls()); - } - - public function testProcessDoesReplaceShared() - { - $container = new ContainerBuilder(); - - $def = $container->register('foo', 'stdClass'); - $def->setInstanceofConditionals([ - 'stdClass' => (new ChildDefinition(''))->setShared(false), - ]); - - (new ResolveInstanceofConditionalsPass())->process($container); - - $def = $container->getDefinition('foo'); - $this->assertFalse($def->isShared()); - } - - public function testProcessHandlesMultipleInheritance() - { - $container = new ContainerBuilder(); - - $def = $container->register('foo', self::class)->setShared(true); - - $def->setInstanceofConditionals([ - parent::class => (new ChildDefinition(''))->setLazy(true)->setShared(false), - self::class => (new ChildDefinition(''))->setAutowired(true), - ]); - - (new ResolveInstanceofConditionalsPass())->process($container); - (new ResolveChildDefinitionsPass())->process($container); - - $def = $container->getDefinition('foo'); - $this->assertTrue($def->isAutowired()); - $this->assertTrue($def->isLazy()); - $this->assertTrue($def->isShared()); - } - - public function testProcessUsesAutoconfiguredInstanceof() - { - $container = new ContainerBuilder(); - $def = $container->register('normal_service', self::class); - $def->setInstanceofConditionals([ - parent::class => (new ChildDefinition('')) - ->addTag('local_instanceof_tag') - ->setFactory('locally_set_factory'), - ]); - $def->setAutoconfigured(true); - $container->registerForAutoconfiguration(parent::class) - ->addTag('autoconfigured_tag') - ->setAutowired(true) - ->setFactory('autoconfigured_factory'); - - (new ResolveInstanceofConditionalsPass())->process($container); - (new ResolveChildDefinitionsPass())->process($container); - - $def = $container->getDefinition('normal_service'); - // autowired thanks to the autoconfigured instanceof - $this->assertTrue($def->isAutowired()); - // factory from the specific instanceof overrides global one - $this->assertEquals('locally_set_factory', $def->getFactory()); - // tags are merged, the locally set one is first - $this->assertSame(['local_instanceof_tag' => [[]], 'autoconfigured_tag' => [[]]], $def->getTags()); - } - - public function testAutoconfigureInstanceofDoesNotDuplicateTags() - { - $container = new ContainerBuilder(); - $def = $container->register('normal_service', self::class); - $def - ->addTag('duplicated_tag') - ->addTag('duplicated_tag', ['and_attributes' => 1]) - ; - $def->setInstanceofConditionals([ - parent::class => (new ChildDefinition(''))->addTag('duplicated_tag'), - ]); - $def->setAutoconfigured(true); - $container->registerForAutoconfiguration(parent::class) - ->addTag('duplicated_tag', ['and_attributes' => 1]) - ; - - (new ResolveInstanceofConditionalsPass())->process($container); - (new ResolveChildDefinitionsPass())->process($container); - - $def = $container->getDefinition('normal_service'); - $this->assertSame(['duplicated_tag' => [[], ['and_attributes' => 1]]], $def->getTags()); - } - - public function testProcessDoesNotUseAutoconfiguredInstanceofIfNotEnabled() - { - $container = new ContainerBuilder(); - $def = $container->register('normal_service', self::class); - $def->setInstanceofConditionals([ - parent::class => (new ChildDefinition('')) - ->addTag('foo_tag'), - ]); - $container->registerForAutoconfiguration(parent::class) - ->setAutowired(true); - - (new ResolveInstanceofConditionalsPass())->process($container); - (new ResolveChildDefinitionsPass())->process($container); - - $def = $container->getDefinition('normal_service'); - $this->assertFalse($def->isAutowired()); - } - - public function testBadInterfaceThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('"App\FakeInterface" is set as an "instanceof" conditional, but it does not exist.'); - $container = new ContainerBuilder(); - $def = $container->register('normal_service', self::class); - $def->setInstanceofConditionals([ - 'App\\FakeInterface' => (new ChildDefinition('')) - ->addTag('foo_tag'), - ]); - - (new ResolveInstanceofConditionalsPass())->process($container); - } - - public function testBadInterfaceForAutomaticInstanceofIsOk() - { - $container = new ContainerBuilder(); - $container->register('normal_service', self::class) - ->setAutoconfigured(true); - $container->registerForAutoconfiguration('App\\FakeInterface') - ->setAutowired(true); - - (new ResolveInstanceofConditionalsPass())->process($container); - $this->assertTrue($container->hasDefinition('normal_service')); - } - - public function testProcessThrowsExceptionForAutoconfiguredCalls() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Autoconfigured instanceof for type "PHPUnit[\\\\_]Framework[\\\\_]TestCase" defines method calls but these are not supported and should be removed\./'); - $container = new ContainerBuilder(); - $container->registerForAutoconfiguration(parent::class) - ->addMethodCall('setFoo'); - - (new ResolveInstanceofConditionalsPass())->process($container); - } - - public function testProcessThrowsExceptionForArguments() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Autoconfigured instanceof for type "PHPUnit[\\\\_]Framework[\\\\_]TestCase" defines arguments but these are not supported and should be removed\./'); - $container = new ContainerBuilder(); - $container->registerForAutoconfiguration(parent::class) - ->addArgument('bar'); - - (new ResolveInstanceofConditionalsPass())->process($container); - } - - public function testMergeReset() - { - $container = new ContainerBuilder(); - - $container - ->register('bar', self::class) - ->addArgument('a') - ->addMethodCall('setB') - ->setDecoratedService('foo') - ->addTag('t') - ->setInstanceofConditionals([ - parent::class => (new ChildDefinition(''))->addTag('bar'), - ]) - ; - - (new ResolveInstanceofConditionalsPass())->process($container); - - $abstract = $container->getDefinition('abstract.instanceof.bar'); - - $this->assertEmpty($abstract->getArguments()); - $this->assertEmpty($abstract->getMethodCalls()); - $this->assertNull($abstract->getDecoratedService()); - $this->assertEmpty($abstract->getTags()); - $this->assertTrue($abstract->isAbstract()); - } - - public function testBindings() - { - $container = new ContainerBuilder(); - $def = $container->register('foo', self::class)->setBindings(['$toto' => 123]); - $def->setInstanceofConditionals([parent::class => new ChildDefinition('')]); - - (new ResolveInstanceofConditionalsPass())->process($container); - - $bindings = $container->getDefinition('foo')->getBindings(); - $this->assertSame(['$toto'], array_keys($bindings)); - $this->assertInstanceOf(BoundArgument::class, $bindings['$toto']); - $this->assertSame(123, $bindings['$toto']->getValues()[0]); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveInvalidReferencesPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveInvalidReferencesPassTest.php deleted file mode 100644 index 817cc64c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveInvalidReferencesPassTest.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Reference; - -class ResolveInvalidReferencesPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $def = $container - ->register('foo') - ->setArguments([ - new Reference('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE), - new Reference('baz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), - ]) - ->addMethodCall('foo', [new Reference('moo', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]) - ; - - $this->process($container); - - $arguments = $def->getArguments(); - $this->assertSame([null, null], $arguments); - $this->assertCount(0, $def->getMethodCalls()); - } - - public function testProcessIgnoreInvalidArgumentInCollectionArgument() - { - $container = new ContainerBuilder(); - $container->register('baz'); - $def = $container - ->register('foo') - ->setArguments([ - [ - new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), - $baz = new Reference('baz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), - new Reference('moo', ContainerInterface::NULL_ON_INVALID_REFERENCE), - ], - ]) - ; - - $this->process($container); - - $arguments = $def->getArguments(); - $this->assertSame([$baz, null], $arguments[0]); - } - - public function testProcessKeepMethodCallOnInvalidArgumentInCollectionArgument() - { - $container = new ContainerBuilder(); - $container->register('baz'); - $def = $container - ->register('foo') - ->addMethodCall('foo', [ - [ - new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), - $baz = new Reference('baz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), - new Reference('moo', ContainerInterface::NULL_ON_INVALID_REFERENCE), - ], - ]) - ; - - $this->process($container); - - $calls = $def->getMethodCalls(); - $this->assertCount(1, $def->getMethodCalls()); - $this->assertSame([$baz, null], $calls[0][1][0]); - } - - public function testProcessIgnoreNonExistentServices() - { - $container = new ContainerBuilder(); - $def = $container - ->register('foo') - ->setArguments([new Reference('bar')]) - ; - - $this->process($container); - - $arguments = $def->getArguments(); - $this->assertEquals('bar', (string) $arguments[0]); - } - - public function testProcessRemovesPropertiesOnInvalid() - { - $container = new ContainerBuilder(); - $def = $container - ->register('foo') - ->setProperty('foo', new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)) - ; - - $this->process($container); - - $this->assertEquals([], $def->getProperties()); - } - - public function testProcessRemovesArgumentsOnInvalid() - { - $container = new ContainerBuilder(); - $def = $container - ->register('foo') - ->addArgument([ - [ - new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE), - new ServiceClosureArgument(new Reference('baz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)), - ], - ]) - ; - - $this->process($container); - - $this->assertSame([[[]]], $def->getArguments()); - } - - protected function process(ContainerBuilder $container) - { - $pass = new ResolveInvalidReferencesPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveNamedArgumentsPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveNamedArgumentsPassTest.php deleted file mode 100644 index a10d226f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveNamedArgumentsPassTest.php +++ /dev/null @@ -1,173 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\ResolveNamedArgumentsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummyWithoutReturnTypes; -use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; -use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy; -use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1; - -/** - * @author Kévin Dunglas - */ -class ResolveNamedArgumentsPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - - $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); - $definition->setArguments([ - 2 => 'http://api.example.com', - '$apiKey' => '123', - 0 => new Reference('foo'), - ]); - $definition->addMethodCall('setApiKey', ['$apiKey' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - - $this->assertEquals([0 => new Reference('foo'), 1 => '123', 2 => 'http://api.example.com'], $definition->getArguments()); - $this->assertEquals([['setApiKey', ['123']]], $definition->getMethodCalls()); - } - - public function testWithFactory() - { - $container = new ContainerBuilder(); - - $container->register('factory', NoConstructor::class); - $definition = $container->register('foo', NoConstructor::class) - ->setFactory([new Reference('factory'), 'create']) - ->setArguments(['$apiKey' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - - $this->assertSame([0 => '123'], $definition->getArguments()); - } - - public function testClassNull() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - - $definition = $container->register(NamedArgumentsDummy::class); - $definition->setArguments(['$apiKey' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - } - - public function testClassNotExist() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - - $definition = $container->register(NotExist::class, NotExist::class); - $definition->setArguments(['$apiKey' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - } - - public function testClassNoConstructor() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $container = new ContainerBuilder(); - - $definition = $container->register(NoConstructor::class, NoConstructor::class); - $definition->setArguments(['$apiKey' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - } - - public function testArgumentNotFound() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy": method "__construct()" has no argument named "$notFound". Check your service definition.'); - $container = new ContainerBuilder(); - - $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); - $definition->setArguments(['$notFound' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - } - - public function testCorrectMethodReportedInException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid service "Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1": method "Symfony\Component\DependencyInjection\Tests\Fixtures\FactoryDummyWithoutReturnTypes::createTestDefinition1()" has no argument named "$notFound". Check your service definition.'); - $container = new ContainerBuilder(); - - $container->register(FactoryDummyWithoutReturnTypes::class, FactoryDummyWithoutReturnTypes::class); - - $definition = $container->register(TestDefinition1::class, TestDefinition1::class); - $definition->setFactory([FactoryDummyWithoutReturnTypes::class, 'createTestDefinition1']); - $definition->setArguments(['$notFound' => '123']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - } - - public function testTypedArgument() - { - $container = new ContainerBuilder(); - - $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); - $definition->setArguments(['$apiKey' => '123', CaseSensitiveClass::class => new Reference('foo')]); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - - $this->assertEquals([new Reference('foo'), '123'], $definition->getArguments()); - } - - public function testResolvesMultipleArgumentsOfTheSameType() - { - $container = new ContainerBuilder(); - - $definition = $container->register(SimilarArgumentsDummy::class, SimilarArgumentsDummy::class); - $definition->setArguments([CaseSensitiveClass::class => new Reference('foo'), '$token' => 'qwerty']); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - - $this->assertEquals([new Reference('foo'), 'qwerty', new Reference('foo')], $definition->getArguments()); - } - - public function testResolvePrioritizeNamedOverType() - { - $container = new ContainerBuilder(); - - $definition = $container->register(SimilarArgumentsDummy::class, SimilarArgumentsDummy::class); - $definition->setArguments([CaseSensitiveClass::class => new Reference('foo'), '$token' => 'qwerty', '$class1' => new Reference('bar')]); - - $pass = new ResolveNamedArgumentsPass(); - $pass->process($container); - - $this->assertEquals([new Reference('bar'), 'qwerty', new Reference('foo')], $definition->getArguments()); - } -} - -class NoConstructor -{ - public static function create($apiKey) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php deleted file mode 100644 index 06399614..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php +++ /dev/null @@ -1,126 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; - -class ResolveParameterPlaceHoldersPassTest extends TestCase -{ - private $compilerPass; - private $container; - private $fooDefinition; - - protected function setUp() - { - $this->compilerPass = new ResolveParameterPlaceHoldersPass(); - $this->container = $this->createContainerBuilder(); - $this->compilerPass->process($this->container); - $this->fooDefinition = $this->container->getDefinition('foo'); - } - - public function testClassParametersShouldBeResolved() - { - $this->assertSame('Foo', $this->fooDefinition->getClass()); - } - - public function testFactoryParametersShouldBeResolved() - { - $this->assertSame(['FooFactory', 'getFoo'], $this->fooDefinition->getFactory()); - } - - public function testArgumentParametersShouldBeResolved() - { - $this->assertSame(['bar', ['bar' => 'baz']], $this->fooDefinition->getArguments()); - } - - public function testMethodCallParametersShouldBeResolved() - { - $this->assertSame([['foobar', ['bar', ['bar' => 'baz']]]], $this->fooDefinition->getMethodCalls()); - } - - public function testPropertyParametersShouldBeResolved() - { - $this->assertSame(['bar' => 'baz'], $this->fooDefinition->getProperties()); - } - - public function testFileParametersShouldBeResolved() - { - $this->assertSame('foo.php', $this->fooDefinition->getFile()); - } - - public function testAliasParametersShouldBeResolved() - { - $this->assertSame('foo', $this->container->getAlias('bar')->__toString()); - } - - public function testBindingsShouldBeResolved() - { - list($boundValue) = $this->container->getDefinition('foo')->getBindings()['$baz']->getValues(); - - $this->assertSame($this->container->getParameterBag()->resolveValue('%env(BAZ)%'), $boundValue); - } - - public function testParameterNotFoundExceptionsIsThrown() - { - $this->expectException(ParameterNotFoundException::class); - $this->expectExceptionMessage('The service "baz_service_id" has a dependency on a non-existent parameter "non_existent_param".'); - - $containerBuilder = new ContainerBuilder(); - $definition = $containerBuilder->register('baz_service_id'); - $definition->setArgument(0, '%non_existent_param%'); - - $pass = new ResolveParameterPlaceHoldersPass(); - $pass->process($containerBuilder); - } - - public function testParameterNotFoundExceptionsIsNotThrown() - { - $containerBuilder = new ContainerBuilder(); - $definition = $containerBuilder->register('baz_service_id'); - $definition->setArgument(0, '%non_existent_param%'); - - $pass = new ResolveParameterPlaceHoldersPass(true, false); - $pass->process($containerBuilder); - - $this->assertCount(1, $definition->getErrors()); - } - - private function createContainerBuilder() - { - $containerBuilder = new ContainerBuilder(); - - $containerBuilder->setParameter('foo.class', 'Foo'); - $containerBuilder->setParameter('foo.factory.class', 'FooFactory'); - $containerBuilder->setParameter('foo.arg1', 'bar'); - $containerBuilder->setParameter('foo.arg2', ['%foo.arg1%' => 'baz']); - $containerBuilder->setParameter('foo.method', 'foobar'); - $containerBuilder->setParameter('foo.property.name', 'bar'); - $containerBuilder->setParameter('foo.property.value', 'baz'); - $containerBuilder->setParameter('foo.file', 'foo.php'); - $containerBuilder->setParameter('alias.id', 'bar'); - - $fooDefinition = $containerBuilder->register('foo', '%foo.class%'); - $fooDefinition->setFactory(['%foo.factory.class%', 'getFoo']); - $fooDefinition->setArguments(['%foo.arg1%', ['%foo.arg1%' => 'baz']]); - $fooDefinition->addMethodCall('%foo.method%', ['%foo.arg1%', '%foo.arg2%']); - $fooDefinition->setProperty('%foo.property.name%', '%foo.property.value%'); - $fooDefinition->setFile('%foo.file%'); - $fooDefinition->setBindings(['$baz' => '%env(BAZ)%']); - - $containerBuilder->setAlias('%alias.id%', 'foo'); - - return $containerBuilder; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolvePrivatesPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolvePrivatesPassTest.php deleted file mode 100644 index 89af24f2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolvePrivatesPassTest.php +++ /dev/null @@ -1,39 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\ResolvePrivatesPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class ResolvePrivatesPassTest extends TestCase -{ - public function testPrivateHasHigherPrecedenceThanPublic() - { - $container = new ContainerBuilder(); - - $container->register('foo', 'stdClass') - ->setPublic(true) - ->setPrivate(true) - ; - - $container->setAlias('bar', 'foo') - ->setPublic(false) - ->setPrivate(false) - ; - - (new ResolvePrivatesPass())->process($container); - - $this->assertFalse($container->getDefinition('foo')->isPublic()); - $this->assertFalse($container->getAlias('bar')->isPublic()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php deleted file mode 100644 index 2465bb7e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveReferencesToAliasesPassTest.php +++ /dev/null @@ -1,89 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Alias; -use Symfony\Component\DependencyInjection\Compiler\ResolveReferencesToAliasesPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Reference; - -class ResolveReferencesToAliasesPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container->setAlias('bar', 'foo'); - $def = $container - ->register('moo') - ->setArguments([new Reference('bar')]) - ; - - $this->process($container); - - $arguments = $def->getArguments(); - $this->assertEquals('foo', (string) $arguments[0]); - } - - public function testProcessRecursively() - { - $container = new ContainerBuilder(); - $container->setAlias('bar', 'foo'); - $container->setAlias('moo', 'bar'); - $def = $container - ->register('foobar') - ->setArguments([new Reference('moo')]) - ; - - $this->process($container); - - $arguments = $def->getArguments(); - $this->assertEquals('foo', (string) $arguments[0]); - } - - public function testAliasCircularReference() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $container = new ContainerBuilder(); - $container->setAlias('bar', 'foo'); - $container->setAlias('foo', 'bar'); - $this->process($container); - } - - public function testResolveFactory() - { - $container = new ContainerBuilder(); - $container->register('factory', 'Factory'); - $container->setAlias('factory_alias', new Alias('factory')); - $foo = new Definition(); - $foo->setFactory([new Reference('factory_alias'), 'createFoo']); - $container->setDefinition('foo', $foo); - $bar = new Definition(); - $bar->setFactory(['Factory', 'createFoo']); - $container->setDefinition('bar', $bar); - - $this->process($container); - - $resolvedFooFactory = $container->getDefinition('foo')->getFactory(); - $resolvedBarFactory = $container->getDefinition('bar')->getFactory(); - - $this->assertSame('factory', (string) $resolvedFooFactory[0]); - $this->assertSame('Factory', (string) $resolvedBarFactory[0]); - } - - protected function process(ContainerBuilder $container) - { - $pass = new ResolveReferencesToAliasesPass(); - $pass->process($container); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveTaggedIteratorArgumentPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ResolveTaggedIteratorArgumentPassTest.php deleted file mode 100644 index 2322817e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ResolveTaggedIteratorArgumentPassTest.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\ResolveTaggedIteratorArgumentPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; - -/** - * @author Roland Franssen - */ -class ResolveTaggedIteratorArgumentPassTest extends TestCase -{ - public function testProcess() - { - $container = new ContainerBuilder(); - $container->register('a', 'stdClass')->addTag('foo'); - $container->register('b', 'stdClass')->addTag('foo', ['priority' => 20]); - $container->register('c', 'stdClass')->addTag('foo', ['priority' => 10]); - $container->register('d', 'stdClass')->setProperty('foos', new TaggedIteratorArgument('foo')); - - (new ResolveTaggedIteratorArgumentPass())->process($container); - - $properties = $container->getDefinition('d')->getProperties(); - $expected = new TaggedIteratorArgument('foo'); - $expected->setValues([new Reference('b'), new Reference('c'), new Reference('a')]); - $this->assertEquals($expected, $properties['foos']); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Compiler/ServiceLocatorTagPassTest.php b/vendor/symfony/dependency-injection/Tests/Compiler/ServiceLocatorTagPassTest.php deleted file mode 100644 index 66af69b5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Compiler/ServiceLocatorTagPassTest.php +++ /dev/null @@ -1,145 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Compiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\BoundArgument; -use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; -use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1; -use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition2; - -require_once __DIR__.'/../Fixtures/includes/classes.php'; - -class ServiceLocatorTagPassTest extends TestCase -{ - public function testNoServices() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid definition for service "foo": an array of references is expected as first argument when the "container.service_locator" tag is set.'); - $container = new ContainerBuilder(); - - $container->register('foo', ServiceLocator::class) - ->addTag('container.service_locator') - ; - - (new ServiceLocatorTagPass())->process($container); - } - - public function testInvalidServices() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid definition for service "foo": an array of references is expected as first argument when the "container.service_locator" tag is set, "string" found for key "0".'); - $container = new ContainerBuilder(); - - $container->register('foo', ServiceLocator::class) - ->setArguments([[ - 'dummy', - ]]) - ->addTag('container.service_locator') - ; - - (new ServiceLocatorTagPass())->process($container); - } - - public function testProcessValue() - { - $container = new ContainerBuilder(); - - $container->register('bar', CustomDefinition::class); - $container->register('baz', CustomDefinition::class); - - $container->register('foo', ServiceLocator::class) - ->setArguments([[ - new Reference('bar'), - new Reference('baz'), - 'some.service' => new Reference('bar'), - ]]) - ->addTag('container.service_locator') - ; - - (new ServiceLocatorTagPass())->process($container); - - /** @var ServiceLocator $locator */ - $locator = $container->get('foo'); - - $this->assertSame(CustomDefinition::class, \get_class($locator('bar'))); - $this->assertSame(CustomDefinition::class, \get_class($locator('baz'))); - $this->assertSame(CustomDefinition::class, \get_class($locator('some.service'))); - } - - public function testServiceWithKeyOverwritesPreviousInheritedKey() - { - $container = new ContainerBuilder(); - - $container->register('bar', TestDefinition1::class); - $container->register('baz', TestDefinition2::class); - - $container->register('foo', ServiceLocator::class) - ->setArguments([[ - new Reference('bar'), - 'bar' => new Reference('baz'), - ]]) - ->addTag('container.service_locator') - ; - - (new ServiceLocatorTagPass())->process($container); - - /** @var ServiceLocator $locator */ - $locator = $container->get('foo'); - - $this->assertSame(TestDefinition2::class, \get_class($locator('bar'))); - } - - public function testInheritedKeyOverwritesPreviousServiceWithKey() - { - $container = new ContainerBuilder(); - - $container->register('bar', TestDefinition1::class); - $container->register('baz', TestDefinition2::class); - - $container->register('foo', ServiceLocator::class) - ->setArguments([[ - 'bar' => new Reference('baz'), - new Reference('bar'), - 16 => new Reference('baz'), - ]]) - ->addTag('container.service_locator') - ; - - (new ServiceLocatorTagPass())->process($container); - - /** @var ServiceLocator $locator */ - $locator = $container->get('foo'); - - $this->assertSame(TestDefinition1::class, \get_class($locator('bar'))); - $this->assertSame(TestDefinition2::class, \get_class($locator(16))); - } - - public function testBindingsAreCopied() - { - $container = new ContainerBuilder(); - - $container->register('foo') - ->setBindings(['foo' => 'foo']); - - $locator = ServiceLocatorTagPass::register($container, ['foo' => new Reference('foo')], 'foo'); - $locator = $container->getDefinition($locator); - $locator = $container->getDefinition($locator->getFactory()[0]); - - $this->assertSame(['foo'], array_keys($locator->getBindings())); - $this->assertInstanceOf(BoundArgument::class, $locator->getBindings()['foo']); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Config/AutowireServiceResourceTest.php b/vendor/symfony/dependency-injection/Tests/Config/AutowireServiceResourceTest.php deleted file mode 100644 index 32515507..00000000 --- a/vendor/symfony/dependency-injection/Tests/Config/AutowireServiceResourceTest.php +++ /dev/null @@ -1,122 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Config; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Compiler\AutowirePass; -use Symfony\Component\DependencyInjection\Config\AutowireServiceResource; - -/** - * @group legacy - */ -class AutowireServiceResourceTest extends TestCase -{ - /** - * @var AutowireServiceResource - */ - private $resource; - private $file; - private $class; - private $time; - - protected function setUp() - { - $this->file = realpath(sys_get_temp_dir()).'/tmp.php'; - $this->time = time(); - touch($this->file, $this->time); - - $this->class = Foo::class; - $this->resource = new AutowireServiceResource( - $this->class, - $this->file, - [] - ); - } - - public function testToString() - { - $this->assertSame('service.autowire.'.$this->class, (string) $this->resource); - } - - public function testSerializeUnserialize() - { - $unserialized = unserialize(serialize($this->resource)); - - $this->assertEquals($this->resource, $unserialized); - } - - public function testIsFresh() - { - $this->assertTrue($this->resource->isFresh($this->time), '->isFresh() returns true if the resource has not changed in same second'); - $this->assertTrue($this->resource->isFresh($this->time + 10), '->isFresh() returns true if the resource has not changed'); - $this->assertFalse($this->resource->isFresh($this->time - 86400), '->isFresh() returns false if the resource has been updated'); - } - - public function testIsFreshForDeletedResources() - { - unlink($this->file); - - $this->assertFalse($this->resource->isFresh($this->getStaleFileTime()), '->isFresh() returns false if the resource does not exist'); - } - - public function testIsNotFreshChangedResource() - { - $oldResource = new AutowireServiceResource( - $this->class, - $this->file, - ['will_be_different'] - ); - - // test with a stale file *and* a resource that *will* be different than the actual - $this->assertFalse($oldResource->isFresh($this->getStaleFileTime()), '->isFresh() returns false if the constructor arguments have changed'); - } - - public function testIsFreshSameConstructorArgs() - { - $oldResource = AutowirePass::createResourceForClass( - new \ReflectionClass(Foo::class) - ); - - // test with a stale file *but* the resource will not be changed - $this->assertTrue($oldResource->isFresh($this->getStaleFileTime()), '->isFresh() returns false if the constructor arguments have changed'); - } - - public function testNotFreshIfClassNotFound() - { - $resource = new AutowireServiceResource( - 'Some\Non\Existent\Class', - $this->file, - [] - ); - - $this->assertFalse($resource->isFresh($this->getStaleFileTime()), '->isFresh() returns false if the class no longer exists'); - } - - protected function tearDown() - { - if (file_exists($this->file)) { - @unlink($this->file); - } - } - - private function getStaleFileTime() - { - return $this->time - 10; - } -} - -class Foo -{ - public function __construct($foo) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Config/ContainerParametersResourceCheckerTest.php b/vendor/symfony/dependency-injection/Tests/Config/ContainerParametersResourceCheckerTest.php deleted file mode 100644 index 51af451c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Config/ContainerParametersResourceCheckerTest.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Config; - -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\ResourceCheckerInterface; -use Symfony\Component\DependencyInjection\Config\ContainerParametersResource; -use Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker; -use Symfony\Component\DependencyInjection\ContainerInterface; - -class ContainerParametersResourceCheckerTest extends TestCase -{ - /** @var ContainerParametersResource */ - private $resource; - - /** @var ResourceCheckerInterface */ - private $resourceChecker; - - /** @var ContainerInterface */ - private $container; - - protected function setUp() - { - $this->resource = new ContainerParametersResource(['locales' => ['fr', 'en'], 'default_locale' => 'fr']); - $this->container = $this->getMockBuilder(ContainerInterface::class)->getMock(); - $this->resourceChecker = new ContainerParametersResourceChecker($this->container); - } - - public function testSupports() - { - $this->assertTrue($this->resourceChecker->supports($this->resource)); - } - - /** - * @dataProvider isFreshProvider - */ - public function testIsFresh(callable $mockContainer, $expected) - { - $mockContainer($this->container); - - $this->assertSame($expected, $this->resourceChecker->isFresh($this->resource, time())); - } - - public function isFreshProvider() - { - yield 'not fresh on missing parameter' => [function (MockObject $container) { - $container->method('hasParameter')->with('locales')->willReturn(false); - }, false]; - - yield 'not fresh on different value' => [function (MockObject $container) { - $container->method('getParameter')->with('locales')->willReturn(['nl', 'es']); - }, false]; - - yield 'fresh on every identical parameters' => [function (MockObject $container) { - $container->expects($this->exactly(2))->method('hasParameter')->willReturn(true); - $container->expects($this->exactly(2))->method('getParameter') - ->withConsecutive( - [$this->equalTo('locales')], - [$this->equalTo('default_locale')] - ) - ->willReturnMap([ - ['locales', ['fr', 'en']], - ['default_locale', 'fr'], - ]) - ; - }, true]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Config/ContainerParametersResourceTest.php b/vendor/symfony/dependency-injection/Tests/Config/ContainerParametersResourceTest.php deleted file mode 100644 index e177ac16..00000000 --- a/vendor/symfony/dependency-injection/Tests/Config/ContainerParametersResourceTest.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Config; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Config\ContainerParametersResource; - -class ContainerParametersResourceTest extends TestCase -{ - /** @var ContainerParametersResource */ - private $resource; - - protected function setUp() - { - $this->resource = new ContainerParametersResource(['locales' => ['fr', 'en'], 'default_locale' => 'fr']); - } - - public function testToString() - { - $this->assertSame('container_parameters_9893d3133814ab03cac3490f36dece77', (string) $this->resource); - } - - public function testSerializeUnserialize() - { - $unserialized = unserialize(serialize($this->resource)); - - $this->assertEquals($this->resource, $unserialized); - } - - public function testGetParameters() - { - $this->assertSame(['locales' => ['fr', 'en'], 'default_locale' => 'fr'], $this->resource->getParameters()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ContainerBuilderTest.php b/vendor/symfony/dependency-injection/Tests/ContainerBuilderTest.php deleted file mode 100644 index fd33ce12..00000000 --- a/vendor/symfony/dependency-injection/Tests/ContainerBuilderTest.php +++ /dev/null @@ -1,1536 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -require_once __DIR__.'/Fixtures/includes/classes.php'; -require_once __DIR__.'/Fixtures/includes/ProjectExtension.php'; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface as PsrContainerInterface; -use Symfony\Component\Config\Resource\ComposerResource; -use Symfony\Component\Config\Resource\DirectoryResource; -use Symfony\Component\Config\Resource\FileResource; -use Symfony\Component\Config\Resource\ResourceInterface; -use Symfony\Component\DependencyInjection\Alias; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\Compiler\PassConfig; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; -use Symfony\Component\DependencyInjection\Loader\ClosureLoader; -use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; -use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory; -use Symfony\Component\DependencyInjection\Tests\Fixtures\SimilarArgumentsDummy; -use Symfony\Component\DependencyInjection\TypedReference; -use Symfony\Component\ExpressionLanguage\Expression; - -class ContainerBuilderTest extends TestCase -{ - public function testDefaultRegisteredDefinitions() - { - $builder = new ContainerBuilder(); - - $this->assertCount(1, $builder->getDefinitions()); - $this->assertTrue($builder->hasDefinition('service_container')); - - $definition = $builder->getDefinition('service_container'); - $this->assertInstanceOf(Definition::class, $definition); - $this->assertTrue($definition->isSynthetic()); - $this->assertSame(ContainerInterface::class, $definition->getClass()); - $this->assertTrue($builder->hasAlias(PsrContainerInterface::class)); - $this->assertTrue($builder->hasAlias(ContainerInterface::class)); - } - - public function testDefinitions() - { - $builder = new ContainerBuilder(); - $definitions = [ - 'foo' => new Definition('Bar\FooClass'), - 'bar' => new Definition('BarClass'), - ]; - $builder->setDefinitions($definitions); - $this->assertEquals($definitions, $builder->getDefinitions(), '->setDefinitions() sets the service definitions'); - $this->assertTrue($builder->hasDefinition('foo'), '->hasDefinition() returns true if a service definition exists'); - $this->assertFalse($builder->hasDefinition('foobar'), '->hasDefinition() returns false if a service definition does not exist'); - - $builder->setDefinition('foobar', $foo = new Definition('FooBarClass')); - $this->assertEquals($foo, $builder->getDefinition('foobar'), '->getDefinition() returns a service definition if defined'); - $this->assertSame($builder->setDefinition('foobar', $foo = new Definition('FooBarClass')), $foo, '->setDefinition() implements a fluid interface by returning the service reference'); - - $builder->addDefinitions($defs = ['foobar' => new Definition('FooBarClass')]); - $this->assertEquals(array_merge($definitions, $defs), $builder->getDefinitions(), '->addDefinitions() adds the service definitions'); - - try { - $builder->getDefinition('baz'); - $this->fail('->getDefinition() throws a ServiceNotFoundException if the service definition does not exist'); - } catch (ServiceNotFoundException $e) { - $this->assertEquals('You have requested a non-existent service "baz".', $e->getMessage(), '->getDefinition() throws a ServiceNotFoundException if the service definition does not exist'); - } - } - - /** - * @group legacy - * @expectedDeprecation The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed. - */ - public function testCreateDeprecatedService() - { - $definition = new Definition('stdClass'); - $definition->setDeprecated(true); - - $builder = new ContainerBuilder(); - $builder->setDefinition('deprecated_foo', $definition); - $builder->get('deprecated_foo'); - } - - public function testRegister() - { - $builder = new ContainerBuilder(); - $builder->register('foo', 'Bar\FooClass'); - $this->assertTrue($builder->hasDefinition('foo'), '->register() registers a new service definition'); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $builder->getDefinition('foo'), '->register() returns the newly created Definition instance'); - } - - public function testAutowire() - { - $builder = new ContainerBuilder(); - $builder->autowire('foo', 'Bar\FooClass'); - - $this->assertTrue($builder->hasDefinition('foo'), '->autowire() registers a new service definition'); - $this->assertTrue($builder->getDefinition('foo')->isAutowired(), '->autowire() creates autowired definitions'); - } - - public function testHas() - { - $builder = new ContainerBuilder(); - $this->assertFalse($builder->has('foo'), '->has() returns false if the service does not exist'); - $builder->register('foo', 'Bar\FooClass'); - $this->assertTrue($builder->has('foo'), '->has() returns true if a service definition exists'); - $builder->set('bar', new \stdClass()); - $this->assertTrue($builder->has('bar'), '->has() returns true if a service exists'); - } - - public function testGetThrowsExceptionIfServiceDoesNotExist() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException'); - $this->expectExceptionMessage('You have requested a non-existent service "foo".'); - $builder = new ContainerBuilder(); - $builder->get('foo'); - } - - public function testGetReturnsNullIfServiceDoesNotExistAndInvalidReferenceIsUsed() - { - $builder = new ContainerBuilder(); - - $this->assertNull($builder->get('foo', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service does not exist and NULL_ON_INVALID_REFERENCE is passed as a second argument'); - } - - public function testGetThrowsCircularReferenceExceptionIfServiceHasReferenceToItself() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $builder = new ContainerBuilder(); - $builder->register('baz', 'stdClass')->setArguments([new Reference('baz')]); - $builder->get('baz'); - } - - public function testGetReturnsSameInstanceWhenServiceIsShared() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass'); - - $this->assertTrue($builder->get('bar') === $builder->get('bar'), '->get() always returns the same instance if the service is shared'); - } - - public function testGetCreatesServiceBasedOnDefinition() - { - $builder = new ContainerBuilder(); - $builder->register('foo', 'stdClass'); - - $this->assertIsObject($builder->get('foo'), '->get() returns the service definition associated with the id'); - } - - public function testGetReturnsRegisteredService() - { - $builder = new ContainerBuilder(); - $builder->set('bar', $bar = new \stdClass()); - - $this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id'); - } - - public function testRegisterDoesNotOverrideExistingService() - { - $builder = new ContainerBuilder(); - $builder->set('bar', $bar = new \stdClass()); - $builder->register('bar', 'stdClass'); - - $this->assertSame($bar, $builder->get('bar'), '->get() returns the service associated with the id even if a definition has been defined'); - } - - public function testNonSharedServicesReturnsDifferentInstances() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass')->setShared(false); - - $this->assertNotSame($builder->get('bar'), $builder->get('bar')); - } - - /** - * @dataProvider provideBadId - */ - public function testBadAliasId($id) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $builder = new ContainerBuilder(); - $builder->setAlias($id, 'foo'); - } - - /** - * @dataProvider provideBadId - */ - public function testBadDefinitionId($id) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $builder = new ContainerBuilder(); - $builder->setDefinition($id, new Definition('Foo')); - } - - public function provideBadId() - { - return [ - [''], - ["\0"], - ["\r"], - ["\n"], - ["'"], - ['ab\\'], - ]; - } - - public function testGetUnsetLoadingServiceWhenCreateServiceThrowsAnException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('You have requested a synthetic service ("foo"). The DIC does not know how to construct this service.'); - $builder = new ContainerBuilder(); - $builder->register('foo', 'stdClass')->setSynthetic(true); - - // we expect a RuntimeException here as foo is synthetic - try { - $builder->get('foo'); - } catch (RuntimeException $e) { - } - - // we must also have the same RuntimeException here - $builder->get('foo'); - } - - public function testGetServiceIds() - { - $builder = new ContainerBuilder(); - $builder->register('foo', 'stdClass'); - $builder->bar = $bar = new \stdClass(); - $builder->register('bar', 'stdClass'); - $this->assertEquals( - [ - 'service_container', - 'foo', - 'bar', - 'Psr\Container\ContainerInterface', - 'Symfony\Component\DependencyInjection\ContainerInterface', - ], - $builder->getServiceIds(), - '->getServiceIds() returns all defined service ids' - ); - } - - public function testAliases() - { - $builder = new ContainerBuilder(); - $builder->register('foo', 'stdClass'); - $builder->setAlias('bar', 'foo'); - $this->assertTrue($builder->hasAlias('bar'), '->hasAlias() returns true if the alias exists'); - $this->assertFalse($builder->hasAlias('foobar'), '->hasAlias() returns false if the alias does not exist'); - $this->assertEquals('foo', (string) $builder->getAlias('bar'), '->getAlias() returns the aliased service'); - $this->assertTrue($builder->has('bar'), '->setAlias() defines a new service'); - $this->assertSame($builder->get('bar'), $builder->get('foo'), '->setAlias() creates a service that is an alias to another one'); - - try { - $builder->setAlias('foobar', 'foobar'); - $this->fail('->setAlias() throws an InvalidArgumentException if the alias references itself'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('An alias can not reference itself, got a circular reference on "foobar".', $e->getMessage(), '->setAlias() throws an InvalidArgumentException if the alias references itself'); - } - - try { - $builder->getAlias('foobar'); - $this->fail('->getAlias() throws an InvalidArgumentException if the alias does not exist'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('The service alias "foobar" does not exist.', $e->getMessage(), '->getAlias() throws an InvalidArgumentException if the alias does not exist'); - } - } - - public function testGetAliases() - { - $builder = new ContainerBuilder(); - $builder->setAlias('bar', 'foo'); - $builder->setAlias('foobar', 'foo'); - $builder->setAlias('moo', new Alias('foo', false)); - - $aliases = $builder->getAliases(); - $this->assertEquals('foo', (string) $aliases['bar']); - $this->assertTrue($aliases['bar']->isPublic()); - $this->assertEquals('foo', (string) $aliases['foobar']); - $this->assertEquals('foo', (string) $aliases['moo']); - $this->assertFalse($aliases['moo']->isPublic()); - - $builder->register('bar', 'stdClass'); - $this->assertFalse($builder->hasAlias('bar')); - - $builder->set('foobar', 'stdClass'); - $builder->set('moo', 'stdClass'); - $this->assertCount(2, $builder->getAliases(), '->getAliases() does not return aliased services that have been overridden'); - } - - public function testSetAliases() - { - $builder = new ContainerBuilder(); - $builder->setAliases(['bar' => 'foo', 'foobar' => 'foo']); - - $aliases = $builder->getAliases(); - $this->assertArrayHasKey('bar', $aliases); - $this->assertArrayHasKey('foobar', $aliases); - } - - public function testAddAliases() - { - $builder = new ContainerBuilder(); - $builder->setAliases(['bar' => 'foo']); - $builder->addAliases(['foobar' => 'foo']); - - $aliases = $builder->getAliases(); - $this->assertArrayHasKey('bar', $aliases); - $this->assertArrayHasKey('foobar', $aliases); - } - - public function testSetReplacesAlias() - { - $builder = new ContainerBuilder(); - $builder->setAlias('alias', 'aliased'); - $builder->set('aliased', new \stdClass()); - - $builder->set('alias', $foo = new \stdClass()); - $this->assertSame($foo, $builder->get('alias'), '->set() replaces an existing alias'); - } - - public function testAliasesKeepInvalidBehavior() - { - $builder = new ContainerBuilder(); - - $aliased = new Definition('stdClass'); - $aliased->addMethodCall('setBar', [new Reference('bar', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]); - $builder->setDefinition('aliased', $aliased); - $builder->setAlias('alias', 'aliased'); - - $this->assertEquals(new \stdClass(), $builder->get('alias')); - } - - public function testAddGetCompilerPass() - { - $builder = new ContainerBuilder(); - $builder->setResourceTracking(false); - $defaultPasses = $builder->getCompiler()->getPassConfig()->getPasses(); - $builder->addCompilerPass($pass1 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -5); - $builder->addCompilerPass($pass2 = $this->getMockBuilder('Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface')->getMock(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10); - - $passes = $builder->getCompiler()->getPassConfig()->getPasses(); - $this->assertCount(\count($passes) - 2, $defaultPasses); - // Pass 1 is executed later - $this->assertTrue(array_search($pass1, $passes, true) > array_search($pass2, $passes, true)); - } - - public function testCreateService() - { - $builder = new ContainerBuilder(); - $builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php'); - $builder->register('foo2', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/%file%.php'); - $builder->setParameter('file', 'foo'); - $this->assertInstanceOf('\Bar\FooClass', $builder->get('foo1'), '->createService() requires the file defined by the service definition'); - $this->assertInstanceOf('\Bar\FooClass', $builder->get('foo2'), '->createService() replaces parameters in the file provided by the service definition'); - } - - public function testCreateProxyWithRealServiceInstantiator() - { - $builder = new ContainerBuilder(); - - $builder->register('foo1', 'Bar\FooClass')->setFile(__DIR__.'/Fixtures/includes/foo.php'); - $builder->getDefinition('foo1')->setLazy(true); - - $foo1 = $builder->get('foo1'); - - $this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls'); - $this->assertSame('Bar\FooClass', \get_class($foo1)); - } - - public function testCreateServiceClass() - { - $builder = new ContainerBuilder(); - $builder->register('foo1', '%class%'); - $builder->setParameter('class', 'stdClass'); - $this->assertInstanceOf('\stdClass', $builder->get('foo1'), '->createService() replaces parameters in the class provided by the service definition'); - } - - public function testCreateServiceArguments() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass'); - $builder->register('foo1', 'Bar\FooClass')->addArgument(['foo' => '%value%', '%value%' => 'foo', new Reference('bar'), '%%unescape_it%%']); - $builder->setParameter('value', 'bar'); - $this->assertEquals(['foo' => 'bar', 'bar' => 'foo', $builder->get('bar'), '%unescape_it%'], $builder->get('foo1')->arguments, '->createService() replaces parameters and service references in the arguments provided by the service definition'); - } - - public function testCreateServiceFactory() - { - $builder = new ContainerBuilder(); - $builder->register('foo', 'Bar\FooClass')->setFactory('Bar\FooClass::getInstance'); - $builder->register('qux', 'Bar\FooClass')->setFactory(['Bar\FooClass', 'getInstance']); - $builder->register('bar', 'Bar\FooClass')->setFactory([new Definition('Bar\FooClass'), 'getInstance']); - $builder->register('baz', 'Bar\FooClass')->setFactory([new Reference('bar'), 'getInstance']); - - $this->assertTrue($builder->get('foo')->called, '->createService() calls the factory method to create the service instance'); - $this->assertTrue($builder->get('qux')->called, '->createService() calls the factory method to create the service instance'); - $this->assertTrue($builder->get('bar')->called, '->createService() uses anonymous service as factory'); - $this->assertTrue($builder->get('baz')->called, '->createService() uses another service as factory'); - } - - public function testCreateServiceMethodCalls() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass'); - $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', [['%value%', new Reference('bar')]]); - $builder->setParameter('value', 'bar'); - $this->assertEquals(['bar', $builder->get('bar')], $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments'); - } - - public function testCreateServiceMethodCallsWithEscapedParam() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass'); - $builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', [['%%unescape_it%%']]); - $builder->setParameter('value', 'bar'); - $this->assertEquals(['%unescape_it%'], $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments'); - } - - public function testCreateServiceProperties() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass'); - $builder->register('foo1', 'Bar\FooClass')->setProperty('bar', ['%value%', new Reference('bar'), '%%unescape_it%%']); - $builder->setParameter('value', 'bar'); - $this->assertEquals(['bar', $builder->get('bar'), '%unescape_it%'], $builder->get('foo1')->bar, '->createService() replaces the values in the properties'); - } - - public function testCreateServiceConfigurator() - { - $builder = new ContainerBuilder(); - $builder->register('foo1', 'Bar\FooClass')->setConfigurator('sc_configure'); - $builder->register('foo2', 'Bar\FooClass')->setConfigurator(['%class%', 'configureStatic']); - $builder->setParameter('class', 'BazClass'); - $builder->register('baz', 'BazClass'); - $builder->register('foo3', 'Bar\FooClass')->setConfigurator([new Reference('baz'), 'configure']); - $builder->register('foo4', 'Bar\FooClass')->setConfigurator([$builder->getDefinition('baz'), 'configure']); - $builder->register('foo5', 'Bar\FooClass')->setConfigurator('foo'); - - $this->assertTrue($builder->get('foo1')->configured, '->createService() calls the configurator'); - $this->assertTrue($builder->get('foo2')->configured, '->createService() calls the configurator'); - $this->assertTrue($builder->get('foo3')->configured, '->createService() calls the configurator'); - $this->assertTrue($builder->get('foo4')->configured, '->createService() calls the configurator'); - - try { - $builder->get('foo5'); - $this->fail('->createService() throws an InvalidArgumentException if the configure callable is not a valid callable'); - } catch (\InvalidArgumentException $e) { - $this->assertEquals('The configure callable for class "Bar\FooClass" is not a callable.', $e->getMessage(), '->createService() throws an InvalidArgumentException if the configure callable is not a valid callable'); - } - } - - public function testCreateServiceWithIteratorArgument() - { - $builder = new ContainerBuilder(); - $builder->register('bar', 'stdClass'); - $builder - ->register('lazy_context', 'LazyContext') - ->setArguments([ - new IteratorArgument(['k1' => new Reference('bar'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]), - new IteratorArgument([]), - ]) - ; - - $lazyContext = $builder->get('lazy_context'); - $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyValues); - $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyEmptyValues); - $this->assertCount(1, $lazyContext->lazyValues); - $this->assertCount(0, $lazyContext->lazyEmptyValues); - - $i = 0; - foreach ($lazyContext->lazyValues as $k => $v) { - ++$i; - $this->assertEquals('k1', $k); - $this->assertInstanceOf('\stdClass', $v); - } - - // The second argument should have been ignored. - $this->assertEquals(1, $i); - - $i = 0; - foreach ($lazyContext->lazyEmptyValues as $k => $v) { - ++$i; - } - - $this->assertEquals(0, $i); - } - - public function testCreateSyntheticService() - { - $this->expectException('RuntimeException'); - $builder = new ContainerBuilder(); - $builder->register('foo', 'Bar\FooClass')->setSynthetic(true); - $builder->get('foo'); - } - - public function testCreateServiceWithExpression() - { - $builder = new ContainerBuilder(); - $builder->setParameter('bar', 'bar'); - $builder->register('bar', 'BarClass'); - $builder->register('foo', 'Bar\FooClass')->addArgument(['foo' => new Expression('service("bar").foo ~ parameter("bar")')]); - $this->assertEquals('foobar', $builder->get('foo')->arguments['foo']); - } - - public function testResolveServices() - { - $builder = new ContainerBuilder(); - $builder->register('foo', 'Bar\FooClass'); - $this->assertEquals($builder->get('foo'), $builder->resolveServices(new Reference('foo')), '->resolveServices() resolves service references to service instances'); - $this->assertEquals(['foo' => ['foo', $builder->get('foo')]], $builder->resolveServices(['foo' => ['foo', new Reference('foo')]]), '->resolveServices() resolves service references to service instances in nested arrays'); - $this->assertEquals($builder->get('foo'), $builder->resolveServices(new Expression('service("foo")')), '->resolveServices() resolves expressions'); - } - - public function testResolveServicesWithDecoratedDefinition() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Constructing service "foo" from a parent definition is not supported at build time.'); - $builder = new ContainerBuilder(); - $builder->setDefinition('grandpa', new Definition('stdClass')); - $builder->setDefinition('parent', new ChildDefinition('grandpa')); - $builder->setDefinition('foo', new ChildDefinition('parent')); - - $builder->get('foo'); - } - - public function testResolveServicesWithCustomDefinitionClass() - { - $builder = new ContainerBuilder(); - $builder->setDefinition('foo', new CustomDefinition('stdClass')); - - $this->assertInstanceOf('stdClass', $builder->get('foo')); - } - - public function testMerge() - { - $container = new ContainerBuilder(new ParameterBag(['bar' => 'foo'])); - $container->setResourceTracking(false); - $config = new ContainerBuilder(new ParameterBag(['foo' => 'bar'])); - $container->merge($config); - $this->assertEquals(['bar' => 'foo', 'foo' => 'bar'], $container->getParameterBag()->all(), '->merge() merges current parameters with the loaded ones'); - - $container = new ContainerBuilder(new ParameterBag(['bar' => 'foo'])); - $container->setResourceTracking(false); - $config = new ContainerBuilder(new ParameterBag(['foo' => '%bar%'])); - $container->merge($config); - $container->compile(); - $this->assertEquals(['bar' => 'foo', 'foo' => 'foo'], $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones'); - - $container = new ContainerBuilder(new ParameterBag(['bar' => 'foo'])); - $container->setResourceTracking(false); - $config = new ContainerBuilder(new ParameterBag(['foo' => '%bar%', 'baz' => '%foo%'])); - $container->merge($config); - $container->compile(); - $this->assertEquals(['bar' => 'foo', 'foo' => 'foo', 'baz' => 'foo'], $container->getParameterBag()->all(), '->merge() evaluates the values of the parameters towards already defined ones'); - - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->register('foo', 'Bar\FooClass'); - $container->register('bar', 'BarClass'); - $config = new ContainerBuilder(); - $config->setDefinition('baz', new Definition('BazClass')); - $config->setAlias('alias_for_foo', 'foo'); - $container->merge($config); - $this->assertEquals(['service_container', 'foo', 'bar', 'baz'], array_keys($container->getDefinitions()), '->merge() merges definitions already defined ones'); - - $aliases = $container->getAliases(); - $this->assertArrayHasKey('alias_for_foo', $aliases); - $this->assertEquals('foo', (string) $aliases['alias_for_foo']); - - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->register('foo', 'Bar\FooClass'); - $config->setDefinition('foo', new Definition('BazClass')); - $container->merge($config); - $this->assertEquals('BazClass', $container->getDefinition('foo')->getClass(), '->merge() overrides already defined services'); - - $container = new ContainerBuilder(); - $bag = new EnvPlaceholderParameterBag(); - $bag->get('env(Foo)'); - $config = new ContainerBuilder($bag); - $this->assertSame(['%env(Bar)%'], $config->resolveEnvPlaceholders([$bag->get('env(Bar)')])); - $container->merge($config); - $this->assertEquals(['Foo' => 0, 'Bar' => 1], $container->getEnvCounters()); - - $container = new ContainerBuilder(); - $config = new ContainerBuilder(); - $childDefA = $container->registerForAutoconfiguration('AInterface'); - $childDefB = $config->registerForAutoconfiguration('BInterface'); - $container->merge($config); - $this->assertSame(['AInterface' => $childDefA, 'BInterface' => $childDefB], $container->getAutoconfiguredInstanceof()); - } - - public function testMergeThrowsExceptionForDuplicateAutomaticInstanceofDefinitions() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('"AInterface" has already been autoconfigured and merge() does not support merging autoconfiguration for the same class/interface.'); - $container = new ContainerBuilder(); - $config = new ContainerBuilder(); - $container->registerForAutoconfiguration('AInterface'); - $config->registerForAutoconfiguration('AInterface'); - $container->merge($config); - } - - public function testResolveEnvValues() - { - $_ENV['DUMMY_ENV_VAR'] = 'du%%y'; - $_SERVER['DUMMY_SERVER_VAR'] = 'ABC'; - $_SERVER['HTTP_DUMMY_VAR'] = 'DEF'; - - $container = new ContainerBuilder(); - $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%'); - $container->setParameter('env(HTTP_DUMMY_VAR)', '123'); - - $this->assertSame('%% du%%%%y ABC 123', $container->resolveEnvPlaceholders('%bar%', true)); - - unset($_ENV['DUMMY_ENV_VAR'], $_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']); - } - - public function testResolveEnvValuesWithArray() - { - $_ENV['ANOTHER_DUMMY_ENV_VAR'] = 'dummy'; - - $dummyArray = ['1' => 'one', '2' => 'two']; - - $container = new ContainerBuilder(); - $container->setParameter('dummy', '%env(ANOTHER_DUMMY_ENV_VAR)%'); - $container->setParameter('dummy2', $dummyArray); - - $container->resolveEnvPlaceholders('%dummy%', true); - $container->resolveEnvPlaceholders('%dummy2%', true); - - $this->assertIsArray($container->resolveEnvPlaceholders('%dummy2%', true)); - - foreach ($dummyArray as $key => $value) { - $this->assertArrayHasKey($key, $container->resolveEnvPlaceholders('%dummy2%', true)); - } - - unset($_ENV['ANOTHER_DUMMY_ENV_VAR']); - } - - public function testCompileWithResolveEnv() - { - putenv('DUMMY_ENV_VAR=du%%y'); - $_SERVER['DUMMY_SERVER_VAR'] = 'ABC'; - $_SERVER['HTTP_DUMMY_VAR'] = 'DEF'; - - $container = new ContainerBuilder(); - $container->setParameter('env(FOO)', 'Foo'); - $container->setParameter('env(DUMMY_ENV_VAR)', 'GHI'); - $container->setParameter('bar', '%% %env(DUMMY_ENV_VAR)% %env(DUMMY_SERVER_VAR)% %env(HTTP_DUMMY_VAR)%'); - $container->setParameter('foo', '%env(FOO)%'); - $container->setParameter('baz', '%foo%'); - $container->setParameter('env(HTTP_DUMMY_VAR)', '123'); - $container->register('teatime', 'stdClass') - ->setProperty('foo', '%env(DUMMY_ENV_VAR)%') - ->setPublic(true) - ; - $container->compile(true); - - $this->assertSame('% du%%y ABC 123', $container->getParameter('bar')); - $this->assertSame('Foo', $container->getParameter('baz')); - $this->assertSame('du%%y', $container->get('teatime')->foo); - - unset($_SERVER['DUMMY_SERVER_VAR'], $_SERVER['HTTP_DUMMY_VAR']); - putenv('DUMMY_ENV_VAR'); - } - - public function testCompileWithArrayResolveEnv() - { - putenv('ARRAY={"foo":"bar"}'); - - $container = new ContainerBuilder(); - $container->setParameter('foo', '%env(json:ARRAY)%'); - $container->compile(true); - - $this->assertSame(['foo' => 'bar'], $container->getParameter('foo')); - - putenv('ARRAY'); - } - - public function testCompileWithArrayAndAnotherResolveEnv() - { - putenv('DUMMY_ENV_VAR=abc'); - putenv('ARRAY={"foo":"bar"}'); - - $container = new ContainerBuilder(); - $container->setParameter('foo', '%env(json:ARRAY)%'); - $container->setParameter('bar', '%env(DUMMY_ENV_VAR)%'); - $container->compile(true); - - $this->assertSame(['foo' => 'bar'], $container->getParameter('foo')); - $this->assertSame('abc', $container->getParameter('bar')); - - putenv('DUMMY_ENV_VAR'); - putenv('ARRAY'); - } - - public function testCompileWithArrayInStringResolveEnv() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('A string value must be composed of strings and/or numbers, but found parameter "env(json:ARRAY)" of type "array" inside string value "ABC %env(json:ARRAY)%".'); - putenv('ARRAY={"foo":"bar"}'); - - $container = new ContainerBuilder(); - $container->setParameter('foo', 'ABC %env(json:ARRAY)%'); - $container->compile(true); - - putenv('ARRAY'); - } - - public function testCompileWithResolveMissingEnv() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\EnvNotFoundException'); - $this->expectExceptionMessage('Environment variable not found: "FOO".'); - $container = new ContainerBuilder(); - $container->setParameter('foo', '%env(FOO)%'); - $container->compile(true); - } - - public function testDynamicEnv() - { - putenv('DUMMY_FOO=some%foo%'); - putenv('DUMMY_BAR=%bar%'); - - $container = new ContainerBuilder(); - $container->setParameter('foo', 'Foo%env(resolve:DUMMY_BAR)%'); - $container->setParameter('bar', 'Bar'); - $container->setParameter('baz', '%env(resolve:DUMMY_FOO)%'); - - $container->compile(true); - putenv('DUMMY_FOO'); - putenv('DUMMY_BAR'); - - $this->assertSame('someFooBar', $container->getParameter('baz')); - } - - public function testCastEnv() - { - $container = new ContainerBuilder(); - $container->setParameter('env(FAKE)', '123'); - - $container->register('foo', 'stdClass') - ->setPublic(true) - ->setProperties([ - 'fake' => '%env(int:FAKE)%', - ]); - - $container->compile(true); - - $this->assertSame(123, $container->get('foo')->fake); - } - - public function testEnvAreNullable() - { - $container = new ContainerBuilder(); - $container->setParameter('env(FAKE)', null); - - $container->register('foo', 'stdClass') - ->setPublic(true) - ->setProperties([ - 'fake' => '%env(int:FAKE)%', - ]); - - $container->compile(true); - - $this->assertNull($container->get('foo')->fake); - } - - public function testEnvInId() - { - $container = include __DIR__.'/Fixtures/containers/container_env_in_id.php'; - $container->compile(true); - - $expected = [ - 'service_container', - 'foo', - 'bar', - 'bar_%env(BAR)%', - ]; - $this->assertSame($expected, array_keys($container->getDefinitions())); - - $expected = [ - PsrContainerInterface::class => true, - ContainerInterface::class => true, - 'baz_%env(BAR)%' => true, - 'bar_%env(BAR)%' => true, - ]; - $this->assertSame($expected, $container->getRemovedIds()); - - $this->assertSame(['baz_bar'], array_keys($container->getDefinition('foo')->getArgument(1))); - } - - public function testCircularDynamicEnv() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException'); - $this->expectExceptionMessage('Circular reference detected for parameter "env(resolve:DUMMY_ENV_VAR)" ("env(resolve:DUMMY_ENV_VAR)" > "env(resolve:DUMMY_ENV_VAR)").'); - putenv('DUMMY_ENV_VAR=some%foo%'); - - $container = new ContainerBuilder(); - $container->setParameter('foo', '%bar%'); - $container->setParameter('bar', '%env(resolve:DUMMY_ENV_VAR)%'); - - try { - $container->compile(true); - } finally { - putenv('DUMMY_ENV_VAR'); - } - } - - public function testMergeLogicException() - { - $this->expectException('LogicException'); - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->compile(); - $container->merge(new ContainerBuilder()); - } - - public function testfindTaggedServiceIds() - { - $builder = new ContainerBuilder(); - $builder - ->register('foo', 'Bar\FooClass') - ->addTag('foo', ['foo' => 'foo']) - ->addTag('bar', ['bar' => 'bar']) - ->addTag('foo', ['foofoo' => 'foofoo']) - ; - $this->assertEquals([ - 'foo' => [ - ['foo' => 'foo'], - ['foofoo' => 'foofoo'], - ], - ], $builder->findTaggedServiceIds('foo'), '->findTaggedServiceIds() returns an array of service ids and its tag attributes'); - $this->assertEquals([], $builder->findTaggedServiceIds('foobar'), '->findTaggedServiceIds() returns an empty array if there is annotated services'); - } - - public function testFindUnusedTags() - { - $builder = new ContainerBuilder(); - $builder - ->register('foo', 'Bar\FooClass') - ->addTag('kernel.event_listener', ['foo' => 'foo']) - ->addTag('kenrel.event_listener', ['bar' => 'bar']) - ; - $builder->findTaggedServiceIds('kernel.event_listener'); - $this->assertEquals(['kenrel.event_listener'], $builder->findUnusedTags(), '->findUnusedTags() returns an array with unused tags'); - } - - public function testFindDefinition() - { - $container = new ContainerBuilder(); - $container->setDefinition('foo', $definition = new Definition('Bar\FooClass')); - $container->setAlias('bar', 'foo'); - $container->setAlias('foobar', 'bar'); - $this->assertEquals($definition, $container->findDefinition('foobar'), '->findDefinition() returns a Definition'); - } - - public function testAddObjectResource() - { - $container = new ContainerBuilder(); - - $container->setResourceTracking(false); - $container->addObjectResource(new \BarClass()); - - $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking'); - - $container->setResourceTracking(true); - $container->addObjectResource(new \BarClass()); - - $resources = $container->getResources(); - - $this->assertCount(2, $resources, '2 resources were registered'); - - /* @var $resource \Symfony\Component\Config\Resource\FileResource */ - $resource = end($resources); - - $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource); - $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource())); - } - - /** - * @group legacy - */ - public function testAddClassResource() - { - $container = new ContainerBuilder(); - - $container->setResourceTracking(false); - $container->addClassResource(new \ReflectionClass('BarClass')); - - $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking'); - - $container->setResourceTracking(true); - $container->addClassResource(new \ReflectionClass('BarClass')); - - $resources = $container->getResources(); - - $this->assertCount(2, $resources, '2 resources were registered'); - - /* @var $resource \Symfony\Component\Config\Resource\FileResource */ - $resource = end($resources); - - $this->assertInstanceOf('Symfony\Component\Config\Resource\FileResource', $resource); - $this->assertSame(realpath(__DIR__.'/Fixtures/includes/classes.php'), realpath($resource->getResource())); - } - - public function testGetReflectionClass() - { - $container = new ContainerBuilder(); - - $container->setResourceTracking(false); - $r1 = $container->getReflectionClass('BarClass'); - - $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking'); - - $container->setResourceTracking(true); - $r2 = $container->getReflectionClass('BarClass'); - $r3 = $container->getReflectionClass('BarClass'); - - $this->assertNull($container->getReflectionClass('BarMissingClass')); - - $this->assertEquals($r1, $r2); - $this->assertSame($r2, $r3); - - $resources = $container->getResources(); - - $this->assertCount(3, $resources, '3 resources were registered'); - - $this->assertSame('reflection.BarClass', (string) $resources[1]); - $this->assertSame('BarMissingClass', (string) end($resources)); - } - - public function testGetReflectionClassOnInternalTypes() - { - $container = new ContainerBuilder(); - - $this->assertNull($container->getReflectionClass('int')); - $this->assertNull($container->getReflectionClass('float')); - $this->assertNull($container->getReflectionClass('string')); - $this->assertNull($container->getReflectionClass('bool')); - $this->assertNull($container->getReflectionClass('resource')); - $this->assertNull($container->getReflectionClass('object')); - $this->assertNull($container->getReflectionClass('array')); - $this->assertNull($container->getReflectionClass('null')); - $this->assertNull($container->getReflectionClass('callable')); - $this->assertNull($container->getReflectionClass('iterable')); - $this->assertNull($container->getReflectionClass('mixed')); - } - - public function testCompilesClassDefinitionsOfLazyServices() - { - $container = new ContainerBuilder(); - - $this->assertEmpty($container->getResources(), 'No resources get registered without resource tracking'); - - $container->register('foo', 'BarClass')->setPublic(true); - $container->getDefinition('foo')->setLazy(true); - - $container->compile(); - - $matchingResources = array_filter( - $container->getResources(), - function (ResourceInterface $resource) { - return 'reflection.BarClass' === (string) $resource; - } - ); - - $this->assertNotEmpty($matchingResources); - } - - public function testResources() - { - $container = new ContainerBuilder(); - $container->addResource($a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml')); - $container->addResource($b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml')); - $resources = []; - foreach ($container->getResources() as $resource) { - if (false === strpos($resource, '.php')) { - $resources[] = $resource; - } - } - $this->assertEquals([$a, $b], $resources, '->getResources() returns an array of resources read for the current configuration'); - $this->assertSame($container, $container->setResources([])); - $this->assertEquals([], $container->getResources()); - } - - public function testFileExists() - { - $container = new ContainerBuilder(); - $A = new ComposerResource(); - $a = new FileResource(__DIR__.'/Fixtures/xml/services1.xml'); - $b = new FileResource(__DIR__.'/Fixtures/xml/services2.xml'); - $c = new DirectoryResource($dir = \dirname($b)); - - $this->assertTrue($container->fileExists((string) $a) && $container->fileExists((string) $b) && $container->fileExists($dir)); - - $resources = []; - foreach ($container->getResources() as $resource) { - if (false === strpos($resource, '.php')) { - $resources[] = $resource; - } - } - - $this->assertEquals([$A, $a, $b, $c], $resources, '->getResources() returns an array of resources read for the current configuration'); - } - - public function testExtension() - { - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - - $container->registerExtension($extension = new \ProjectExtension()); - $this->assertSame($container->getExtension('project'), $extension, '->registerExtension() registers an extension'); - - $this->expectException('LogicException'); - $container->getExtension('no_registered'); - } - - public function testRegisteredButNotLoadedExtension() - { - $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock(); - $extension->expects($this->once())->method('getAlias')->willReturn('project'); - $extension->expects($this->never())->method('load'); - - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->registerExtension($extension); - $container->compile(); - } - - public function testRegisteredAndLoadedExtension() - { - $extension = $this->getMockBuilder('Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface')->getMock(); - $extension->expects($this->exactly(2))->method('getAlias')->willReturn('project'); - $extension->expects($this->once())->method('load')->with([['foo' => 'bar']]); - - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->registerExtension($extension); - $container->loadFromExtension('project', ['foo' => 'bar']); - $container->compile(); - } - - public function testPrivateServiceUser() - { - $fooDefinition = new Definition('BarClass'); - $fooUserDefinition = new Definition('BarUserClass', [new Reference('bar')]); - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - - $fooDefinition->setPublic(false); - - $container->addDefinitions([ - 'bar' => $fooDefinition, - 'bar_user' => $fooUserDefinition->setPublic(true), - ]); - - $container->compile(); - $this->assertInstanceOf('BarClass', $container->get('bar_user')->bar); - } - - public function testThrowsExceptionWhenSetServiceOnACompiledContainer() - { - $this->expectException('BadMethodCallException'); - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->register('a', 'stdClass')->setPublic(true); - $container->compile(); - $container->set('a', new \stdClass()); - } - - public function testNoExceptionWhenAddServiceOnACompiledContainer() - { - $container = new ContainerBuilder(); - $container->compile(); - $container->set('a', $foo = new \stdClass()); - $this->assertSame($foo, $container->get('a')); - } - - public function testNoExceptionWhenSetSyntheticServiceOnACompiledContainer() - { - $container = new ContainerBuilder(); - $def = new Definition('stdClass'); - $def->setSynthetic(true)->setPublic(true); - $container->setDefinition('a', $def); - $container->compile(); - $container->set('a', $a = new \stdClass()); - $this->assertEquals($a, $container->get('a')); - } - - public function testThrowsExceptionWhenSetDefinitionOnACompiledContainer() - { - $this->expectException('BadMethodCallException'); - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->compile(); - $container->setDefinition('a', new Definition()); - } - - public function testExtensionConfig() - { - $container = new ContainerBuilder(); - - $configs = $container->getExtensionConfig('foo'); - $this->assertEmpty($configs); - - $first = ['foo' => 'bar']; - $container->prependExtensionConfig('foo', $first); - $configs = $container->getExtensionConfig('foo'); - $this->assertEquals([$first], $configs); - - $second = ['ding' => 'dong']; - $container->prependExtensionConfig('foo', $second); - $configs = $container->getExtensionConfig('foo'); - $this->assertEquals([$second, $first], $configs); - } - - public function testAbstractAlias() - { - $container = new ContainerBuilder(); - - $abstract = new Definition('AbstractClass'); - $abstract->setAbstract(true)->setPublic(true); - - $container->setDefinition('abstract_service', $abstract); - $container->setAlias('abstract_alias', 'abstract_service')->setPublic(true); - - $container->compile(); - - $this->assertSame('abstract_service', (string) $container->getAlias('abstract_alias')); - } - - public function testLazyLoadedService() - { - $loader = new ClosureLoader($container = new ContainerBuilder()); - $loader->load(function (ContainerBuilder $container) { - $container->set('a', new \BazClass()); - $definition = new Definition('BazClass'); - $definition->setLazy(true); - $definition->setPublic(true); - $container->setDefinition('a', $definition); - }); - - $container->setResourceTracking(true); - - $container->compile(); - - $r = new \ReflectionProperty($container, 'resources'); - $r->setAccessible(true); - $resources = $r->getValue($container); - - $classInList = false; - foreach ($resources as $resource) { - if ('reflection.BazClass' === (string) $resource) { - $classInList = true; - break; - } - } - - $this->assertTrue($classInList); - } - - public function testInlinedDefinitions() - { - $container = new ContainerBuilder(); - - $definition = new Definition('BarClass'); - - $container->register('bar_user', 'BarUserClass') - ->addArgument($definition) - ->setProperty('foo', $definition); - - $container->register('bar', 'BarClass') - ->setProperty('foo', $definition) - ->addMethodCall('setBaz', [$definition]); - - $barUser = $container->get('bar_user'); - $bar = $container->get('bar'); - - $this->assertSame($barUser->foo, $barUser->bar); - $this->assertSame($bar->foo, $bar->getBaz()); - $this->assertNotSame($bar->foo, $barUser->foo); - } - - public function testThrowsCircularExceptionForCircularAliases() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $this->expectExceptionMessage('Circular reference detected for service "app.test_class", path: "app.test_class -> App\TestClass -> app.test_class".'); - $builder = new ContainerBuilder(); - - $builder->setAliases([ - 'foo' => new Alias('app.test_class'), - 'app.test_class' => new Alias('App\\TestClass'), - 'App\\TestClass' => new Alias('app.test_class'), - ]); - - $builder->findDefinition('foo'); - } - - public function testInitializePropertiesBeforeMethodCalls() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass'); - $container->register('bar', 'MethodCallClass') - ->setPublic(true) - ->setProperty('simple', 'bar') - ->setProperty('complex', new Reference('foo')) - ->addMethodCall('callMe'); - - $container->compile(); - - $this->assertTrue($container->get('bar')->callPassed(), '->compile() initializes properties before method calls'); - } - - public function testAutowiring() - { - $container = new ContainerBuilder(); - - $container->register(A::class)->setPublic(true); - $bDefinition = $container->register('b', B::class); - $bDefinition->setAutowired(true); - $bDefinition->setPublic(true); - - $container->compile(); - - $this->assertEquals(A::class, (string) $container->getDefinition('b')->getArgument(0)); - } - - public function testClassFromId() - { - $container = new ContainerBuilder(); - - $unknown = $container->register('Acme\UnknownClass'); - $autoloadClass = $container->register(CaseSensitiveClass::class); - $container->compile(); - - $this->assertSame('Acme\UnknownClass', $unknown->getClass()); - $this->assertEquals(CaseSensitiveClass::class, $autoloadClass->getClass()); - } - - public function testNoClassFromGlobalNamespaceClassId() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.'); - $container = new ContainerBuilder(); - - $container->register(\DateTime::class); - $container->compile(); - } - - public function testNoClassFromGlobalNamespaceClassIdWithLeadingSlash() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The definition for "\DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.'); - $container = new ContainerBuilder(); - - $container->register('\\'.\DateTime::class); - $container->compile(); - } - - public function testNoClassFromNamespaceClassIdWithLeadingSlash() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The definition for "\Symfony\Component\DependencyInjection\Tests\FooClass" has no class attribute, and appears to reference a class or interface. Please specify the class attribute explicitly or remove the leading backslash by renaming the service to "Symfony\Component\DependencyInjection\Tests\FooClass" to get rid of this error.'); - $container = new ContainerBuilder(); - - $container->register('\\'.FooClass::class); - $container->compile(); - } - - public function testNoClassFromNonClassId() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The definition for "123_abc" has no class.'); - $container = new ContainerBuilder(); - - $container->register('123_abc'); - $container->compile(); - } - - public function testNoClassFromNsSeparatorId() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The definition for "\foo" has no class.'); - $container = new ContainerBuilder(); - - $container->register('\\foo'); - $container->compile(); - } - - public function testServiceLocator() - { - $container = new ContainerBuilder(); - $container->register('foo_service', ServiceLocator::class) - ->setPublic(true) - ->addArgument([ - 'bar' => new ServiceClosureArgument(new Reference('bar_service')), - 'baz' => new ServiceClosureArgument(new TypedReference('baz_service', 'stdClass')), - ]) - ; - $container->register('bar_service', 'stdClass')->setArguments([new Reference('baz_service')])->setPublic(true); - $container->register('baz_service', 'stdClass')->setPublic(false); - $container->compile(); - - $this->assertInstanceOf(ServiceLocator::class, $foo = $container->get('foo_service')); - $this->assertSame($container->get('bar_service'), $foo->get('bar')); - } - - public function testUninitializedReference() - { - $container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php'; - $container->compile(); - - $bar = $container->get('bar'); - - $this->assertNull($bar->foo1); - $this->assertNull($bar->foo2); - $this->assertNull($bar->foo3); - $this->assertNull($bar->closures[0]()); - $this->assertNull($bar->closures[1]()); - $this->assertNull($bar->closures[2]()); - $this->assertSame([], iterator_to_array($bar->iter)); - - $container = include __DIR__.'/Fixtures/containers/container_uninitialized_ref.php'; - $container->compile(); - - $container->get('foo1'); - $container->get('baz'); - - $bar = $container->get('bar'); - - $this->assertEquals(new \stdClass(), $bar->foo1); - $this->assertNull($bar->foo2); - $this->assertEquals(new \stdClass(), $bar->foo3); - $this->assertEquals(new \stdClass(), $bar->closures[0]()); - $this->assertNull($bar->closures[1]()); - $this->assertEquals(new \stdClass(), $bar->closures[2]()); - $this->assertEquals(['foo1' => new \stdClass(), 'foo3' => new \stdClass()], iterator_to_array($bar->iter)); - } - - /** - * @dataProvider provideAlmostCircular - */ - public function testAlmostCircular($visibility) - { - $container = include __DIR__.'/Fixtures/containers/container_almost_circular.php'; - - $foo = $container->get('foo'); - $this->assertSame($foo, $foo->bar->foobar->foo); - - $foo2 = $container->get('foo2'); - $this->assertSame($foo2, $foo2->bar->foobar->foo); - - $this->assertSame([], (array) $container->get('foobar4')); - - $foo5 = $container->get('foo5'); - $this->assertSame($foo5, $foo5->bar->foo); - - $manager = $container->get('manager'); - $this->assertEquals(new \stdClass(), $manager); - - $manager = $container->get('manager2'); - $this->assertEquals(new \stdClass(), $manager); - - $foo6 = $container->get('foo6'); - $this->assertEquals((object) ['bar6' => (object) []], $foo6); - - $this->assertInstanceOf(\stdClass::class, $container->get('root')); - - $manager3 = $container->get('manager3'); - $listener3 = $container->get('listener3'); - $this->assertSame($manager3, $listener3->manager, 'Both should identically be the manager3 service'); - - $listener4 = $container->get('listener4'); - $this->assertInstanceOf('stdClass', $listener4); - } - - public function provideAlmostCircular() - { - yield ['public']; - yield ['private']; - } - - public function testRegisterForAutoconfiguration() - { - $container = new ContainerBuilder(); - $childDefA = $container->registerForAutoconfiguration('AInterface'); - $childDefB = $container->registerForAutoconfiguration('BInterface'); - $this->assertSame(['AInterface' => $childDefA, 'BInterface' => $childDefB], $container->getAutoconfiguredInstanceof()); - - // when called multiple times, the same instance is returned - $this->assertSame($childDefA, $container->registerForAutoconfiguration('AInterface')); - } - - /** - * This test checks the trigger of a deprecation note and should not be removed in major releases. - * - * @group legacy - * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed. - */ - public function testPrivateServiceTriggersDeprecation() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass') - ->setPublic(false) - ->setDeprecated(true); - $container->register('bar', 'stdClass') - ->setPublic(true) - ->setProperty('foo', new Reference('foo')); - - $container->compile(); - - $container->get('bar'); - } - - /** - * @group legacy - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4. - */ - public function testParameterWithMixedCase() - { - $container = new ContainerBuilder(new ParameterBag(['foo' => 'bar'])); - $container->register('foo', 'stdClass') - ->setPublic(true) - ->setProperty('foo', '%FOO%'); - - $container->compile(); - - $this->assertSame('bar', $container->get('foo')->foo); - } - - public function testArgumentsHaveHigherPriorityThanBindings() - { - $container = new ContainerBuilder(); - $container->register('class.via.bindings', CaseSensitiveClass::class)->setArguments([ - 'via-bindings', - ]); - $container->register('class.via.argument', CaseSensitiveClass::class)->setArguments([ - 'via-argument', - ]); - $container->register('foo', SimilarArgumentsDummy::class)->setPublic(true)->setBindings([ - CaseSensitiveClass::class => new Reference('class.via.bindings'), - '$token' => '1234', - ])->setArguments([ - '$class1' => new Reference('class.via.argument'), - ]); - - $this->assertSame(['service_container', 'class.via.bindings', 'class.via.argument', 'foo', 'Psr\Container\ContainerInterface', 'Symfony\Component\DependencyInjection\ContainerInterface'], $container->getServiceIds()); - - $container->compile(); - - $this->assertSame('via-argument', $container->get('foo')->class1->identifier); - $this->assertSame('via-bindings', $container->get('foo')->class2->identifier); - } - - public function testUninitializedSyntheticReference() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setPublic(true)->setSynthetic(true); - $container->register('bar', 'stdClass')->setPublic(true)->setShared(false) - ->setProperty('foo', new Reference('foo', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)); - - $container->compile(); - - $this->assertEquals((object) ['foo' => null], $container->get('bar')); - - $container->set('foo', (object) [123]); - $this->assertEquals((object) ['foo' => (object) [123]], $container->get('bar')); - } - - public function testDecoratedSelfReferenceInvolvingPrivateServices() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass') - ->setPublic(false) - ->setProperty('bar', new Reference('foo')); - $container->register('baz', 'stdClass') - ->setPublic(false) - ->setProperty('inner', new Reference('baz.inner')) - ->setDecoratedService('foo'); - - $container->compile(); - - $this->assertSame(['service_container'], array_keys($container->getDefinitions())); - } - - public function testScalarService() - { - $c = new ContainerBuilder(); - $c->register('foo', 'string') - ->setPublic(true) - ->setFactory([ScalarFactory::class, 'getSomeValue']) - ; - - $c->compile(); - - $this->assertTrue($c->has('foo')); - $this->assertSame('some value', $c->get('foo')); - } -} - -class FooClass -{ -} - -class A -{ -} - -class B -{ - public function __construct(A $a) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ContainerTest.php b/vendor/symfony/dependency-injection/Tests/ContainerTest.php deleted file mode 100644 index 46527e09..00000000 --- a/vendor/symfony/dependency-injection/Tests/ContainerTest.php +++ /dev/null @@ -1,692 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Container; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; - -class ContainerTest extends TestCase -{ - public function testConstructor() - { - $sc = new Container(); - $this->assertSame($sc, $sc->get('service_container'), '__construct() automatically registers itself as a service'); - - $sc = new Container(new ParameterBag(['foo' => 'bar'])); - $this->assertEquals(['foo' => 'bar'], $sc->getParameterBag()->all(), '__construct() takes an array of parameters as its first argument'); - } - - /** - * @dataProvider dataForTestCamelize - */ - public function testCamelize($id, $expected) - { - $this->assertEquals($expected, Container::camelize($id), sprintf('Container::camelize("%s")', $id)); - } - - public function dataForTestCamelize() - { - return [ - ['foo_bar', 'FooBar'], - ['foo.bar', 'Foo_Bar'], - ['foo.bar_baz', 'Foo_BarBaz'], - ['foo._bar', 'Foo_Bar'], - ['foo_.bar', 'Foo_Bar'], - ['_foo', 'Foo'], - ['.foo', '_Foo'], - ['foo_', 'Foo'], - ['foo.', 'Foo_'], - ['foo\bar', 'Foo_Bar'], - ]; - } - - /** - * @dataProvider dataForTestUnderscore - */ - public function testUnderscore($id, $expected) - { - $this->assertEquals($expected, Container::underscore($id), sprintf('Container::underscore("%s")', $id)); - } - - public function dataForTestUnderscore() - { - return [ - ['FooBar', 'foo_bar'], - ['Foo_Bar', 'foo.bar'], - ['Foo_BarBaz', 'foo.bar_baz'], - ['FooBar_BazQux', 'foo_bar.baz_qux'], - ['_Foo', '.foo'], - ['Foo_', 'foo.'], - ]; - } - - public function testCompile() - { - $sc = new Container(new ParameterBag(['foo' => 'bar'])); - $this->assertFalse($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag'); - $sc->compile(); - $this->assertTrue($sc->getParameterBag()->isResolved(), '->compile() resolves the parameter bag'); - $this->assertInstanceOf('Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag', $sc->getParameterBag(), '->compile() changes the parameter bag to a FrozenParameterBag instance'); - $this->assertEquals(['foo' => 'bar'], $sc->getParameterBag()->all(), '->compile() copies the current parameters to the new parameter bag'); - } - - /** - * @group legacy - * @expectedDeprecation The Symfony\Component\DependencyInjection\Container::isFrozen() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead. - * @expectedDeprecation The Symfony\Component\DependencyInjection\Container::isFrozen() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead. - */ - public function testIsFrozen() - { - $sc = new Container(new ParameterBag(['foo' => 'bar'])); - $this->assertFalse($sc->isFrozen(), '->isFrozen() returns false if the parameters are not frozen'); - $sc->compile(); - $this->assertTrue($sc->isFrozen(), '->isFrozen() returns true if the parameters are frozen'); - } - - public function testIsCompiled() - { - $sc = new Container(new ParameterBag(['foo' => 'bar'])); - $this->assertFalse($sc->isCompiled(), '->isCompiled() returns false if the container is not compiled'); - $sc->compile(); - $this->assertTrue($sc->isCompiled(), '->isCompiled() returns true if the container is compiled'); - } - - public function testIsCompiledWithFrozenParameters() - { - $sc = new Container(new FrozenParameterBag(['foo' => 'bar'])); - $this->assertFalse($sc->isCompiled(), '->isCompiled() returns false if the container is not compiled but the parameter bag is already frozen'); - } - - public function testGetParameterBag() - { - $sc = new Container(); - $this->assertEquals([], $sc->getParameterBag()->all(), '->getParameterBag() returns an empty array if no parameter has been defined'); - } - - public function testGetSetParameter() - { - $sc = new Container(new ParameterBag(['foo' => 'bar'])); - $sc->setParameter('bar', 'foo'); - $this->assertEquals('foo', $sc->getParameter('bar'), '->setParameter() sets the value of a new parameter'); - - $sc->setParameter('foo', 'baz'); - $this->assertEquals('baz', $sc->getParameter('foo'), '->setParameter() overrides previously set parameter'); - - try { - $sc->getParameter('baba'); - $this->fail('->getParameter() thrown an \InvalidArgumentException if the key does not exist'); - } catch (\Exception $e) { - $this->assertInstanceOf('\InvalidArgumentException', $e, '->getParameter() thrown an \InvalidArgumentException if the key does not exist'); - $this->assertEquals('You have requested a non-existent parameter "baba".', $e->getMessage(), '->getParameter() thrown an \InvalidArgumentException if the key does not exist'); - } - } - - /** - * @group legacy - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since Symfony 3.4. - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4. - */ - public function testGetSetParameterWithMixedCase() - { - $sc = new Container(new ParameterBag(['foo' => 'bar'])); - - $sc->setParameter('Foo', 'baz1'); - $this->assertEquals('baz1', $sc->getParameter('foo'), '->setParameter() converts the key to lowercase'); - $this->assertEquals('baz1', $sc->getParameter('FOO'), '->getParameter() converts the key to lowercase'); - } - - public function testGetServiceIds() - { - $sc = new Container(); - $sc->set('foo', $obj = new \stdClass()); - $sc->set('bar', $obj = new \stdClass()); - $this->assertEquals(['service_container', 'foo', 'bar'], $sc->getServiceIds(), '->getServiceIds() returns all defined service ids'); - - $sc = new ProjectServiceContainer(); - $sc->set('foo', $obj = new \stdClass()); - $this->assertEquals(['service_container', 'internal', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'internal_dependency', 'alias', 'foo'], $sc->getServiceIds(), '->getServiceIds() returns defined service ids by factory methods in the method map, followed by service ids defined by set()'); - } - - /** - * @group legacy - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - */ - public function testGetLegacyServiceIds() - { - $sc = new LegacyProjectServiceContainer(); - $sc->set('foo', $obj = new \stdClass()); - - $this->assertEquals(['internal', 'bar', 'foo_bar', 'foo.baz', 'circular', 'throw_exception', 'throws_exception_on_service_configuration', 'service_container', 'alias', 'foo'], $sc->getServiceIds(), '->getServiceIds() returns defined service ids by getXXXService() methods, followed by service ids defined by set()'); - } - - public function testSet() - { - $sc = new Container(); - $sc->set('._. \\o/', $foo = new \stdClass()); - $this->assertSame($foo, $sc->get('._. \\o/'), '->set() sets a service'); - } - - public function testSetWithNullResetTheService() - { - $sc = new Container(); - $sc->set('foo', null); - $this->assertFalse($sc->has('foo'), '->set() with null service resets the service'); - } - - public function testSetReplacesAlias() - { - $c = new ProjectServiceContainer(); - - $c->set('alias', $foo = new \stdClass()); - $this->assertSame($foo, $c->get('alias'), '->set() replaces an existing alias'); - } - - /** - * @group legacy - * @expectedDeprecation The "bar" service is already initialized, unsetting it is deprecated since Symfony 3.3 and will fail in 4.0. - */ - public function testSetWithNullOnInitializedPredefinedService() - { - $sc = new Container(); - $sc->set('foo', new \stdClass()); - $sc->set('foo', null); - $this->assertFalse($sc->has('foo'), '->set() with null service resets the service'); - - $sc = new ProjectServiceContainer(); - $sc->get('bar'); - $sc->set('bar', null); - $this->assertTrue($sc->has('bar'), '->set() with null service resets the pre-defined service'); - } - - public function testSetWithNullOnUninitializedPredefinedService() - { - $sc = new Container(); - $sc->set('foo', new \stdClass()); - $sc->get('foo', null); - $sc->set('foo', null); - $this->assertFalse($sc->has('foo'), '->set() with null service resets the service'); - - $sc = new ProjectServiceContainer(); - $sc->set('bar', null); - $this->assertTrue($sc->has('bar'), '->set() with null service resets the pre-defined service'); - } - - public function testGet() - { - $sc = new ProjectServiceContainer(); - $sc->set('foo', $foo = new \stdClass()); - $this->assertSame($foo, $sc->get('foo'), '->get() returns the service for the given id'); - $this->assertSame($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id'); - $this->assertSame($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined'); - $this->assertSame($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined'); - - try { - $sc->get(''); - $this->fail('->get() throws a \InvalidArgumentException exception if the service is empty'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty'); - } - $this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service is empty'); - } - - /** - * @group legacy - * @expectedDeprecation Service identifiers will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since Symfony 3.3. - */ - public function testGetInsensitivity() - { - $sc = new ProjectServiceContainer(); - $sc->set('foo', $foo = new \stdClass()); - $this->assertSame($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase'); - } - - /** - * @group legacy - * @expectedDeprecation Service identifiers will be made case sensitive in Symfony 4.0. Using "foo" instead of "Foo" is deprecated since Symfony 3.3. - */ - public function testNormalizeIdKeepsCase() - { - $sc = new ProjectServiceContainer(); - $sc->normalizeId('Foo', true); - $this->assertSame('Foo', $sc->normalizeId('foo')); - } - - /** - * @group legacy - * @expectedDeprecation Service identifiers will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since Symfony 3.3. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - */ - public function testLegacyGet() - { - $sc = new LegacyProjectServiceContainer(); - $sc->set('foo', $foo = new \stdClass()); - - $this->assertSame($foo, $sc->get('foo'), '->get() returns the service for the given id'); - $this->assertSame($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase'); - $this->assertSame($sc->__bar, $sc->get('bar'), '->get() returns the service for the given id'); - $this->assertSame($sc->__foo_bar, $sc->get('foo_bar'), '->get() returns the service if a get*Method() is defined'); - $this->assertSame($sc->__foo_baz, $sc->get('foo.baz'), '->get() returns the service if a get*Method() is defined'); - $this->assertSame($sc->__foo_baz, $sc->get('foo\\baz'), '->get() returns the service if a get*Method() is defined'); - - $sc->set('bar', $bar = new \stdClass()); - $this->assertSame($bar, $sc->get('bar'), '->get() prefers to return a service defined with set() than one defined with a getXXXMethod()'); - - try { - $sc->get(''); - $this->fail('->get() throws a \InvalidArgumentException exception if the service is empty'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws a ServiceNotFoundException exception if the service is empty'); - } - $this->assertNull($sc->get('', ContainerInterface::NULL_ON_INVALID_REFERENCE), '->get() returns null if the service is empty'); - } - - public function testGetThrowServiceNotFoundException() - { - $sc = new ProjectServiceContainer(); - $sc->set('foo', $foo = new \stdClass()); - $sc->set('baz', $foo = new \stdClass()); - - try { - $sc->get('foo1'); - $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist'); - $this->assertEquals('You have requested a non-existent service "foo1". Did you mean this: "foo"?', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException with some advices'); - } - - try { - $sc->get('bag'); - $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException if the key does not exist'); - $this->assertEquals('You have requested a non-existent service "bag". Did you mean one of these: "bar", "baz"?', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException with some advices'); - } - } - - public function testGetCircularReference() - { - $sc = new ProjectServiceContainer(); - try { - $sc->get('circular'); - $this->fail('->get() throws a ServiceCircularReferenceException if it contains circular reference'); - } catch (\Exception $e) { - $this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException', $e, '->get() throws a ServiceCircularReferenceException if it contains circular reference'); - $this->assertStringStartsWith('Circular reference detected for service "circular"', $e->getMessage(), '->get() throws a \LogicException if it contains circular reference'); - } - } - - public function testGetSyntheticServiceThrows() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException'); - $this->expectExceptionMessage('The "request" service is synthetic, it needs to be set at boot time before it can be used.'); - require_once __DIR__.'/Fixtures/php/services9_compiled.php'; - - $container = new \ProjectServiceContainer(); - $container->get('request'); - } - - public function testGetRemovedServiceThrows() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException'); - $this->expectExceptionMessage('The "inlined" service or alias has been removed or inlined when the container was compiled. You should either make it public, or stop using the container directly and use dependency injection instead.'); - require_once __DIR__.'/Fixtures/php/services9_compiled.php'; - - $container = new \ProjectServiceContainer(); - $container->get('inlined'); - } - - public function testHas() - { - $sc = new ProjectServiceContainer(); - $sc->set('foo', new \stdClass()); - $this->assertFalse($sc->has('foo1'), '->has() returns false if the service does not exist'); - $this->assertTrue($sc->has('foo'), '->has() returns true if the service exists'); - $this->assertTrue($sc->has('bar'), '->has() returns true if a get*Method() is defined'); - $this->assertTrue($sc->has('foo_bar'), '->has() returns true if a get*Method() is defined'); - $this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined'); - } - - /** - * @group legacy - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - * @expectedDeprecation Generating a dumped container without populating the method map is deprecated since Symfony 3.2 and will be unsupported in 4.0. Update your dumper to generate the method map. - */ - public function testLegacyHas() - { - $sc = new LegacyProjectServiceContainer(); - $sc->set('foo', new \stdClass()); - - $this->assertFalse($sc->has('foo1'), '->has() returns false if the service does not exist'); - $this->assertTrue($sc->has('foo'), '->has() returns true if the service exists'); - $this->assertTrue($sc->has('bar'), '->has() returns true if a get*Method() is defined'); - $this->assertTrue($sc->has('foo_bar'), '->has() returns true if a get*Method() is defined'); - $this->assertTrue($sc->has('foo.baz'), '->has() returns true if a get*Method() is defined'); - $this->assertTrue($sc->has('foo\\baz'), '->has() returns true if a get*Method() is defined'); - } - - public function testScalarService() - { - $c = new Container(); - - $c->set('foo', 'some value'); - - $this->assertTrue($c->has('foo')); - $this->assertSame('some value', $c->get('foo')); - } - - public function testInitialized() - { - $sc = new ProjectServiceContainer(); - $sc->set('foo', new \stdClass()); - $this->assertTrue($sc->initialized('foo'), '->initialized() returns true if service is loaded'); - $this->assertFalse($sc->initialized('foo1'), '->initialized() returns false if service is not loaded'); - $this->assertFalse($sc->initialized('bar'), '->initialized() returns false if a service is defined, but not currently loaded'); - $this->assertFalse($sc->initialized('alias'), '->initialized() returns false if an aliased service is not initialized'); - - $sc->get('bar'); - $this->assertTrue($sc->initialized('alias'), '->initialized() returns true for alias if aliased service is initialized'); - } - - /** - * @group legacy - * @expectedDeprecation Checking for the initialization of the "internal" private service is deprecated since Symfony 3.4 and won't be supported anymore in Symfony 4.0. - */ - public function testInitializedWithPrivateService() - { - $sc = new ProjectServiceContainer(); - $sc->get('internal_dependency'); - $this->assertTrue($sc->initialized('internal')); - } - - public function testReset() - { - $c = new Container(); - $c->set('bar', new \stdClass()); - - $c->reset(); - - $this->assertNull($c->get('bar', ContainerInterface::NULL_ON_INVALID_REFERENCE)); - } - - public function testGetThrowsException() - { - $this->expectException('Exception'); - $this->expectExceptionMessage('Something went terribly wrong!'); - $c = new ProjectServiceContainer(); - - try { - $c->get('throw_exception'); - } catch (\Exception $e) { - // Do nothing. - } - - // Retry, to make sure that get*Service() will be called. - $c->get('throw_exception'); - } - - public function testGetThrowsExceptionOnServiceConfiguration() - { - $c = new ProjectServiceContainer(); - - try { - $c->get('throws_exception_on_service_configuration'); - } catch (\Exception $e) { - // Do nothing. - } - - $this->assertFalse($c->initialized('throws_exception_on_service_configuration')); - - // Retry, to make sure that get*Service() will be called. - try { - $c->get('throws_exception_on_service_configuration'); - } catch (\Exception $e) { - // Do nothing. - } - $this->assertFalse($c->initialized('throws_exception_on_service_configuration')); - } - - protected function getField($obj, $field) - { - $reflection = new \ReflectionProperty($obj, $field); - $reflection->setAccessible(true); - - return $reflection->getValue($obj); - } - - public function testAlias() - { - $c = new ProjectServiceContainer(); - - $this->assertTrue($c->has('alias')); - $this->assertSame($c->get('alias'), $c->get('bar')); - } - - public function testThatCloningIsNotSupported() - { - $class = new \ReflectionClass('Symfony\Component\DependencyInjection\Container'); - $clone = $class->getMethod('__clone'); - $this->assertFalse($class->isCloneable()); - $this->assertTrue($clone->isPrivate()); - } - - /** - * @group legacy - * @expectedDeprecation The "internal" service is private, unsetting it is deprecated since Symfony 3.2 and will fail in 4.0. - */ - public function testUnsetInternalPrivateServiceIsDeprecated() - { - $c = new ProjectServiceContainer(); - $c->set('internal', null); - } - - /** - * @group legacy - * @expectedDeprecation The "internal" service is private, replacing it is deprecated since Symfony 3.2 and will fail in 4.0. - */ - public function testChangeInternalPrivateServiceIsDeprecated() - { - $c = new ProjectServiceContainer(); - $c->set('internal', $internal = new \stdClass()); - $this->assertSame($c->get('internal'), $internal); - } - - /** - * @group legacy - * @expectedDeprecation The "internal" service is private, checking for its existence is deprecated since Symfony 3.2 and will fail in 4.0. - */ - public function testCheckExistenceOfAnInternalPrivateServiceIsDeprecated() - { - $c = new ProjectServiceContainer(); - $c->get('internal_dependency'); - $this->assertTrue($c->has('internal')); - } - - /** - * @group legacy - * @expectedDeprecation The "internal" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - */ - public function testRequestAnInternalSharedPrivateServiceIsDeprecated() - { - $c = new ProjectServiceContainer(); - $c->get('internal_dependency'); - $c->get('internal'); - } - - /** - * @group legacy - * @expectedDeprecation The "bar" service is already initialized, replacing it is deprecated since Symfony 3.3 and will fail in 4.0. - */ - public function testReplacingAPreDefinedServiceIsDeprecated() - { - $c = new ProjectServiceContainer(); - $c->set('bar', new \stdClass()); - $c->set('bar', $bar = new \stdClass()); - - $this->assertSame($bar, $c->get('bar'), '->set() replaces a pre-defined service'); - } - - /** - * @group legacy - * @expectedDeprecation The "synthetic" service is private, replacing it is deprecated since Symfony 3.2 and will fail in 4.0. - */ - public function testSetWithPrivateSyntheticServiceThrowsDeprecation() - { - $c = new ProjectServiceContainer(); - $c->set('synthetic', new \stdClass()); - } -} - -class ProjectServiceContainer extends Container -{ - public $__bar; - public $__foo_bar; - public $__foo_baz; - public $__internal; - protected $privates; - protected $methodMap = [ - 'internal' => 'getInternalService', - 'bar' => 'getBarService', - 'foo_bar' => 'getFooBarService', - 'foo.baz' => 'getFoo_BazService', - 'circular' => 'getCircularService', - 'throw_exception' => 'getThrowExceptionService', - 'throws_exception_on_service_configuration' => 'getThrowsExceptionOnServiceConfigurationService', - 'internal_dependency' => 'getInternalDependencyService', - ]; - - public function __construct() - { - parent::__construct(); - - $this->__bar = new \stdClass(); - $this->__foo_bar = new \stdClass(); - $this->__foo_baz = new \stdClass(); - $this->__internal = new \stdClass(); - $this->privates = [ - 'internal' => true, - 'synthetic' => true, - ]; - $this->aliases = ['alias' => 'bar']; - $this->syntheticIds['synthetic'] = true; - } - - protected function getInternalService() - { - return $this->services['internal'] = $this->__internal; - } - - protected function getBarService() - { - return $this->services['bar'] = $this->__bar; - } - - protected function getFooBarService() - { - return $this->__foo_bar; - } - - protected function getFoo_BazService() - { - return $this->__foo_baz; - } - - protected function getCircularService() - { - return $this->get('circular'); - } - - protected function getThrowExceptionService() - { - throw new \Exception('Something went terribly wrong!'); - } - - protected function getThrowsExceptionOnServiceConfigurationService() - { - $this->services['throws_exception_on_service_configuration'] = $instance = new \stdClass(); - - throw new \Exception('Something was terribly wrong while trying to configure the service!'); - } - - protected function getInternalDependencyService() - { - $this->services['internal_dependency'] = $instance = new \stdClass(); - - $instance->internal = isset($this->services['internal']) ? $this->services['internal'] : $this->getInternalService(); - - return $instance; - } -} - -class LegacyProjectServiceContainer extends Container -{ - public $__bar; - public $__foo_bar; - public $__foo_baz; - public $__internal; - - public function __construct() - { - parent::__construct(); - - $this->__bar = new \stdClass(); - $this->__foo_bar = new \stdClass(); - $this->__foo_baz = new \stdClass(); - $this->__internal = new \stdClass(); - $this->privates = ['internal' => true]; - $this->aliases = ['alias' => 'bar']; - } - - protected function getInternalService() - { - return $this->__internal; - } - - protected function getBarService() - { - return $this->__bar; - } - - protected function getFooBarService() - { - return $this->__foo_bar; - } - - protected function getFoo_BazService() - { - return $this->__foo_baz; - } - - protected function getCircularService() - { - return $this->get('circular'); - } - - protected function getThrowExceptionService() - { - throw new \Exception('Something went terribly wrong!'); - } - - protected function getThrowsExceptionOnServiceConfigurationService() - { - $this->services['throws_exception_on_service_configuration'] = $instance = new \stdClass(); - - throw new \Exception('Something was terribly wrong while trying to configure the service!'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/CrossCheckTest.php b/vendor/symfony/dependency-injection/Tests/CrossCheckTest.php deleted file mode 100644 index fe132af4..00000000 --- a/vendor/symfony/dependency-injection/Tests/CrossCheckTest.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -class CrossCheckTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = __DIR__.'/Fixtures/'; - - require_once self::$fixturesPath.'/includes/classes.php'; - require_once self::$fixturesPath.'/includes/foo.php'; - } - - /** - * @dataProvider crossCheckLoadersDumpers - */ - public function testCrossCheck($fixture, $type) - { - $loaderClass = 'Symfony\\Component\\DependencyInjection\\Loader\\'.ucfirst($type).'FileLoader'; - $dumperClass = 'Symfony\\Component\\DependencyInjection\\Dumper\\'.ucfirst($type).'Dumper'; - - $tmp = tempnam(sys_get_temp_dir(), 'sf'); - - copy(self::$fixturesPath.'/'.$type.'/'.$fixture, $tmp); - - $container1 = new ContainerBuilder(); - $loader1 = new $loaderClass($container1, new FileLocator()); - $loader1->load($tmp); - - $dumper = new $dumperClass($container1); - file_put_contents($tmp, $dumper->dump()); - - $container2 = new ContainerBuilder(); - $loader2 = new $loaderClass($container2, new FileLocator()); - $loader2->load($tmp); - - unlink($tmp); - - $this->assertEquals($container2->getAliases(), $container1->getAliases(), 'loading a dump from a previously loaded container returns the same container'); - $this->assertEquals($container2->getDefinitions(), $container1->getDefinitions(), 'loading a dump from a previously loaded container returns the same container'); - $this->assertEquals($container2->getParameterBag()->all(), $container1->getParameterBag()->all(), '->getParameterBag() returns the same value for both containers'); - - $r = new \ReflectionProperty(ContainerBuilder::class, 'normalizedIds'); - $r->setAccessible(true); - $r->setValue($container2, []); - $r->setValue($container1, []); - - $this->assertEquals(serialize($container2), serialize($container1), 'loading a dump from a previously loaded container returns the same container'); - - $services1 = []; - foreach ($container1 as $id => $service) { - $services1[$id] = serialize($service); - } - $services2 = []; - foreach ($container2 as $id => $service) { - $services2[$id] = serialize($service); - } - - unset($services1['service_container'], $services2['service_container']); - - $this->assertEquals($services2, $services1, 'Iterator on the containers returns the same services'); - } - - public function crossCheckLoadersDumpers() - { - return [ - ['services1.xml', 'xml'], - ['services2.xml', 'xml'], - ['services6.xml', 'xml'], - ['services8.xml', 'xml'], - ['services9.xml', 'xml'], - ['services1.yml', 'yaml'], - ['services2.yml', 'yaml'], - ['services6.yml', 'yaml'], - ['services8.yml', 'yaml'], - ['services9.yml', 'yaml'], - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/DefinitionDecoratorTest.php b/vendor/symfony/dependency-injection/Tests/DefinitionDecoratorTest.php deleted file mode 100644 index 8d382f81..00000000 --- a/vendor/symfony/dependency-injection/Tests/DefinitionDecoratorTest.php +++ /dev/null @@ -1,128 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\DefinitionDecorator; - -/** - * @group legacy - */ -class DefinitionDecoratorTest extends TestCase -{ - public function testConstructor() - { - $def = new DefinitionDecorator('foo'); - - $this->assertEquals('foo', $def->getParent()); - $this->assertEquals([], $def->getChanges()); - } - - /** - * @dataProvider getPropertyTests - */ - public function testSetProperty($property, $changeKey) - { - $def = new DefinitionDecorator('foo'); - - $getter = 'get'.ucfirst($property); - $setter = 'set'.ucfirst($property); - - $this->assertNull($def->$getter()); - $this->assertSame($def, $def->$setter('foo')); - $this->assertEquals('foo', $def->$getter()); - $this->assertEquals([$changeKey => true], $def->getChanges()); - } - - public function getPropertyTests() - { - return [ - ['class', 'class'], - ['factory', 'factory'], - ['configurator', 'configurator'], - ['file', 'file'], - ]; - } - - public function testSetPublic() - { - $def = new DefinitionDecorator('foo'); - - $this->assertTrue($def->isPublic()); - $this->assertSame($def, $def->setPublic(false)); - $this->assertFalse($def->isPublic()); - $this->assertEquals(['public' => true], $def->getChanges()); - } - - public function testSetLazy() - { - $def = new DefinitionDecorator('foo'); - - $this->assertFalse($def->isLazy()); - $this->assertSame($def, $def->setLazy(false)); - $this->assertFalse($def->isLazy()); - $this->assertEquals(['lazy' => true], $def->getChanges()); - } - - public function testSetAutowired() - { - $def = new DefinitionDecorator('foo'); - - $this->assertFalse($def->isAutowired()); - $this->assertSame($def, $def->setAutowired(true)); - $this->assertTrue($def->isAutowired()); - $this->assertSame(['autowired' => true], $def->getChanges()); - } - - public function testSetArgument() - { - $def = new DefinitionDecorator('foo'); - - $this->assertEquals([], $def->getArguments()); - $this->assertSame($def, $def->replaceArgument(0, 'foo')); - $this->assertEquals(['index_0' => 'foo'], $def->getArguments()); - } - - public function testReplaceArgumentShouldRequireIntegerIndex() - { - $this->expectException('InvalidArgumentException'); - $def = new DefinitionDecorator('foo'); - - $def->replaceArgument('0', 'foo'); - } - - public function testReplaceArgument() - { - $def = new DefinitionDecorator('foo'); - - $def->setArguments([0 => 'foo', 1 => 'bar']); - $this->assertEquals('foo', $def->getArgument(0)); - $this->assertEquals('bar', $def->getArgument(1)); - - $this->assertSame($def, $def->replaceArgument(1, 'baz')); - $this->assertEquals('foo', $def->getArgument(0)); - $this->assertEquals('baz', $def->getArgument(1)); - - $this->assertEquals([0 => 'foo', 1 => 'bar', 'index_1' => 'baz'], $def->getArguments()); - } - - public function testGetArgumentShouldCheckBounds() - { - $this->expectException('OutOfBoundsException'); - $def = new DefinitionDecorator('foo'); - - $def->setArguments([0 => 'foo']); - $def->replaceArgument(0, 'foo'); - - $def->getArgument(1); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/DefinitionTest.php b/vendor/symfony/dependency-injection/Tests/DefinitionTest.php deleted file mode 100644 index 63ca748e..00000000 --- a/vendor/symfony/dependency-injection/Tests/DefinitionTest.php +++ /dev/null @@ -1,387 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Definition; - -class DefinitionTest extends TestCase -{ - public function testConstructor() - { - $def = new Definition('stdClass'); - $this->assertEquals('stdClass', $def->getClass(), '__construct() takes the class name as its first argument'); - $this->assertSame(['class' => true], $def->getChanges()); - - $def = new Definition('stdClass', ['foo']); - $this->assertEquals(['foo'], $def->getArguments(), '__construct() takes an optional array of arguments as its second argument'); - } - - public function testSetGetFactory() - { - $def = new Definition(); - - $this->assertSame($def, $def->setFactory('foo'), '->setFactory() implements a fluent interface'); - $this->assertEquals('foo', $def->getFactory(), '->getFactory() returns the factory'); - - $def->setFactory('Foo::bar'); - $this->assertEquals(['Foo', 'bar'], $def->getFactory(), '->setFactory() converts string static method call to the array'); - $this->assertSame(['factory' => true], $def->getChanges()); - } - - public function testSetGetClass() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->setClass('foo'), '->setClass() implements a fluent interface'); - $this->assertEquals('foo', $def->getClass(), '->getClass() returns the class name'); - } - - public function testSetGetDecoratedService() - { - $def = new Definition('stdClass'); - $this->assertNull($def->getDecoratedService()); - $def->setDecoratedService('foo', 'foo.renamed', 5); - $this->assertEquals(['foo', 'foo.renamed', 5], $def->getDecoratedService()); - $def->setDecoratedService(null); - $this->assertNull($def->getDecoratedService()); - - $def = new Definition('stdClass'); - $this->assertNull($def->getDecoratedService()); - $def->setDecoratedService('foo', 'foo.renamed'); - $this->assertEquals(['foo', 'foo.renamed', 0], $def->getDecoratedService()); - $def->setDecoratedService(null); - $this->assertNull($def->getDecoratedService()); - - $def = new Definition('stdClass'); - $def->setDecoratedService('foo'); - $this->assertEquals(['foo', null, 0], $def->getDecoratedService()); - $def->setDecoratedService(null); - $this->assertNull($def->getDecoratedService()); - - $def = new Definition('stdClass'); - - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The decorated service inner name for "foo" must be different than the service name itself.'); - - $def->setDecoratedService('foo', 'foo'); - } - - public function testArguments() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->setArguments(['foo']), '->setArguments() implements a fluent interface'); - $this->assertEquals(['foo'], $def->getArguments(), '->getArguments() returns the arguments'); - $this->assertSame($def, $def->addArgument('bar'), '->addArgument() implements a fluent interface'); - $this->assertEquals(['foo', 'bar'], $def->getArguments(), '->addArgument() adds an argument'); - } - - public function testMethodCalls() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->setMethodCalls([['foo', ['foo']]]), '->setMethodCalls() implements a fluent interface'); - $this->assertEquals([['foo', ['foo']]], $def->getMethodCalls(), '->getMethodCalls() returns the methods to call'); - $this->assertSame($def, $def->addMethodCall('bar', ['bar']), '->addMethodCall() implements a fluent interface'); - $this->assertEquals([['foo', ['foo']], ['bar', ['bar']]], $def->getMethodCalls(), '->addMethodCall() adds a method to call'); - $this->assertTrue($def->hasMethodCall('bar'), '->hasMethodCall() returns true if first argument is a method to call registered'); - $this->assertFalse($def->hasMethodCall('no_registered'), '->hasMethodCall() returns false if first argument is not a method to call registered'); - $this->assertSame($def, $def->removeMethodCall('bar'), '->removeMethodCall() implements a fluent interface'); - $this->assertEquals([['foo', ['foo']]], $def->getMethodCalls(), '->removeMethodCall() removes a method to call'); - } - - public function testExceptionOnEmptyMethodCall() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Method name cannot be empty.'); - $def = new Definition('stdClass'); - $def->addMethodCall(''); - } - - public function testSetGetFile() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->setFile('foo'), '->setFile() implements a fluent interface'); - $this->assertEquals('foo', $def->getFile(), '->getFile() returns the file to include'); - } - - public function testSetIsShared() - { - $def = new Definition('stdClass'); - $this->assertTrue($def->isShared(), '->isShared() returns true by default'); - $this->assertSame($def, $def->setShared(false), '->setShared() implements a fluent interface'); - $this->assertFalse($def->isShared(), '->isShared() returns false if the instance must not be shared'); - } - - public function testSetIsPublic() - { - $def = new Definition('stdClass'); - $this->assertTrue($def->isPublic(), '->isPublic() returns true by default'); - $this->assertSame($def, $def->setPublic(false), '->setPublic() implements a fluent interface'); - $this->assertFalse($def->isPublic(), '->isPublic() returns false if the instance must not be public.'); - } - - public function testSetIsSynthetic() - { - $def = new Definition('stdClass'); - $this->assertFalse($def->isSynthetic(), '->isSynthetic() returns false by default'); - $this->assertSame($def, $def->setSynthetic(true), '->setSynthetic() implements a fluent interface'); - $this->assertTrue($def->isSynthetic(), '->isSynthetic() returns true if the service is synthetic.'); - } - - public function testSetIsLazy() - { - $def = new Definition('stdClass'); - $this->assertFalse($def->isLazy(), '->isLazy() returns false by default'); - $this->assertSame($def, $def->setLazy(true), '->setLazy() implements a fluent interface'); - $this->assertTrue($def->isLazy(), '->isLazy() returns true if the service is lazy.'); - } - - public function testSetIsAbstract() - { - $def = new Definition('stdClass'); - $this->assertFalse($def->isAbstract(), '->isAbstract() returns false by default'); - $this->assertSame($def, $def->setAbstract(true), '->setAbstract() implements a fluent interface'); - $this->assertTrue($def->isAbstract(), '->isAbstract() returns true if the instance must not be public.'); - } - - public function testSetIsDeprecated() - { - $def = new Definition('stdClass'); - $this->assertFalse($def->isDeprecated(), '->isDeprecated() returns false by default'); - $this->assertSame($def, $def->setDeprecated(true), '->setDeprecated() implements a fluent interface'); - $this->assertTrue($def->isDeprecated(), '->isDeprecated() returns true if the instance should not be used anymore.'); - $this->assertSame('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', $def->getDeprecationMessage('deprecated_service'), '->getDeprecationMessage() should return a formatted message template'); - } - - /** - * @dataProvider invalidDeprecationMessageProvider - */ - public function testSetDeprecatedWithInvalidDeprecationTemplate($message) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $def = new Definition('stdClass'); - $def->setDeprecated(false, $message); - } - - public function invalidDeprecationMessageProvider() - { - return [ - "With \rs" => ["invalid \r message %service_id%"], - "With \ns" => ["invalid \n message %service_id%"], - 'With */s' => ['invalid */ message %service_id%'], - 'message not containing require %service_id% variable' => ['this is deprecated'], - ]; - } - - public function testSetGetConfigurator() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->setConfigurator('foo'), '->setConfigurator() implements a fluent interface'); - $this->assertEquals('foo', $def->getConfigurator(), '->getConfigurator() returns the configurator'); - } - - public function testClearTags() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->clearTags(), '->clearTags() implements a fluent interface'); - $def->addTag('foo', ['foo' => 'bar']); - $def->clearTags(); - $this->assertEquals([], $def->getTags(), '->clearTags() removes all current tags'); - } - - public function testClearTag() - { - $def = new Definition('stdClass'); - $this->assertSame($def, $def->clearTags(), '->clearTags() implements a fluent interface'); - $def->addTag('1foo1', ['foo1' => 'bar1']); - $def->addTag('2foo2', ['foo2' => 'bar2']); - $def->addTag('3foo3', ['foo3' => 'bar3']); - $def->clearTag('2foo2'); - $this->assertTrue($def->hasTag('1foo1')); - $this->assertFalse($def->hasTag('2foo2')); - $this->assertTrue($def->hasTag('3foo3')); - $def->clearTag('1foo1'); - $this->assertFalse($def->hasTag('1foo1')); - $this->assertTrue($def->hasTag('3foo3')); - } - - public function testTags() - { - $def = new Definition('stdClass'); - $this->assertEquals([], $def->getTag('foo'), '->getTag() returns an empty array if the tag is not defined'); - $this->assertFalse($def->hasTag('foo')); - $this->assertSame($def, $def->addTag('foo'), '->addTag() implements a fluent interface'); - $this->assertTrue($def->hasTag('foo')); - $this->assertEquals([[]], $def->getTag('foo'), '->getTag() returns attributes for a tag name'); - $def->addTag('foo', ['foo' => 'bar']); - $this->assertEquals([[], ['foo' => 'bar']], $def->getTag('foo'), '->addTag() can adds the same tag several times'); - $def->addTag('bar', ['bar' => 'bar']); - $this->assertEquals([ - 'foo' => [[], ['foo' => 'bar']], - 'bar' => [['bar' => 'bar']], - ], $def->getTags(), '->getTags() returns all tags'); - } - - public function testSetArgument() - { - $def = new Definition('stdClass'); - - $def->addArgument('foo'); - $this->assertSame(['foo'], $def->getArguments()); - - $this->assertSame($def, $def->replaceArgument(0, 'moo')); - $this->assertSame(['moo'], $def->getArguments()); - - $def->addArgument('moo'); - $def - ->replaceArgument(0, 'foo') - ->replaceArgument(1, 'bar') - ; - $this->assertSame(['foo', 'bar'], $def->getArguments()); - } - - public function testGetArgumentShouldCheckBounds() - { - $this->expectException('OutOfBoundsException'); - $def = new Definition('stdClass'); - - $def->addArgument('foo'); - $def->getArgument(1); - } - - public function testReplaceArgumentShouldCheckBounds() - { - $this->expectException('OutOfBoundsException'); - $this->expectExceptionMessage('The index "1" is not in the range [0, 0].'); - $def = new Definition('stdClass'); - - $def->addArgument('foo'); - $def->replaceArgument(1, 'bar'); - } - - public function testReplaceArgumentWithoutExistingArgumentsShouldCheckBounds() - { - $this->expectException('OutOfBoundsException'); - $this->expectExceptionMessage('Cannot replace arguments if none have been configured yet.'); - $def = new Definition('stdClass'); - $def->replaceArgument(0, 'bar'); - } - - public function testSetGetProperties() - { - $def = new Definition('stdClass'); - - $this->assertEquals([], $def->getProperties()); - $this->assertSame($def, $def->setProperties(['foo' => 'bar'])); - $this->assertEquals(['foo' => 'bar'], $def->getProperties()); - } - - public function testSetProperty() - { - $def = new Definition('stdClass'); - - $this->assertEquals([], $def->getProperties()); - $this->assertSame($def, $def->setProperty('foo', 'bar')); - $this->assertEquals(['foo' => 'bar'], $def->getProperties()); - } - - public function testAutowired() - { - $def = new Definition('stdClass'); - $this->assertFalse($def->isAutowired()); - - $def->setAutowired(true); - $this->assertTrue($def->isAutowired()); - - $def->setAutowired(false); - $this->assertFalse($def->isAutowired()); - } - - public function testChangesNoChanges() - { - $def = new Definition(); - - $this->assertSame([], $def->getChanges()); - } - - public function testGetChangesWithChanges() - { - $def = new Definition('stdClass', ['fooarg']); - - $def->setAbstract(true); - $def->setAutowired(true); - $def->setConfigurator('configuration_func'); - $def->setDecoratedService(null); - $def->setDeprecated(true); - $def->setFactory('factory_func'); - $def->setFile('foo.php'); - $def->setLazy(true); - $def->setPublic(true); - $def->setShared(true); - $def->setSynthetic(true); - // changes aren't tracked for these, class or arguments - $def->setInstanceofConditionals([]); - $def->addTag('foo_tag'); - $def->addMethodCall('methodCall'); - $def->setProperty('fooprop', true); - $def->setAutoconfigured(true); - - $this->assertSame([ - 'class' => true, - 'autowired' => true, - 'configurator' => true, - 'decorated_service' => true, - 'deprecated' => true, - 'factory' => true, - 'file' => true, - 'lazy' => true, - 'public' => true, - 'shared' => true, - 'autoconfigured' => true, - ], $def->getChanges()); - - $def->setChanges([]); - $this->assertSame([], $def->getChanges()); - } - - /** - * @group legacy - */ - public function testTypes() - { - $def = new Definition('stdClass'); - - $this->assertEquals([], $def->getAutowiringTypes()); - $this->assertSame($def, $def->setAutowiringTypes(['Foo'])); - $this->assertEquals(['Foo'], $def->getAutowiringTypes()); - $this->assertSame($def, $def->addAutowiringType('Bar')); - $this->assertTrue($def->hasAutowiringType('Bar')); - $this->assertSame($def, $def->removeAutowiringType('Foo')); - $this->assertEquals(['Bar'], $def->getAutowiringTypes()); - } - - public function testShouldAutoconfigure() - { - $def = new Definition('stdClass'); - $this->assertFalse($def->isAutoconfigured()); - $def->setAutoconfigured(true); - $this->assertTrue($def->isAutoconfigured()); - } - - public function testAddError() - { - $def = new Definition('stdClass'); - $this->assertEmpty($def->getErrors()); - $def->addError('First error'); - $def->addError('Second error'); - $this->assertSame(['First error', 'Second error'], $def->getErrors()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Dumper/GraphvizDumperTest.php b/vendor/symfony/dependency-injection/Tests/Dumper/GraphvizDumperTest.php deleted file mode 100644 index ea11c7c5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Dumper/GraphvizDumperTest.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Dumper; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Dumper\GraphvizDumper; -use Symfony\Component\DependencyInjection\Reference; - -class GraphvizDumperTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = __DIR__.'/../Fixtures/'; - } - - public function testDump() - { - $dumper = new GraphvizDumper($container = new ContainerBuilder()); - - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services1.dot', $dumper->dump(), '->dump() dumps an empty container as an empty dot file'); - - $container = include self::$fixturesPath.'/containers/container9.php'; - $dumper = new GraphvizDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services9.dot', $dumper->dump(), '->dump() dumps services'); - - $container = include self::$fixturesPath.'/containers/container10.php'; - $dumper = new GraphvizDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services10.dot', $dumper->dump(), '->dump() dumps services'); - - $container = include self::$fixturesPath.'/containers/container10.php'; - $dumper = new GraphvizDumper($container); - $this->assertEquals($dumper->dump([ - 'graph' => ['ratio' => 'normal'], - 'node' => ['fontsize' => 13, 'fontname' => 'Verdana', 'shape' => 'square'], - 'edge' => ['fontsize' => 12, 'fontname' => 'Verdana', 'color' => 'white', 'arrowhead' => 'closed', 'arrowsize' => 1], - 'node.instance' => ['fillcolor' => 'green', 'style' => 'empty'], - 'node.definition' => ['fillcolor' => 'grey'], - 'node.missing' => ['fillcolor' => 'red', 'style' => 'empty'], - ]), file_get_contents(self::$fixturesPath.'/graphviz/services10-1.dot'), '->dump() dumps services'); - } - - public function testDumpWithFrozenContainer() - { - $container = include self::$fixturesPath.'/containers/container13.php'; - $dumper = new GraphvizDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services13.dot', $dumper->dump(), '->dump() dumps services'); - } - - public function testDumpWithFrozenCustomClassContainer() - { - $container = include self::$fixturesPath.'/containers/container14.php'; - $dumper = new GraphvizDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services14.dot', $dumper->dump(), '->dump() dumps services'); - } - - public function testDumpWithUnresolvedParameter() - { - $container = include self::$fixturesPath.'/containers/container17.php'; - $dumper = new GraphvizDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services17.dot', $dumper->dump(), '->dump() dumps services'); - } - - public function testDumpWithInlineDefinition() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->addArgument( - (new Definition('stdClass'))->addArgument(new Reference('bar')) - ); - $container->register('bar', 'stdClass'); - $dumper = new GraphvizDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/graphviz/services_inline.dot', $dumper->dump(), '->dump() dumps nested references'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Dumper/PhpDumperTest.php b/vendor/symfony/dependency-injection/Tests/Dumper/PhpDumperTest.php deleted file mode 100644 index 946d09c7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Dumper/PhpDumperTest.php +++ /dev/null @@ -1,1184 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Dumper; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\ChildDefinition; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Dumper\PhpDumper; -use Symfony\Component\DependencyInjection\EnvVarProcessorInterface; -use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\DependencyInjection\Parameter; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; -use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory; -use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator; -use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber; -use Symfony\Component\DependencyInjection\TypedReference; -use Symfony\Component\DependencyInjection\Variable; -use Symfony\Component\ExpressionLanguage\Expression; - -require_once __DIR__.'/../Fixtures/includes/classes.php'; - -class PhpDumperTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - } - - public function testDump() - { - $container = new ContainerBuilder(); - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services1.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class'); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services1-1.php', $dumper->dump(['class' => 'Container', 'base_class' => 'AbstractContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Dump']), '->dump() takes a class and a base_class options'); - } - - public function testDumpOptimizationString() - { - $definition = new Definition(); - $definition->setClass('stdClass'); - $definition->addArgument([ - 'only dot' => '.', - 'concatenation as value' => '.\'\'.', - 'concatenation from the start value' => '\'\'.', - '.' => 'dot as a key', - '.\'\'.' => 'concatenation as a key', - '\'\'.' => 'concatenation from the start key', - 'optimize concatenation' => 'string1%some_string%string2', - 'optimize concatenation with empty string' => 'string1%empty_value%string2', - 'optimize concatenation from the start' => '%empty_value%start', - 'optimize concatenation at the end' => 'end%empty_value%', - 'new line' => "string with \nnew line", - ]); - $definition->setPublic(true); - - $container = new ContainerBuilder(); - $container->setResourceTracking(false); - $container->setDefinition('test', $definition); - $container->setParameter('empty_value', ''); - $container->setParameter('some_string', '-'); - $container->compile(); - - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services10.php', $dumper->dump(), '->dump() dumps an empty container as an empty PHP class'); - } - - public function testDumpRelativeDir() - { - $definition = new Definition(); - $definition->setClass('stdClass'); - $definition->addArgument('%foo%'); - $definition->addArgument(['%foo%' => '%buz%/']); - $definition->setPublic(true); - - $container = new ContainerBuilder(); - $container->setDefinition('test', $definition); - $container->setParameter('foo', 'file://'.\dirname(__DIR__)); - $container->setParameter('bar', __DIR__); - $container->setParameter('baz', '%bar%/PhpDumperTest.php'); - $container->setParameter('buz', \dirname(\dirname(__DIR__))); - $container->compile(); - - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services12.php', $dumper->dump(['file' => __FILE__]), '->dump() dumps __DIR__ relative strings'); - } - - public function testDumpCustomContainerClassWithoutConstructor() - { - $container = new ContainerBuilder(); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_without_constructor.php', $dumper->dump(['base_class' => 'NoConstructorContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'])); - } - - public function testDumpCustomContainerClassConstructorWithoutArguments() - { - $container = new ContainerBuilder(); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_constructor_without_arguments.php', $dumper->dump(['base_class' => 'ConstructorWithoutArgumentsContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'])); - } - - public function testDumpCustomContainerClassWithOptionalArgumentLessConstructor() - { - $container = new ContainerBuilder(); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_with_optional_constructor_arguments.php', $dumper->dump(['base_class' => 'ConstructorWithOptionalArgumentsContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'])); - } - - public function testDumpCustomContainerClassWithMandatoryArgumentLessConstructor() - { - $container = new ContainerBuilder(); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_with_mandatory_constructor_arguments.php', $dumper->dump(['base_class' => 'ConstructorWithMandatoryArgumentsContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'])); - } - - /** - * @dataProvider provideInvalidParameters - */ - public function testExportParameters($parameters) - { - $this->expectException('InvalidArgumentException'); - $container = new ContainerBuilder(new ParameterBag($parameters)); - $container->compile(); - $dumper = new PhpDumper($container); - $dumper->dump(); - } - - public function provideInvalidParameters() - { - return [ - [['foo' => new Definition('stdClass')]], - [['foo' => new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')]], - [['foo' => new Reference('foo')]], - [['foo' => new Variable('foo')]], - ]; - } - - public function testAddParameters() - { - $container = include self::$fixturesPath.'/containers/container8.php'; - $container->compile(); - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services8.php', $dumper->dump(), '->dump() dumps parameters'); - } - - /** - * @group legacy - * @expectedDeprecation Dumping an uncompiled ContainerBuilder is deprecated since Symfony 3.3 and will not be supported anymore in 4.0. Compile the container beforehand. - */ - public function testAddServiceWithoutCompilation() - { - $container = include self::$fixturesPath.'/containers/container9.php'; - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services9.php', str_replace(str_replace('\\', '\\\\', self::$fixturesPath.\DIRECTORY_SEPARATOR.'includes'.\DIRECTORY_SEPARATOR), '%path%', $dumper->dump()), '->dump() dumps services'); - } - - public function testAddService() - { - $container = include self::$fixturesPath.'/containers/container9.php'; - $container->compile(); - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services9_compiled.php', str_replace(str_replace('\\', '\\\\', self::$fixturesPath.\DIRECTORY_SEPARATOR.'includes'.\DIRECTORY_SEPARATOR), '%path%', $dumper->dump()), '->dump() dumps services'); - - $container = new ContainerBuilder(); - $container->register('foo', 'FooClass')->addArgument(new \stdClass())->setPublic(true); - $container->compile(); - $dumper = new PhpDumper($container); - try { - $dumper->dump(); - $this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - } catch (\Exception $e) { - $this->assertInstanceOf('\Symfony\Component\DependencyInjection\Exception\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - $this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - } - } - - public function testDumpAsFiles() - { - $container = include self::$fixturesPath.'/containers/container9.php'; - $container->getDefinition('bar')->addTag('hot'); - $container->compile(); - $dumper = new PhpDumper($container); - $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__, 'hot_path_tag' => 'hot']), true); - if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace('\\\\Fixtures\\\\includes\\\\foo.php', '/Fixtures/includes/foo.php', $dump); - } - $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_as_files.txt', $dump); - } - - public function testServicesWithAnonymousFactories() - { - $container = include self::$fixturesPath.'/containers/container19.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services19.php', $dumper->dump(), '->dump() dumps services with anonymous factories'); - } - - public function testAddServiceIdWithUnsupportedCharacters() - { - $class = 'Symfony_DI_PhpDumper_Test_Unsupported_Characters'; - $container = new ContainerBuilder(); - $container->setParameter("'", 'oh-no'); - $container->register('foo*/oh-no', 'FooClass')->setPublic(true); - $container->register('bar$', 'FooClass')->setPublic(true); - $container->register('bar$!', 'FooClass')->setPublic(true); - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_unsupported_characters.php', $dumper->dump(['class' => $class])); - - require_once self::$fixturesPath.'/php/services_unsupported_characters.php'; - - $this->assertTrue(method_exists($class, 'getFooOhNoService')); - $this->assertTrue(method_exists($class, 'getBarService')); - $this->assertTrue(method_exists($class, 'getBar2Service')); - } - - public function testConflictingServiceIds() - { - $class = 'Symfony_DI_PhpDumper_Test_Conflicting_Service_Ids'; - $container = new ContainerBuilder(); - $container->register('foo_bar', 'FooClass')->setPublic(true); - $container->register('foobar', 'FooClass')->setPublic(true); - $container->compile(); - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => $class])); - - $this->assertTrue(method_exists($class, 'getFooBarService')); - $this->assertTrue(method_exists($class, 'getFoobar2Service')); - } - - public function testConflictingMethodsWithParent() - { - $class = 'Symfony_DI_PhpDumper_Test_Conflicting_Method_With_Parent'; - $container = new ContainerBuilder(); - $container->register('bar', 'FooClass')->setPublic(true); - $container->register('foo_bar', 'FooClass')->setPublic(true); - $container->compile(); - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump([ - 'class' => $class, - 'base_class' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\containers\CustomContainer', - ])); - - $this->assertTrue(method_exists($class, 'getBar2Service')); - $this->assertTrue(method_exists($class, 'getFoobar2Service')); - } - - /** - * @dataProvider provideInvalidFactories - */ - public function testInvalidFactories($factory) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Cannot dump definition'); - $container = new ContainerBuilder(); - $def = new Definition('stdClass'); - $def->setPublic(true); - $def->setFactory($factory); - $container->setDefinition('bar', $def); - $container->compile(); - $dumper = new PhpDumper($container); - $dumper->dump(); - } - - public function provideInvalidFactories() - { - return [ - [['', 'method']], - [['class', '']], - [['...', 'method']], - [['class', '...']], - ]; - } - - public function testAliases() - { - $container = include self::$fixturesPath.'/containers/container9.php'; - $container->setParameter('foo_bar', 'foo_bar'); - $container->compile(); - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Aliases'])); - - $container = new \Symfony_DI_PhpDumper_Test_Aliases(); - $foo = $container->get('foo'); - $this->assertSame($foo, $container->get('alias_for_foo')); - $this->assertSame($foo, $container->get('alias_for_alias')); - } - - public function testFrozenContainerWithoutAliases() - { - $container = new ContainerBuilder(); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Frozen_No_Aliases'])); - - $container = new \Symfony_DI_PhpDumper_Test_Frozen_No_Aliases(); - $this->assertFalse($container->has('foo')); - } - - /** - * @group legacy - * @expectedDeprecation The "decorator_service" service is already initialized, replacing it is deprecated since Symfony 3.3 and will fail in 4.0. - */ - public function testOverrideServiceWhenUsingADumpedContainer() - { - require_once self::$fixturesPath.'/php/services9_compiled.php'; - - $container = new \ProjectServiceContainer(); - $container->get('decorator_service'); - $container->set('decorator_service', $decorator = new \stdClass()); - - $this->assertSame($decorator, $container->get('decorator_service'), '->set() overrides an already defined service'); - } - - public function testDumpAutowireData() - { - $container = include self::$fixturesPath.'/containers/container24.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services24.php', $dumper->dump()); - } - - public function testEnvInId() - { - $container = include self::$fixturesPath.'/containers/container_env_in_id.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_env_in_id.php', $dumper->dump()); - } - - public function testEnvParameter() - { - $rand = mt_rand(); - putenv('Baz='.$rand); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services26.yml'); - $container->setParameter('env(json_file)', self::$fixturesPath.'/array.json'); - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services26.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_EnvParameters', 'file' => self::$fixturesPath.'/php/services26.php'])); - - require self::$fixturesPath.'/php/services26.php'; - $container = new \Symfony_DI_PhpDumper_Test_EnvParameters(); - $this->assertSame($rand, $container->getParameter('baz')); - $this->assertSame([123, 'abc'], $container->getParameter('json')); - $this->assertSame('sqlite:///foo/bar/var/data.db', $container->getParameter('db_dsn')); - putenv('Baz'); - } - - public function testResolvedBase64EnvParameters() - { - $container = new ContainerBuilder(); - $container->setParameter('env(foo)', base64_encode('world')); - $container->setParameter('hello', '%env(base64:foo)%'); - $container->compile(true); - - $expected = [ - 'env(foo)' => 'd29ybGQ=', - 'hello' => 'world', - ]; - $this->assertSame($expected, $container->getParameterBag()->all()); - } - - public function testDumpedBase64EnvParameters() - { - $container = new ContainerBuilder(); - $container->setParameter('env(foo)', base64_encode('world')); - $container->setParameter('hello', '%env(base64:foo)%'); - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->dump(); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_base64_env.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Base64Parameters'])); - - require self::$fixturesPath.'/php/services_base64_env.php'; - $container = new \Symfony_DI_PhpDumper_Test_Base64Parameters(); - $this->assertSame('world', $container->getParameter('hello')); - } - - public function testCustomEnvParameters() - { - $container = new ContainerBuilder(); - $container->setParameter('env(foo)', str_rot13('world')); - $container->setParameter('hello', '%env(rot13:foo)%'); - $container->register(Rot13EnvVarProcessor::class)->addTag('container.env_var_processor')->setPublic(true); - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->dump(); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_rot13_env.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Rot13Parameters'])); - - require self::$fixturesPath.'/php/services_rot13_env.php'; - $container = new \Symfony_DI_PhpDumper_Test_Rot13Parameters(); - $this->assertSame('world', $container->getParameter('hello')); - } - - public function testFileEnvProcessor() - { - $container = new ContainerBuilder(); - $container->setParameter('env(foo)', __FILE__); - $container->setParameter('random', '%env(file:foo)%'); - $container->compile(true); - - $this->assertStringEqualsFile(__FILE__, $container->getParameter('random')); - } - - public function testUnusedEnvParameter() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\EnvParameterException'); - $this->expectExceptionMessage('Environment variables "FOO" are never used. Please, check your container\'s configuration.'); - $container = new ContainerBuilder(); - $container->getParameter('env(FOO)'); - $container->compile(); - $dumper = new PhpDumper($container); - $dumper->dump(); - } - - public function testCircularDynamicEnv() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException'); - $this->expectExceptionMessage('Circular reference detected for parameter "env(resolve:DUMMY_ENV_VAR)" ("env(resolve:DUMMY_ENV_VAR)" > "env(resolve:DUMMY_ENV_VAR)").'); - $container = new ContainerBuilder(); - $container->setParameter('foo', '%bar%'); - $container->setParameter('bar', '%env(resolve:DUMMY_ENV_VAR)%'); - $container->compile(); - - $dumper = new PhpDumper($container); - $dump = $dumper->dump(['class' => $class = __FUNCTION__]); - - eval('?>'.$dump); - $container = new $class(); - - putenv('DUMMY_ENV_VAR=%foo%'); - try { - $container->getParameter('bar'); - } finally { - putenv('DUMMY_ENV_VAR'); - } - } - - public function testInlinedDefinitionReferencingServiceContainer() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->addMethodCall('add', [new Reference('service_container')])->setPublic(false); - $container->register('bar', 'stdClass')->addArgument(new Reference('foo'))->setPublic(true); - $container->compile(); - - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services13.php', $dumper->dump(), '->dump() dumps inline definitions which reference service_container'); - } - - public function testNonSharedLazyDefinitionReferences() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setShared(false)->setLazy(true); - $container->register('bar', 'stdClass')->addArgument(new Reference('foo', ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, false)); - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->setProxyDumper(new \DummyProxyDumper()); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_non_shared_lazy.php', $dumper->dump()); - } - - public function testInitializePropertiesBeforeMethodCalls() - { - require_once self::$fixturesPath.'/includes/classes.php'; - - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setPublic(true); - $container->register('bar', 'MethodCallClass') - ->setPublic(true) - ->setProperty('simple', 'bar') - ->setProperty('complex', new Reference('foo')) - ->addMethodCall('callMe'); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls'])); - - $container = new \Symfony_DI_PhpDumper_Test_Properties_Before_Method_Calls(); - $this->assertTrue($container->get('bar')->callPassed(), '->dump() initializes properties before method calls'); - } - - public function testCircularReferenceAllowanceForLazyServices() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->addArgument(new Reference('bar'))->setPublic(true); - $container->register('bar', 'stdClass')->setLazy(true)->addArgument(new Reference('foo'))->setPublic(true); - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->setProxyDumper(new \DummyProxyDumper()); - $dumper->dump(); - - $this->addToAssertionCount(1); - - $dumper = new PhpDumper($container); - - $message = 'Circular reference detected for service "foo", path: "foo -> bar -> foo". Try running "composer require symfony/proxy-manager-bridge".'; - $this->expectException(ServiceCircularReferenceException::class); - $this->expectExceptionMessage($message); - - $dumper->dump(); - } - - public function testDedupLazyProxy() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setLazy(true)->setPublic(true); - $container->register('bar', 'stdClass')->setLazy(true)->setPublic(true); - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->setProxyDumper(new \DummyProxyDumper()); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_dedup_lazy_proxy.php', $dumper->dump()); - } - - public function testLazyArgumentProvideGenerator() - { - require_once self::$fixturesPath.'/includes/classes.php'; - - $container = new ContainerBuilder(); - $container->register('lazy_referenced', 'stdClass')->setPublic(true); - $container - ->register('lazy_context', 'LazyContext') - ->setPublic(true) - ->setArguments([ - new IteratorArgument(['k1' => new Reference('lazy_referenced'), 'k2' => new Reference('service_container')]), - new IteratorArgument([]), - ]) - ; - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Lazy_Argument_Provide_Generator'])); - - $container = new \Symfony_DI_PhpDumper_Test_Lazy_Argument_Provide_Generator(); - $lazyContext = $container->get('lazy_context'); - - $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyValues); - $this->assertInstanceOf(RewindableGenerator::class, $lazyContext->lazyEmptyValues); - $this->assertCount(2, $lazyContext->lazyValues); - $this->assertCount(0, $lazyContext->lazyEmptyValues); - - $i = -1; - foreach ($lazyContext->lazyValues as $k => $v) { - switch (++$i) { - case 0: - $this->assertEquals('k1', $k); - $this->assertInstanceOf('stdCLass', $v); - break; - case 1: - $this->assertEquals('k2', $k); - $this->assertInstanceOf('Symfony_DI_PhpDumper_Test_Lazy_Argument_Provide_Generator', $v); - break; - } - } - - $this->assertEmpty(iterator_to_array($lazyContext->lazyEmptyValues)); - } - - public function testNormalizedId() - { - $container = include self::$fixturesPath.'/containers/container33.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services33.php', $dumper->dump()); - } - - public function testDumpContainerBuilderWithFrozenConstructorIncludingPrivateServices() - { - $container = new ContainerBuilder(); - $container->register('foo_service', 'stdClass')->setArguments([new Reference('baz_service')])->setPublic(true); - $container->register('bar_service', 'stdClass')->setArguments([new Reference('baz_service')])->setPublic(true); - $container->register('baz_service', 'stdClass')->setPublic(false); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_private_frozen.php', $dumper->dump()); - } - - public function testServiceLocator() - { - $container = new ContainerBuilder(); - $container->register('foo_service', ServiceLocator::class) - ->setPublic(true) - ->addArgument([ - 'bar' => new ServiceClosureArgument(new Reference('bar_service')), - 'baz' => new ServiceClosureArgument(new TypedReference('baz_service', 'stdClass')), - 'nil' => $nil = new ServiceClosureArgument(new Reference('nil')), - ]) - ; - - // no method calls - $container->register('translator.loader_1', 'stdClass')->setPublic(true); - $container->register('translator.loader_1_locator', ServiceLocator::class) - ->setPublic(false) - ->addArgument([ - 'translator.loader_1' => new ServiceClosureArgument(new Reference('translator.loader_1')), - ]); - $container->register('translator_1', StubbedTranslator::class) - ->setPublic(true) - ->addArgument(new Reference('translator.loader_1_locator')); - - // one method calls - $container->register('translator.loader_2', 'stdClass')->setPublic(true); - $container->register('translator.loader_2_locator', ServiceLocator::class) - ->setPublic(false) - ->addArgument([ - 'translator.loader_2' => new ServiceClosureArgument(new Reference('translator.loader_2')), - ]); - $container->register('translator_2', StubbedTranslator::class) - ->setPublic(true) - ->addArgument(new Reference('translator.loader_2_locator')) - ->addMethodCall('addResource', ['db', new Reference('translator.loader_2'), 'nl']); - - // two method calls - $container->register('translator.loader_3', 'stdClass')->setPublic(true); - $container->register('translator.loader_3_locator', ServiceLocator::class) - ->setPublic(false) - ->addArgument([ - 'translator.loader_3' => new ServiceClosureArgument(new Reference('translator.loader_3')), - ]); - $container->register('translator_3', StubbedTranslator::class) - ->setPublic(true) - ->addArgument(new Reference('translator.loader_3_locator')) - ->addMethodCall('addResource', ['db', new Reference('translator.loader_3'), 'nl']) - ->addMethodCall('addResource', ['db', new Reference('translator.loader_3'), 'en']); - - $nil->setValues([null]); - $container->register('bar_service', 'stdClass')->setArguments([new Reference('baz_service')])->setPublic(true); - $container->register('baz_service', 'stdClass')->setPublic(false); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_locator.php', $dumper->dump()); - } - - public function testServiceSubscriber() - { - $container = new ContainerBuilder(); - $container->register('foo_service', TestServiceSubscriber::class) - ->setPublic(true) - ->setAutowired(true) - ->addArgument(new Reference(ContainerInterface::class)) - ->addTag('container.service_subscriber', [ - 'key' => 'bar', - 'id' => TestServiceSubscriber::class, - ]) - ; - $container->register(TestServiceSubscriber::class, TestServiceSubscriber::class)->setPublic(true); - - $container->register(CustomDefinition::class, CustomDefinition::class) - ->setPublic(false); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_subscriber.php', $dumper->dump()); - } - - public function testPrivateWithIgnoreOnInvalidReference() - { - require_once self::$fixturesPath.'/includes/classes.php'; - - $container = new ContainerBuilder(); - $container->register('not_invalid', 'BazClass') - ->setPublic(false); - $container->register('bar', 'BarClass') - ->setPublic(true) - ->addMethodCall('setBaz', [new Reference('not_invalid', SymfonyContainerInterface::IGNORE_ON_INVALID_REFERENCE)]); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Private_With_Ignore_On_Invalid_Reference'])); - - $container = new \Symfony_DI_PhpDumper_Test_Private_With_Ignore_On_Invalid_Reference(); - $this->assertInstanceOf('BazClass', $container->get('bar')->getBaz()); - } - - public function testArrayParameters() - { - $container = new ContainerBuilder(); - $container->setParameter('array_1', [123]); - $container->setParameter('array_2', [__DIR__]); - $container->register('bar', 'BarClass') - ->setPublic(true) - ->addMethodCall('setBaz', ['%array_1%', '%array_2%', '%%array_1%%', [123]]); - $container->compile(); - - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_array_params.php', str_replace('\\\\Dumper', '/Dumper', $dumper->dump(['file' => self::$fixturesPath.'/php/services_array_params.php']))); - } - - public function testExpressionReferencingPrivateService() - { - $container = new ContainerBuilder(); - $container->register('private_bar', 'stdClass') - ->setPublic(false); - $container->register('private_foo', 'stdClass') - ->setPublic(false); - $container->register('public_foo', 'stdClass') - ->setPublic(true) - ->addArgument(new Expression('service("private_foo").bar')); - - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_private_in_expression.php', $dumper->dump()); - } - - public function testUninitializedReference() - { - $container = include self::$fixturesPath.'/containers/container_uninitialized_ref.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_uninitialized_ref.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Uninitialized_Reference'])); - - require self::$fixturesPath.'/php/services_uninitialized_ref.php'; - - $container = new \Symfony_DI_PhpDumper_Test_Uninitialized_Reference(); - - $bar = $container->get('bar'); - - $this->assertNull($bar->foo1); - $this->assertNull($bar->foo2); - $this->assertNull($bar->foo3); - $this->assertNull($bar->closures[0]()); - $this->assertNull($bar->closures[1]()); - $this->assertNull($bar->closures[2]()); - $this->assertSame([], iterator_to_array($bar->iter)); - - $container = new \Symfony_DI_PhpDumper_Test_Uninitialized_Reference(); - - $container->get('foo1'); - $container->get('baz'); - - $bar = $container->get('bar'); - - $this->assertEquals(new \stdClass(), $bar->foo1); - $this->assertNull($bar->foo2); - $this->assertEquals(new \stdClass(), $bar->foo3); - $this->assertEquals(new \stdClass(), $bar->closures[0]()); - $this->assertNull($bar->closures[1]()); - $this->assertEquals(new \stdClass(), $bar->closures[2]()); - $this->assertEquals(['foo1' => new \stdClass(), 'foo3' => new \stdClass()], iterator_to_array($bar->iter)); - } - - /** - * @dataProvider provideAlmostCircular - */ - public function testAlmostCircular($visibility) - { - $container = include self::$fixturesPath.'/containers/container_almost_circular.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $container = 'Symfony_DI_PhpDumper_Test_Almost_Circular_'.ucfirst($visibility); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_almost_circular_'.$visibility.'.php', $dumper->dump(['class' => $container])); - - require self::$fixturesPath.'/php/services_almost_circular_'.$visibility.'.php'; - - $container = new $container(); - - $foo = $container->get('foo'); - $this->assertSame($foo, $foo->bar->foobar->foo); - - $foo2 = $container->get('foo2'); - $this->assertSame($foo2, $foo2->bar->foobar->foo); - - $this->assertSame([], (array) $container->get('foobar4')); - - $foo5 = $container->get('foo5'); - $this->assertSame($foo5, $foo5->bar->foo); - - $manager = $container->get('manager'); - $this->assertEquals(new \stdClass(), $manager); - - $manager = $container->get('manager2'); - $this->assertEquals(new \stdClass(), $manager); - - $foo6 = $container->get('foo6'); - $this->assertEquals((object) ['bar6' => (object) []], $foo6); - - $this->assertInstanceOf(\stdClass::class, $container->get('root')); - - $manager3 = $container->get('manager3'); - $listener3 = $container->get('listener3'); - $this->assertSame($manager3, $listener3->manager); - - $listener4 = $container->get('listener4'); - $this->assertInstanceOf('stdClass', $listener4); - } - - public function provideAlmostCircular() - { - yield ['public']; - yield ['private']; - } - - public function testDeepServiceGraph() - { - $container = new ContainerBuilder(); - - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_deep_graph.yml'); - - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->dump(); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_deep_graph.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Deep_Graph'])); - - require self::$fixturesPath.'/php/services_deep_graph.php'; - - $container = new \Symfony_DI_PhpDumper_Test_Deep_Graph(); - - $this->assertInstanceOf(FooForDeepGraph::class, $container->get('foo')); - $this->assertEquals((object) ['p2' => (object) ['p3' => (object) []]], $container->get('foo')->bClone); - } - - public function testInlineSelfRef() - { - $container = new ContainerBuilder(); - - $bar = (new Definition('App\Bar')) - ->setProperty('foo', new Reference('App\Foo')); - - $baz = (new Definition('App\Baz')) - ->setProperty('bar', $bar) - ->addArgument($bar); - - $container->register('App\Foo') - ->setPublic(true) - ->addArgument($baz); - - $container->getCompiler()->getPassConfig(); - $container->compile(); - - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_self_ref.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Inline_Self_Ref'])); - } - - public function testHotPathOptimizations() - { - $container = include self::$fixturesPath.'/containers/container_inline_requires.php'; - $container->setParameter('inline_requires', true); - $container->compile(); - $dumper = new PhpDumper($container); - - $dump = $dumper->dump(['hot_path_tag' => 'container.hot_path', 'inline_class_loader_parameter' => 'inline_requires', 'file' => self::$fixturesPath.'/php/services_inline_requires.php']); - if ('\\' === \DIRECTORY_SEPARATOR) { - $dump = str_replace("'\\\\includes\\\\HotPath\\\\", "'/includes/HotPath/", $dump); - } - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_requires.php', $dump); - } - - public function testDumpHandlesLiteralClassWithRootNamespace() - { - $container = new ContainerBuilder(); - $container->register('foo', '\\stdClass')->setPublic(true); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Literal_Class_With_Root_Namespace'])); - - $container = new \Symfony_DI_PhpDumper_Test_Literal_Class_With_Root_Namespace(); - - $this->assertInstanceOf('stdClass', $container->get('foo')); - } - - public function testDumpHandlesObjectClassNames() - { - $container = new ContainerBuilder(new ParameterBag([ - 'class' => 'stdClass', - ])); - - $container->setDefinition('foo', new Definition(new Parameter('class'))); - $container->setDefinition('bar', new Definition('stdClass', [ - new Reference('foo'), - ]))->setPublic(true); - - $container->setParameter('inline_requires', true); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump([ - 'class' => 'Symfony_DI_PhpDumper_Test_Object_Class_Name', - 'inline_class_loader_parameter' => 'inline_requires', - ])); - - $container = new \Symfony_DI_PhpDumper_Test_Object_Class_Name(); - - $this->assertInstanceOf('stdClass', $container->get('bar')); - } - - public function testUninitializedSyntheticReference() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setPublic(true)->setSynthetic(true); - $container->register('bar', 'stdClass')->setPublic(true)->setShared(false) - ->setProperty('foo', new Reference('foo', ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE)); - - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump([ - 'class' => 'Symfony_DI_PhpDumper_Test_UninitializedSyntheticReference', - 'inline_class_loader_parameter' => 'inline_requires', - ])); - - $container = new \Symfony_DI_PhpDumper_Test_UninitializedSyntheticReference(); - - $this->assertEquals((object) ['foo' => null], $container->get('bar')); - - $container->set('foo', (object) [123]); - $this->assertEquals((object) ['foo' => (object) [123]], $container->get('bar')); - } - - public function testAdawsonContainer() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_adawson.yml'); - $container->compile(); - - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_adawson.php', $dumper->dump()); - } - - /** - * @group legacy - * @expectedDeprecation The "private" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "private_alias" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "decorated_private" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "decorated_private_alias" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "private_not_inlined" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "private_not_removed" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "private_child" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - * @expectedDeprecation The "private_parent" service is private, getting it from the container is deprecated since Symfony 3.2 and will fail in 4.0. You should either make the service public, or stop using the container directly and use dependency injection instead. - */ - public function testLegacyPrivateServices() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_legacy_privates.yml'); - - $container->setDefinition('private_child', new ChildDefinition('foo')); - $container->setDefinition('private_parent', new ChildDefinition('private')); - - $container->getDefinition('private')->setPrivate(true); - $container->getDefinition('private_not_inlined')->setPrivate(true); - $container->getDefinition('private_not_removed')->setPrivate(true); - $container->getDefinition('decorated_private')->setPrivate(true); - $container->getDefinition('private_child')->setPrivate(true); - $container->getAlias('decorated_private_alias')->setPrivate(true); - $container->getAlias('private_alias')->setPrivate(true); - - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_legacy_privates.php', $dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Legacy_Privates', 'file' => self::$fixturesPath.'/php/services_legacy_privates.php'])); - - require self::$fixturesPath.'/php/services_legacy_privates.php'; - - $container = new \Symfony_DI_PhpDumper_Test_Legacy_Privates(); - - $container->get('private'); - $container->get('private_alias'); - $container->get('alias_to_private'); - $container->get('decorated_private'); - $container->get('decorated_private_alias'); - $container->get('private_not_inlined'); - $container->get('private_not_removed'); - $container->get('private_child'); - $container->get('private_parent'); - $container->get('public_child'); - } - - /** - * This test checks the trigger of a deprecation note and should not be removed in major releases. - * - * @group legacy - * @expectedDeprecation The "foo" service is deprecated. You should stop using it, as it will soon be removed. - */ - public function testPrivateServiceTriggersDeprecation() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass') - ->setPublic(false) - ->setDeprecated(true); - $container->register('bar', 'stdClass') - ->setPublic(true) - ->setProperty('foo', new Reference('foo')); - - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Private_Service_Triggers_Deprecation'])); - - $container = new \Symfony_DI_PhpDumper_Test_Private_Service_Triggers_Deprecation(); - - $container->get('bar'); - } - - /** - * @group legacy - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "foo" instead of "Foo" is deprecated since Symfony 3.4. - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "Foo" is deprecated since Symfony 3.4. - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "bar" instead of "BAR" is deprecated since Symfony 3.4. - */ - public function testParameterWithMixedCase() - { - $container = new ContainerBuilder(new ParameterBag(['Foo' => 'bar', 'BAR' => 'foo'])); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Parameter_With_Mixed_Case'])); - - $container = new \Symfony_DI_PhpDumper_Test_Parameter_With_Mixed_Case(); - - $this->assertSame('bar', $container->getParameter('foo')); - $this->assertSame('bar', $container->getParameter('FOO')); - $this->assertSame('foo', $container->getParameter('bar')); - $this->assertSame('foo', $container->getParameter('BAR')); - } - - /** - * @group legacy - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4. - */ - public function testParameterWithLowerCase() - { - $container = new ContainerBuilder(new ParameterBag(['foo' => 'bar'])); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Parameter_With_Lower_Case'])); - - $container = new \Symfony_DI_PhpDumper_Test_Parameter_With_Lower_Case(); - - $this->assertSame('bar', $container->getParameter('FOO')); - } - - /** - * @group legacy - * @expectedDeprecation Service identifiers will be made case sensitive in Symfony 4.0. Using "foo" instead of "Foo" is deprecated since Symfony 3.3. - * @expectedDeprecation The "Foo" service is deprecated. You should stop using it, as it will soon be removed. - */ - public function testReferenceWithLowerCaseId() - { - $container = new ContainerBuilder(); - $container->register('Bar', 'stdClass')->setProperty('foo', new Reference('foo'))->setPublic(true); - $container->register('Foo', 'stdClass')->setDeprecated(); - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Reference_With_Lower_Case_Id'])); - - $container = new \Symfony_DI_PhpDumper_Test_Reference_With_Lower_Case_Id(); - - $this->assertEquals((object) ['foo' => (object) []], $container->get('Bar')); - } - - public function testScalarService() - { - $container = new ContainerBuilder(); - $container->register('foo', 'string') - ->setPublic(true) - ->setFactory([ScalarFactory::class, 'getSomeValue']) - ; - - $container->compile(); - - $dumper = new PhpDumper($container); - eval('?>'.$dumper->dump(['class' => 'Symfony_DI_PhpDumper_Test_Scalar_Service'])); - - $container = new \Symfony_DI_PhpDumper_Test_Scalar_Service(); - - $this->assertTrue($container->has('foo')); - $this->assertSame('some value', $container->get('foo')); - } - - public function testAliasCanBeFoundInTheDumpedContainerWhenBothTheAliasAndTheServiceArePublic() - { - $container = new ContainerBuilder(); - - $container->register('foo', 'stdClass')->setPublic(true); - $container->setAlias('bar', 'foo')->setPublic(true); - - $container->compile(); - - // Bar is found in the compiled container - $service_ids = $container->getServiceIds(); - $this->assertContains('bar', $service_ids); - - $dumper = new PhpDumper($container); - $dump = $dumper->dump(['class' => 'Symfony_DI_PhpDumper_AliasesCanBeFoundInTheDumpedContainer']); - eval('?>'.$dump); - - $container = new \Symfony_DI_PhpDumper_AliasesCanBeFoundInTheDumpedContainer(); - - // Bar should still be found in the compiled container - $service_ids = $container->getServiceIds(); - $this->assertContains('bar', $service_ids); - } -} - -class Rot13EnvVarProcessor implements EnvVarProcessorInterface -{ - public function getEnv($prefix, $name, \Closure $getEnv) - { - return str_rot13($getEnv($name)); - } - - public static function getProvidedTypes() - { - return ['rot13' => 'string']; - } -} - -class FooForDeepGraph -{ - public $bClone; - - public function __construct(\stdClass $a, \stdClass $b) - { - // clone to verify that $b has been fully initialized before - $this->bClone = clone $b; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Dumper/XmlDumperTest.php b/vendor/symfony/dependency-injection/Tests/Dumper/XmlDumperTest.php deleted file mode 100644 index e660c7e8..00000000 --- a/vendor/symfony/dependency-injection/Tests/Dumper/XmlDumperTest.php +++ /dev/null @@ -1,210 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Dumper; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Dumper\XmlDumper; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Reference; - -class XmlDumperTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - } - - public function testDump() - { - $dumper = new XmlDumper(new ContainerBuilder()); - - $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services1.xml', $dumper->dump(), '->dump() dumps an empty container as an empty XML file'); - } - - public function testExportParameters() - { - $container = include self::$fixturesPath.'//containers/container8.php'; - $dumper = new XmlDumper($container); - $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services8.xml', $dumper->dump(), '->dump() dumps parameters'); - } - - public function testAddParameters() - { - $container = include self::$fixturesPath.'//containers/container8.php'; - $dumper = new XmlDumper($container); - $this->assertXmlStringEqualsXmlFile(self::$fixturesPath.'/xml/services8.xml', $dumper->dump(), '->dump() dumps parameters'); - } - - public function testAddService() - { - $container = include self::$fixturesPath.'/containers/container9.php'; - $dumper = new XmlDumper($container); - - $this->assertEquals(str_replace('%path%', self::$fixturesPath.\DIRECTORY_SEPARATOR.'includes'.\DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/xml/services9.xml')), $dumper->dump(), '->dump() dumps services'); - - $dumper = new XmlDumper($container = new ContainerBuilder()); - $container->register('foo', 'FooClass')->addArgument(new \stdClass())->setPublic(true); - try { - $dumper->dump(); - $this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - } catch (\Exception $e) { - $this->assertInstanceOf('\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - $this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - } - } - - public function testDumpAnonymousServices() - { - $container = include self::$fixturesPath.'/containers/container11.php'; - $dumper = new XmlDumper($container); - $this->assertEquals(' - - - - - - - - - - - - - - - - -', $dumper->dump()); - } - - public function testDumpEntities() - { - $container = include self::$fixturesPath.'/containers/container12.php'; - $dumper = new XmlDumper($container); - $this->assertEquals(" - - - - - - foo<>&bar - - - - - -", $dumper->dump()); - } - - /** - * @dataProvider provideDecoratedServicesData - */ - public function testDumpDecoratedServices($expectedXmlDump, $container) - { - $dumper = new XmlDumper($container); - $this->assertEquals($expectedXmlDump, $dumper->dump()); - } - - public function provideDecoratedServicesData() - { - $fixturesPath = realpath(__DIR__.'/../Fixtures/'); - - return [ - [" - - - - - - - - -", include $fixturesPath.'/containers/container15.php'], - [" - - - - - - - - -", include $fixturesPath.'/containers/container16.php'], - ]; - } - - /** - * @dataProvider provideCompiledContainerData - */ - public function testCompiledContainerCanBeDumped($containerFile) - { - $fixturesPath = __DIR__.'/../Fixtures'; - $container = require $fixturesPath.'/containers/'.$containerFile.'.php'; - $container->compile(); - $dumper = new XmlDumper($container); - $dumper->dump(); - - $this->addToAssertionCount(1); - } - - public function provideCompiledContainerData() - { - return [ - ['container8'], - ['container9'], - ['container11'], - ['container12'], - ['container14'], - ]; - } - - public function testDumpInlinedServices() - { - $container = include self::$fixturesPath.'/containers/container21.php'; - $dumper = new XmlDumper($container); - - $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services21.xml'), $dumper->dump()); - } - - public function testDumpAutowireData() - { - $container = include self::$fixturesPath.'/containers/container24.php'; - $dumper = new XmlDumper($container); - - $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services24.xml'), $dumper->dump()); - } - - public function testDumpLoad() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_dump_load.xml'); - - $this->assertEquals([new Reference('bar', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)], $container->getDefinition('foo')->getArguments()); - - $dumper = new XmlDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_dump_load.xml', $dumper->dump()); - } - - public function testDumpAbstractServices() - { - $container = include self::$fixturesPath.'/containers/container_abstract.php'; - $dumper = new XmlDumper($container); - - $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_abstract.xml'), $dumper->dump()); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Dumper/YamlDumperTest.php b/vendor/symfony/dependency-injection/Tests/Dumper/YamlDumperTest.php deleted file mode 100644 index 49ee8e6f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Dumper/YamlDumperTest.php +++ /dev/null @@ -1,104 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Dumper; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Dumper\YamlDumper; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\Yaml\Parser; -use Symfony\Component\Yaml\Yaml; - -class YamlDumperTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - } - - public function testDump() - { - $dumper = new YamlDumper($container = new ContainerBuilder()); - - $this->assertEqualYamlStructure(file_get_contents(self::$fixturesPath.'/yaml/services1.yml'), $dumper->dump(), '->dump() dumps an empty container as an empty YAML file'); - } - - public function testAddParameters() - { - $container = include self::$fixturesPath.'/containers/container8.php'; - $dumper = new YamlDumper($container); - $this->assertEqualYamlStructure(file_get_contents(self::$fixturesPath.'/yaml/services8.yml'), $dumper->dump(), '->dump() dumps parameters'); - } - - public function testAddService() - { - $container = include self::$fixturesPath.'/containers/container9.php'; - $dumper = new YamlDumper($container); - $this->assertEqualYamlStructure(str_replace('%path%', self::$fixturesPath.\DIRECTORY_SEPARATOR.'includes'.\DIRECTORY_SEPARATOR, file_get_contents(self::$fixturesPath.'/yaml/services9.yml')), $dumper->dump(), '->dump() dumps services'); - - $dumper = new YamlDumper($container = new ContainerBuilder()); - $container->register('foo', 'FooClass')->addArgument(new \stdClass())->setPublic(true); - try { - $dumper->dump(); - $this->fail('->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - } catch (\Exception $e) { - $this->assertInstanceOf('\RuntimeException', $e, '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - $this->assertEquals('Unable to dump a service container if a parameter is an object or a resource.', $e->getMessage(), '->dump() throws a RuntimeException if the container to be dumped has reference to objects or resources'); - } - } - - public function testDumpAutowireData() - { - $container = include self::$fixturesPath.'/containers/container24.php'; - $dumper = new YamlDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services24.yml', $dumper->dump()); - } - - public function testDumpLoad() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_dump_load.yml'); - - $this->assertEquals([new Reference('bar', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE)], $container->getDefinition('foo')->getArguments()); - - $dumper = new YamlDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_dump_load.yml', $dumper->dump()); - } - - public function testInlineServices() - { - $container = new ContainerBuilder(); - $container->register('foo', 'Class1') - ->setPublic(true) - ->addArgument((new Definition('Class2')) - ->addArgument(new Definition('Class2')) - ) - ; - - $dumper = new YamlDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_inline.yml', $dumper->dump()); - } - - private function assertEqualYamlStructure($expected, $yaml, $message = '') - { - $parser = new Parser(); - - $this->assertEquals($parser->parse($expected, Yaml::PARSE_CUSTOM_TAGS), $parser->parse($yaml, Yaml::PARSE_CUSTOM_TAGS), $message); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/EnvVarProcessorTest.php b/vendor/symfony/dependency-injection/Tests/EnvVarProcessorTest.php deleted file mode 100644 index 6f0dfd3e..00000000 --- a/vendor/symfony/dependency-injection/Tests/EnvVarProcessorTest.php +++ /dev/null @@ -1,300 +0,0 @@ -setParameter('env(foo)', $value); - $container->compile(); - - $processor = new EnvVarProcessor($container); - - $result = $processor->getEnv('string', 'foo', function () { - $this->fail('Should not be called'); - }); - - $this->assertSame($processed, $result); - } - - public function validStrings() - { - return [ - ['hello', 'hello'], - ['true', 'true'], - ['false', 'false'], - ['null', 'null'], - ['1', '1'], - ['0', '0'], - ['1.1', '1.1'], - ['1e1', '1e1'], - ]; - } - - /** - * @dataProvider validBools - */ - public function testGetEnvBool($value, $processed) - { - $processor = new EnvVarProcessor(new Container()); - - $result = $processor->getEnv('bool', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - - $this->assertSame($processed, $result); - } - - public function validBools() - { - return [ - ['true', true], - ['false', false], - ['null', false], - ['1', true], - ['0', false], - ['1.1', true], - ['1e1', true], - ]; - } - - /** - * @dataProvider validInts - */ - public function testGetEnvInt($value, $processed) - { - $processor = new EnvVarProcessor(new Container()); - - $result = $processor->getEnv('int', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - - $this->assertSame($processed, $result); - } - - public function validInts() - { - return [ - ['1', 1], - ['1.1', 1], - ['1e1', 10], - ]; - } - - /** - * @dataProvider invalidInts - */ - public function testGetEnvIntInvalid($value) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Non-numeric env var'); - $processor = new EnvVarProcessor(new Container()); - - $processor->getEnv('int', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - } - - public function invalidInts() - { - return [ - ['foo'], - ['true'], - ['null'], - ]; - } - - /** - * @dataProvider validFloats - */ - public function testGetEnvFloat($value, $processed) - { - $processor = new EnvVarProcessor(new Container()); - - $result = $processor->getEnv('float', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - - $this->assertSame($processed, $result); - } - - public function validFloats() - { - return [ - ['1', 1.0], - ['1.1', 1.1], - ['1e1', 10.0], - ]; - } - - /** - * @dataProvider invalidFloats - */ - public function testGetEnvFloatInvalid($value) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Non-numeric env var'); - $processor = new EnvVarProcessor(new Container()); - - $processor->getEnv('float', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - } - - public function invalidFloats() - { - return [ - ['foo'], - ['true'], - ['null'], - ]; - } - - /** - * @dataProvider validConsts - */ - public function testGetEnvConst($value, $processed) - { - $processor = new EnvVarProcessor(new Container()); - - $result = $processor->getEnv('const', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - - $this->assertSame($processed, $result); - } - - public function validConsts() - { - return [ - ['Symfony\Component\DependencyInjection\Tests\EnvVarProcessorTest::TEST_CONST', self::TEST_CONST], - ['E_ERROR', \E_ERROR], - ]; - } - - /** - * @dataProvider invalidConsts - */ - public function testGetEnvConstInvalid($value) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('undefined constant'); - $processor = new EnvVarProcessor(new Container()); - - $processor->getEnv('const', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return $value; - }); - } - - public function invalidConsts() - { - return [ - ['Symfony\Component\DependencyInjection\Tests\EnvVarProcessorTest::UNDEFINED_CONST'], - ['UNDEFINED_CONST'], - ]; - } - - public function testGetEnvBase64() - { - $processor = new EnvVarProcessor(new Container()); - - $result = $processor->getEnv('base64', 'foo', function ($name) { - $this->assertSame('foo', $name); - - return base64_encode('hello'); - }); - - $this->assertSame('hello', $result); - } - - public function testGetEnvJson() - { - $processor = new EnvVarProcessor(new Container()); - - $result = $processor->getEnv('json', 'foo', function ($name) { - $this->assertSame('foo', $name); - - return json_encode([1]); - }); - - $this->assertSame([1], $result); - } - - public function testGetEnvInvalidJson() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Syntax error'); - $processor = new EnvVarProcessor(new Container()); - - $processor->getEnv('json', 'foo', function ($name) { - $this->assertSame('foo', $name); - - return 'invalid_json'; - }); - } - - /** - * @dataProvider otherJsonValues - */ - public function testGetEnvJsonOther($value) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Invalid JSON env var'); - $processor = new EnvVarProcessor(new Container()); - - $processor->getEnv('json', 'foo', function ($name) use ($value) { - $this->assertSame('foo', $name); - - return json_encode($value); - }); - } - - public function otherJsonValues() - { - return [ - [1], - [1.1], - [true], - [false], - ]; - } - - public function testGetEnvUnknown() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('Unsupported env var prefix'); - $processor = new EnvVarProcessor(new Container()); - - $processor->getEnv('unknown', 'foo', function ($name) { - $this->assertSame('foo', $name); - - return 'foo'; - }); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Extension/ExtensionTest.php b/vendor/symfony/dependency-injection/Tests/Extension/ExtensionTest.php deleted file mode 100644 index 9f35b4a4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Extension/ExtensionTest.php +++ /dev/null @@ -1,57 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Extension; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Extension\Extension; - -class ExtensionTest extends TestCase -{ - /** - * @dataProvider getResolvedEnabledFixtures - */ - public function testIsConfigEnabledReturnsTheResolvedValue($enabled) - { - $extension = new EnableableExtension(); - $this->assertSame($enabled, $extension->isConfigEnabled(new ContainerBuilder(), ['enabled' => $enabled])); - } - - public function getResolvedEnabledFixtures() - { - return [ - [true], - [false], - ]; - } - - public function testIsConfigEnabledOnNonEnableableConfig() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The config array has no \'enabled\' key.'); - $extension = new EnableableExtension(); - - $extension->isConfigEnabled(new ContainerBuilder(), []); - } -} - -class EnableableExtension extends Extension -{ - public function load(array $configs, ContainerBuilder $container) - { - } - - public function isConfigEnabled(ContainerBuilder $container, array $config) - { - return parent::isConfigEnabled($container, $config); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/Bar.php b/vendor/symfony/dependency-injection/Tests/Fixtures/Bar.php deleted file mode 100644 index 1aaca2f1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/Bar.php +++ /dev/null @@ -1,26 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -class Bar implements BarInterface -{ - public $quz; - - public function __construct($quz = null, \NonExistent $nonExistent = null, BarInterface $decorated = null, array $foo = []) - { - $this->quz = $quz; - } - - public static function create(\NonExistent $nonExistent = null, $factory = null) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/BarInterface.php b/vendor/symfony/dependency-injection/Tests/Fixtures/BarInterface.php deleted file mode 100644 index dc81f33f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/BarInterface.php +++ /dev/null @@ -1,16 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -interface BarInterface -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/CaseSensitiveClass.php b/vendor/symfony/dependency-injection/Tests/Fixtures/CaseSensitiveClass.php deleted file mode 100644 index 7c6f0ff4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/CaseSensitiveClass.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -class CaseSensitiveClass -{ - public $identifier; - - public function __construct($identifier = null) - { - $this->identifier = $identifier; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php b/vendor/symfony/dependency-injection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php deleted file mode 100644 index ba55fb75..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php +++ /dev/null @@ -1,10 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -use Symfony\Component\DependencyInjection\Definition; - -class CustomDefinition extends Definition -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/DeprecatedClass.php b/vendor/symfony/dependency-injection/Tests/Fixtures/DeprecatedClass.php deleted file mode 100644 index 33f37a03..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/DeprecatedClass.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -@trigger_error('deprecated', E_USER_DEPRECATED); - -class DeprecatedClass -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/FactoryDummy.php b/vendor/symfony/dependency-injection/Tests/Fixtures/FactoryDummy.php deleted file mode 100644 index da984b56..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/FactoryDummy.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -class FactoryDummy extends FactoryParent -{ - public static function createFactory(): FactoryDummy - { - } - - public function create(): \stdClass - { - } - - // Not supported by hhvm - public function createBuiltin(): int - { - } - - public static function createSelf(): self - { - } - - public static function createParent(): parent - { - } -} - -class FactoryParent -{ -} - -function factoryFunction(): FactoryDummy -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/FactoryDummyWithoutReturnTypes.php b/vendor/symfony/dependency-injection/Tests/Fixtures/FactoryDummyWithoutReturnTypes.php deleted file mode 100644 index f480a668..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/FactoryDummyWithoutReturnTypes.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -class FactoryDummyWithoutReturnTypes -{ - public function createTestDefinition1() - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/FooForCircularWithAddCalls.php b/vendor/symfony/dependency-injection/Tests/Fixtures/FooForCircularWithAddCalls.php deleted file mode 100644 index a8331dc3..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/FooForCircularWithAddCalls.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -class FooForCircularWithAddCalls -{ - public function call(\stdClass $argument) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/NamedArgumentsDummy.php b/vendor/symfony/dependency-injection/Tests/Fixtures/NamedArgumentsDummy.php deleted file mode 100644 index 09d907df..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/NamedArgumentsDummy.php +++ /dev/null @@ -1,21 +0,0 @@ - - */ -class NamedArgumentsDummy -{ - public function __construct(CaseSensitiveClass $c, $apiKey, $hostName) - { - } - - public function setApiKey($apiKey) - { - } - - public function setSensitiveClass(CaseSensitiveClass $c) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/ParentNotExists.php b/vendor/symfony/dependency-injection/Tests/Fixtures/ParentNotExists.php deleted file mode 100644 index ae637f91..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/ParentNotExists.php +++ /dev/null @@ -1,7 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -class SimilarArgumentsDummy -{ - public $class1; - public $class2; - - public function __construct(CaseSensitiveClass $class1, $token, CaseSensitiveClass $class2) - { - $this->class1 = $class1; - $this->class2 = $class2; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/StubbedTranslator.php b/vendor/symfony/dependency-injection/Tests/Fixtures/StubbedTranslator.php deleted file mode 100644 index eed18426..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/StubbedTranslator.php +++ /dev/null @@ -1,28 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -use Psr\Container\ContainerInterface; - -/** - * @author Iltar van der Berg - */ -class StubbedTranslator -{ - public function __construct(ContainerInterface $container) - { - } - - public function addResource($format, $resource, $locale, $domain = null) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/TestDefinition1.php b/vendor/symfony/dependency-injection/Tests/Fixtures/TestDefinition1.php deleted file mode 100644 index 8ec76a9d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/TestDefinition1.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Fixtures; - -use Symfony\Component\DependencyInjection\Definition; - -class TestDefinition1 extends Definition -{ -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/TestDefinition2.php b/vendor/symfony/dependency-injection/Tests/Fixtures/TestDefinition2.php deleted file mode 100644 index 2ec8f9cf..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/TestDefinition2.php +++ /dev/null @@ -1,9 +0,0 @@ - CustomDefinition::class, - 'baz' => '?'.CustomDefinition::class, - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/array.json b/vendor/symfony/dependency-injection/Tests/Fixtures/array.json deleted file mode 100644 index dc27f0fa..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/array.json +++ /dev/null @@ -1 +0,0 @@ -[123, "abc"] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/basic.expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/config/basic.expected.yml deleted file mode 100644 index 39a3b631..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/basic.expected.yml +++ /dev/null @@ -1,9 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - App\BarService: - class: App\BarService - arguments: [!service { class: FooClass }] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/basic.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/basic.php deleted file mode 100644 index a9e250b9..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/basic.php +++ /dev/null @@ -1,11 +0,0 @@ -services(); - $s->set(BarService::class) - ->args([inline('FooClass')]); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/child.expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/config/child.expected.yml deleted file mode 100644 index f60d6bb5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/child.expected.yml +++ /dev/null @@ -1,12 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - foo: - class: Class2 - file: file.php - lazy: true - arguments: [!service { class: Class1, public: false }] - bar: '@foo' diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/child.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/child.php deleted file mode 100644 index 8a5f2431..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/child.php +++ /dev/null @@ -1,22 +0,0 @@ -services() - ->set('bar', 'Class1') - ->set(BarService::class) - ->abstract(true) - ->lazy() - ->set('foo') - ->parent(BarService::class) - ->decorate('bar', 'b', 1) - ->args([ref('b')]) - ->class('Class2') - ->file('file.php') - ->parent('bar') - ->parent(BarService::class) - ; -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/defaults.expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/config/defaults.expected.yml deleted file mode 100644 index 3f01b109..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/defaults.expected.yml +++ /dev/null @@ -1,26 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - App\BarService: - class: App\BarService - arguments: [!service { class: FooClass }] - Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo - public: true - tags: - - { name: t, a: b } - autowire: true - autoconfigure: true - arguments: ['@bar'] - bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo - public: false - tags: - - { name: t, a: b } - autowire: true - calls: - - [setFoo, ['@bar']] - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/defaults.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/defaults.php deleted file mode 100644 index 2889d3fb..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/defaults.php +++ /dev/null @@ -1,21 +0,0 @@ -import('basic.php'); - - $s = $c->services()->defaults() - ->public() - ->private() - ->autoconfigure() - ->autowire() - ->tag('t', ['a' => 'b']) - ->bind(Foo::class, ref('bar')) - ->private(); - - $s->set(Foo::class)->args([ref('bar')])->public(); - $s->set('bar', Foo::class)->call('setFoo')->autoconfigure(false); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/factory_short_notation.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/factory_short_notation.php deleted file mode 100644 index 5b37793e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/factory_short_notation.php +++ /dev/null @@ -1,9 +0,0 @@ -services() - ->set('service', \stdClass::class) - ->factory('factory:method'); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/instanceof.expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/config/instanceof.expected.yml deleted file mode 100644 index 1238a7bd..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/instanceof.expected.yml +++ /dev/null @@ -1,19 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo - tags: - - { name: tag, k: v } - lazy: true - properties: { p: 1 } - calls: - - [setFoo, ['@foo']] - - shared: false - configurator: c - foo: - class: App\FooService diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/instanceof.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/instanceof.php deleted file mode 100644 index 0d6aac7a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/instanceof.php +++ /dev/null @@ -1,22 +0,0 @@ -services(); - $s->instanceof(Prototype\Foo::class) - ->property('p', 0) - ->call('setFoo', [ref('foo')]) - ->tag('tag', ['k' => 'v']) - ->share(false) - ->lazy() - ->configurator('c') - ->property('p', 1); - - $s->load(Prototype::class.'\\', '../Prototype')->exclude('../Prototype/*/*'); - - $s->set('foo', FooService::class); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/php7.expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/config/php7.expected.yml deleted file mode 100644 index 7cec320b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/php7.expected.yml +++ /dev/null @@ -1,18 +0,0 @@ -parameters: - foo: Foo - bar: Bar - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo - public: true - arguments: ['@bar'] - bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo - calls: - - [setFoo, { }] - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/php7.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/php7.php deleted file mode 100644 index 7711624e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/php7.php +++ /dev/null @@ -1,19 +0,0 @@ -parameters() - ('foo', 'Foo') - ('bar', 'Bar') - ; - $c->services() - (Foo::class) - ->arg('$bar', ref('bar')) - ->public() - ('bar', Foo::class) - ->call('setFoo') - ; -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/prototype.expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/config/prototype.expected.yml deleted file mode 100644 index 24a79401..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/prototype.expected.yml +++ /dev/null @@ -1,23 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo - tags: - - { name: foo } - - { name: baz } - deprecated: '%service_id%' - arguments: [1] - factory: f - Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar - tags: - - { name: foo } - - { name: baz } - deprecated: '%service_id%' - lazy: true - arguments: [1] - factory: f diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/prototype.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/prototype.php deleted file mode 100644 index e2884aa2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/prototype.php +++ /dev/null @@ -1,22 +0,0 @@ -services()->defaults() - ->tag('baz'); - $di->load(Prototype::class.'\\', '../Prototype') - ->autoconfigure() - ->exclude('../Prototype/{OtherDir,BadClasses}') - ->factory('f') - ->deprecate('%service_id%') - ->args([0]) - ->args([1]) - ->autoconfigure(false) - ->tag('foo') - ->parent('foo'); - $di->set('foo')->lazy()->abstract(); - $di->get(Prototype\Foo::class)->lazy(false); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/services9.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/services9.php deleted file mode 100644 index ef390937..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/services9.php +++ /dev/null @@ -1,127 +0,0 @@ -parameters(); - $p->set('baz_class', 'BazClass'); - $p->set('foo_class', FooClass::class) - ->set('foo', 'bar'); - - $s = $c->services()->defaults()->public(); - $s->set('foo') - ->args(['foo', ref('foo.baz'), ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%'], true, ref('service_container')]) - ->class(FooClass::class) - ->tag('foo', ['foo' => 'foo']) - ->tag('foo', ['bar' => 'bar', 'baz' => 'baz']) - ->factory([FooClass::class, 'getInstance']) - ->property('foo', 'bar') - ->property('moo', ref('foo.baz')) - ->property('qux', ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%']) - ->call('setBar', [ref('bar')]) - ->call('initialize') - ->configurator('sc_configure'); - - $s->set('foo.baz', '%baz_class%') - ->factory(['%baz_class%', 'getInstance']) - ->configurator(['%baz_class%', 'configureStatic1']); - - $s->set('bar', FooClass::class) - ->args(['foo', ref('foo.baz'), new Parameter('foo_bar')]) - ->configurator([ref('foo.baz'), 'configure']); - - $s->set('foo_bar', '%foo_class%') - ->args([ref('deprecated_service')]) - ->share(false); - - $s->set('method_call1', 'Bar\FooClass') - ->file(realpath(__DIR__.'/../includes/foo.php')) - ->call('setBar', [ref('foo')]) - ->call('setBar', [ref('foo2')->nullOnInvalid()]) - ->call('setBar', [ref('foo3')->ignoreOnInvalid()]) - ->call('setBar', [ref('foobaz')->ignoreOnInvalid()]) - ->call('setBar', [expr('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')]); - - $s->set('foo_with_inline', 'Foo') - ->call('setBar', [ref('inlined')]); - - $s->set('inlined', 'Bar') - ->property('pub', 'pub') - ->call('setBaz', [ref('baz')]) - ->private(); - - $s->set('baz', 'Baz') - ->call('setFoo', [ref('foo_with_inline')]); - - $s->set('request', 'Request') - ->synthetic(); - - $s->set('configurator_service', 'ConfClass') - ->private() - ->call('setFoo', [ref('baz')]); - - $s->set('configured_service', 'stdClass') - ->configurator([ref('configurator_service'), 'configureStdClass']); - - $s->set('configurator_service_simple', 'ConfClass') - ->args(['bar']) - ->private(); - - $s->set('configured_service_simple', 'stdClass') - ->configurator([ref('configurator_service_simple'), 'configureStdClass']); - - $s->set('decorated', 'stdClass'); - - $s->set('decorator_service', 'stdClass') - ->decorate('decorated'); - - $s->set('decorator_service_with_name', 'stdClass') - ->decorate('decorated', 'decorated.pif-pouf'); - - $s->set('deprecated_service', 'stdClass') - ->deprecate(); - - $s->set('new_factory', 'FactoryClass') - ->property('foo', 'bar') - ->private(); - - $s->set('factory_service', 'Bar') - ->factory([ref('foo.baz'), 'getInstance']); - - $s->set('new_factory_service', 'FooBarBaz') - ->property('foo', 'bar') - ->factory([ref('new_factory'), 'getInstance']); - - $s->set('service_from_static_method', 'Bar\FooClass') - ->factory(['Bar\FooClass', 'getInstance']); - - $s->set('factory_simple', 'SimpleFactoryClass') - ->deprecate() - ->args(['foo']) - ->private(); - - $s->set('factory_service_simple', 'Bar') - ->factory([ref('factory_simple'), 'getInstance']); - - $s->set('lazy_context', 'LazyContext') - ->args([iterator(['k1' => ref('foo.baz'), 'k2' => ref('service_container')]), iterator([])]); - - $s->set('lazy_context_ignore_invalid_ref', 'LazyContext') - ->args([iterator([ref('foo.baz'), ref('invalid')->ignoreOnInvalid()]), iterator([])]); - - $s->set('tagged_iterator_foo', 'Bar') - ->private() - ->tag('foo'); - - $s->set('tagged_iterator', 'Bar') - ->args([tagged('foo')]); - - $s->alias('alias_for_foo', 'foo')->private()->public(); - $s->alias('alias_for_alias', ref('alias_for_foo')); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/config/services_autoconfigure_with_parent.php b/vendor/symfony/dependency-injection/Tests/Fixtures/config/services_autoconfigure_with_parent.php deleted file mode 100644 index f8ffb1de..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/config/services_autoconfigure_with_parent.php +++ /dev/null @@ -1,9 +0,0 @@ -services() - ->set('parent_service', \stdClass::class) - ->set('child_service')->parent('parent_service')->autoconfigure(true); -}; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/CustomContainer.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/CustomContainer.php deleted file mode 100644 index 22514353..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/CustomContainer.php +++ /dev/null @@ -1,17 +0,0 @@ - - register('foo', 'FooClass')-> - addArgument(new Reference('bar')) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container11.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container11.php deleted file mode 100644 index 91e5c263..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container11.php +++ /dev/null @@ -1,13 +0,0 @@ - - register('foo', 'FooClass')-> - addArgument(new Definition('BarClass', [new Definition('BazClass')])) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container12.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container12.php deleted file mode 100644 index ef077030..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container12.php +++ /dev/null @@ -1,13 +0,0 @@ - - register('foo', 'FooClass\\Foo')-> - addArgument('foo<>&bar')-> - addTag('foo"bar\\bar', ['foo' => 'foo"barřž€']) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container13.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container13.php deleted file mode 100644 index df598d4e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container13.php +++ /dev/null @@ -1,18 +0,0 @@ - - register('foo', 'FooClass')-> - addArgument(new Reference('bar')) - ->setPublic(true) -; -$container-> - register('bar', 'BarClass') - ->setPublic(true) -; -$container->compile(); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container14.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container14.php deleted file mode 100644 index 191afb8c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container14.php +++ /dev/null @@ -1,17 +0,0 @@ -register('foo', 'FooClass\\Foo') - ->setDecoratedService('bar', 'bar.woozy') - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container16.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container16.php deleted file mode 100644 index 88619ec5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container16.php +++ /dev/null @@ -1,12 +0,0 @@ -register('foo', 'FooClass\\Foo') - ->setDecoratedService('bar') - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container17.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container17.php deleted file mode 100644 index 7f1db676..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container17.php +++ /dev/null @@ -1,11 +0,0 @@ -register('foo', '%foo.class%') - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container19.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container19.php deleted file mode 100644 index c3af5c96..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container19.php +++ /dev/null @@ -1,27 +0,0 @@ -setParameter('env(FOO)', 'Bar\FaooClass'); -$container->setParameter('foo', '%env(FOO)%'); - -$container - ->register('service_from_anonymous_factory', '%foo%') - ->setFactory([new Definition('%foo%'), 'getInstance']) - ->setPublic(true) -; - -$anonymousServiceWithFactory = new Definition('Bar\FooClass'); -$anonymousServiceWithFactory->setFactory('Bar\FooClass::getInstance'); -$container - ->register('service_with_method_call_and_factory', 'Bar\FooClass') - ->addMethodCall('setBar', [$anonymousServiceWithFactory]) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container21.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container21.php deleted file mode 100644 index d82cf385..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container21.php +++ /dev/null @@ -1,21 +0,0 @@ -setConfigurator([new Definition('Baz'), 'configureBar']); - -$fooFactory = new Definition('FooFactory'); -$fooFactory->setFactory([new Definition('Foobar'), 'createFooFactory']); - -$container - ->register('foo', 'Foo') - ->setFactory([$fooFactory, 'createFoo']) - ->setConfigurator([$bar, 'configureFoo']) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container24.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container24.php deleted file mode 100644 index b9d0b91f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container24.php +++ /dev/null @@ -1,13 +0,0 @@ -register('foo', 'Foo') - ->setAutowired(true) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container33.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container33.php deleted file mode 100644 index 673abe20..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container33.php +++ /dev/null @@ -1,12 +0,0 @@ -register(\Foo\Foo::class)->setPublic(true); -$container->register(\Bar\Foo::class)->setPublic(true); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container8.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container8.php deleted file mode 100644 index edcd045e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container8.php +++ /dev/null @@ -1,25 +0,0 @@ - '%baz%', - 'baz' => 'bar', - 'bar' => 'foo is %%foo bar', - 'escape' => '@escapeme', - 'values' => [true, false, null, 0, 1000.3, 'true', 'false', 'null'], - 'null string' => 'null', - 'string of digits' => '123', - 'string of digits prefixed with minus character' => '-123', - 'true string' => 'true', - 'false string' => 'false', - 'binary number string' => '0b0110', - 'numeric string' => '-1.2E2', - 'hexadecimal number string' => '0xFF', - 'float string' => '10100.1', - 'positive float string' => '+10100.1', - 'negative float string' => '-10100.1', -])); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container9.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container9.php deleted file mode 100644 index 691a7fa6..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container9.php +++ /dev/null @@ -1,176 +0,0 @@ -register('foo', '\Bar\FooClass') - ->addTag('foo', ['foo' => 'foo']) - ->addTag('foo', ['bar' => 'bar', 'baz' => 'baz']) - ->setFactory(['Bar\\FooClass', 'getInstance']) - ->setArguments(['foo', new Reference('foo.baz'), ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%'], true, new Reference('service_container')]) - ->setProperties(['foo' => 'bar', 'moo' => new Reference('foo.baz'), 'qux' => ['%foo%' => 'foo is %foo%', 'foobar' => '%foo%']]) - ->addMethodCall('setBar', [new Reference('bar')]) - ->addMethodCall('initialize') - ->setConfigurator('sc_configure') - ->setPublic(true) -; -$container - ->register('foo.baz', '%baz_class%') - ->setFactory(['%baz_class%', 'getInstance']) - ->setConfigurator(['%baz_class%', 'configureStatic1']) - ->setPublic(true) -; -$container - ->register('bar', 'Bar\FooClass') - ->setArguments(['foo', new Reference('foo.baz'), new Parameter('foo_bar')]) - ->setConfigurator([new Reference('foo.baz'), 'configure']) - ->setPublic(true) -; -$container - ->register('foo_bar', '%foo_class%') - ->addArgument(new Reference('deprecated_service')) - ->setShared(false) - ->setPublic(true) -; -$container->getParameterBag()->clear(); -$container->getParameterBag()->add([ - 'baz_class' => 'BazClass', - 'foo_class' => 'Bar\FooClass', - 'foo' => 'bar', -]); -$container - ->register('method_call1', 'Bar\FooClass') - ->setFile(realpath(__DIR__.'/../includes/foo.php')) - ->addMethodCall('setBar', [new Reference('foo')]) - ->addMethodCall('setBar', [new Reference('foo2', ContainerInterface::NULL_ON_INVALID_REFERENCE)]) - ->addMethodCall('setBar', [new Reference('foo3', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]) - ->addMethodCall('setBar', [new Reference('foobaz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]) - ->addMethodCall('setBar', [new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')]) - ->setPublic(true) -; -$container - ->register('foo_with_inline', 'Foo') - ->addMethodCall('setBar', [new Reference('inlined')]) - ->setPublic(true) -; -$container - ->register('inlined', 'Bar') - ->setProperty('pub', 'pub') - ->addMethodCall('setBaz', [new Reference('baz')]) - ->setPublic(false) -; -$container - ->register('baz', 'Baz') - ->addMethodCall('setFoo', [new Reference('foo_with_inline')]) - ->setPublic(true) -; -$container - ->register('request', 'Request') - ->setSynthetic(true) - ->setPublic(true) -; -$container - ->register('configurator_service', 'ConfClass') - ->setPublic(false) - ->addMethodCall('setFoo', [new Reference('baz')]) -; -$container - ->register('configured_service', 'stdClass') - ->setConfigurator([new Reference('configurator_service'), 'configureStdClass']) - ->setPublic(true) -; -$container - ->register('configurator_service_simple', 'ConfClass') - ->addArgument('bar') - ->setPublic(false) -; -$container - ->register('configured_service_simple', 'stdClass') - ->setConfigurator([new Reference('configurator_service_simple'), 'configureStdClass']) - ->setPublic(true) -; -$container - ->register('decorated', 'stdClass') - ->setPublic(true) -; -$container - ->register('decorator_service', 'stdClass') - ->setDecoratedService('decorated') - ->setPublic(true) -; -$container - ->register('decorator_service_with_name', 'stdClass') - ->setDecoratedService('decorated', 'decorated.pif-pouf') - ->setPublic(true) -; -$container - ->register('deprecated_service', 'stdClass') - ->setDeprecated(true) - ->setPublic(true) -; -$container - ->register('new_factory', 'FactoryClass') - ->setProperty('foo', 'bar') - ->setPublic(false) -; -$container - ->register('factory_service', 'Bar') - ->setFactory([new Reference('foo.baz'), 'getInstance']) - ->setPublic(true) -; -$container - ->register('new_factory_service', 'FooBarBaz') - ->setProperty('foo', 'bar') - ->setFactory([new Reference('new_factory'), 'getInstance']) - ->setPublic(true) -; -$container - ->register('service_from_static_method', 'Bar\FooClass') - ->setFactory(['Bar\FooClass', 'getInstance']) - ->setPublic(true) -; -$container - ->register('factory_simple', 'SimpleFactoryClass') - ->addArgument('foo') - ->setDeprecated(true) - ->setPublic(false) -; -$container - ->register('factory_service_simple', 'Bar') - ->setFactory([new Reference('factory_simple'), 'getInstance']) - ->setPublic(true) -; -$container - ->register('lazy_context', 'LazyContext') - ->setArguments([new IteratorArgument(['k1' => new Reference('foo.baz'), 'k2' => new Reference('service_container')]), new IteratorArgument([])]) - ->setPublic(true) -; -$container - ->register('lazy_context_ignore_invalid_ref', 'LazyContext') - ->setArguments([new IteratorArgument([new Reference('foo.baz'), new Reference('invalid', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]), new IteratorArgument([])]) - ->setPublic(true) -; -$container - ->register('tagged_iterator_foo', 'Bar') - ->addTag('foo') - ->setPublic(false) -; -$container - ->register('tagged_iterator', 'Bar') - ->addArgument(new TaggedIteratorArgument('foo')) - ->setPublic(true) -; -$container->setAlias('alias_for_foo', 'foo')->setPublic(true); -$container->setAlias('alias_for_alias', 'alias_for_foo')->setPublic(true); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_abstract.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_abstract.php deleted file mode 100644 index 308e2252..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_abstract.php +++ /dev/null @@ -1,13 +0,0 @@ -register('foo', 'Foo') - ->setAbstract(true) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_almost_circular.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_almost_circular.php deleted file mode 100644 index a1f88539..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_almost_circular.php +++ /dev/null @@ -1,176 +0,0 @@ -register('foo', FooCircular::class)->setPublic(true) - ->addArgument(new Reference('bar')); - -$container->register('bar', BarCircular::class)->setPublic($public) - ->addMethodCall('addFoobar', [new Reference('foobar')]); - -$container->register('foobar', FoobarCircular::class)->setPublic($public) - ->addArgument(new Reference('foo')); - -// mixed visibility for deps - -$container->register('foo2', FooCircular::class)->setPublic(true) - ->addArgument(new Reference('bar2')); - -$container->register('bar2', BarCircular::class)->setPublic(!$public) - ->addMethodCall('addFoobar', [new Reference('foobar2')]); - -$container->register('foobar2', FoobarCircular::class)->setPublic($public) - ->addArgument(new Reference('foo2')); - -// simple inline setter with internal reference - -$container->register('bar3', BarCircular::class)->setPublic(true) - ->addMethodCall('addFoobar', [new Reference('foobar3'), new Reference('foobar3')]); - -$container->register('foobar3', FoobarCircular::class)->setPublic($public); - -// loop with non-shared dep - -$container->register('foo4', 'stdClass')->setPublic($public) - ->setShared(false) - ->setProperty('foobar', new Reference('foobar4')); - -$container->register('foobar4', 'stdClass')->setPublic(true) - ->addArgument(new Reference('foo4')); - -// loop on the constructor of a setter-injected dep with property - -$container->register('foo5', 'stdClass')->setPublic(true) - ->setProperty('bar', new Reference('bar5')); - -$container->register('bar5', 'stdClass')->setPublic($public) - ->addArgument(new Reference('foo5')) - ->setProperty('foo', new Reference('foo5')); - -// doctrine-like event system + some extra - -$container->register('manager', 'stdClass')->setPublic(true) - ->addArgument(new Reference('connection')); - -$container->register('logger', 'stdClass')->setPublic(true) - ->addArgument(new Reference('connection')) - ->setProperty('handler', (new Definition('stdClass'))->addArgument(new Reference('manager'))) -; -$container->register('connection', 'stdClass')->setPublic(true) - ->addArgument(new Reference('dispatcher')) - ->addArgument(new Reference('config')); - -$container->register('config', 'stdClass')->setPublic(false) - ->setProperty('logger', new Reference('logger')); - -$container->register('dispatcher', 'stdClass')->setPublic($public) - ->setLazy($public) - ->setProperty('subscriber', new Reference('subscriber')); - -$container->register('subscriber', 'stdClass')->setPublic(true) - ->addArgument(new Reference('manager')); - -// doctrine-like event system + some extra (bis) - -$container->register('manager2', 'stdClass')->setPublic(true) - ->addArgument(new Reference('connection2')); - -$container->register('logger2', 'stdClass')->setPublic(false) - ->addArgument(new Reference('connection2')) - ->setProperty('handler2', (new Definition('stdClass'))->addArgument(new Reference('manager2'))) -; -$container->register('connection2', 'stdClass')->setPublic(true) - ->addArgument(new Reference('dispatcher2')) - ->addArgument(new Reference('config2')); - -$container->register('config2', 'stdClass')->setPublic(false) - ->setProperty('logger2', new Reference('logger2')); - -$container->register('dispatcher2', 'stdClass')->setPublic($public) - ->setLazy($public) - ->setProperty('subscriber2', new Reference('subscriber2')); - -$container->register('subscriber2', 'stdClass')->setPublic(false) - ->addArgument(new Reference('manager2')); - -// doctrine-like event system with listener - -$container->register('manager3', 'stdClass') - ->setLazy(true) - ->setPublic(true) - ->addArgument(new Reference('connection3')); - -$container->register('connection3', 'stdClass') - ->setPublic($public) - ->setProperty('listener', [new Reference('listener3')]); - -$container->register('listener3', 'stdClass') - ->setPublic(true) - ->setProperty('manager', new Reference('manager3')); - -// doctrine-like event system with small differences - -$container->register('manager4', 'stdClass') - ->setLazy(true) - ->addArgument(new Reference('connection4')); - -$container->register('connection4', 'stdClass') - ->setPublic($public) - ->setProperty('listener', [new Reference('listener4')]); - -$container->register('listener4', 'stdClass') - ->setPublic(true) - ->addArgument(new Reference('manager4')); - -// private service involved in a loop - -$container->register('foo6', 'stdClass') - ->setPublic(true) - ->setProperty('bar6', new Reference('bar6')); - -$container->register('bar6', 'stdClass') - ->setPublic(false) - ->addArgument(new Reference('foo6')); - -$container->register('baz6', 'stdClass') - ->setPublic(true) - ->setProperty('bar6', new Reference('bar6')); - -// provided by Christian Schiffler - -$container - ->register('root', 'stdClass') - ->setArguments([new Reference('level2'), new Reference('multiuse1')]) - ->setPublic(true); - -$container - ->register('level2', FooForCircularWithAddCalls::class) - ->addMethodCall('call', [new Reference('level3')]); - -$container->register('multiuse1', 'stdClass'); - -$container - ->register('level3', 'stdClass') - ->addArgument(new Reference('level4')); - -$container - ->register('level4', 'stdClass') - ->setArguments([new Reference('multiuse1'), new Reference('level5')]); - -$container - ->register('level5', 'stdClass') - ->addArgument(new Reference('level6')); - -$container - ->register('level6', FooForCircularWithAddCalls::class) - ->addMethodCall('call', [new Reference('level5')]); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_env_in_id.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_env_in_id.php deleted file mode 100644 index 1e851cf0..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_env_in_id.php +++ /dev/null @@ -1,22 +0,0 @@ -setParameter('env(BAR)', 'bar'); - -$container->register('foo', 'stdClass')->setPublic(true) - ->addArgument(new Reference('bar_%env(BAR)%')) - ->addArgument(['baz_%env(BAR)%' => new Reference('baz_%env(BAR)%')]); - -$container->register('bar', 'stdClass')->setPublic(true) - ->addArgument(new Reference('bar_%env(BAR)%')); - -$container->register('bar_%env(BAR)%', 'stdClass')->setPublic(false); -$container->register('baz_%env(BAR)%', 'stdClass')->setPublic(false); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_inline_requires.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_inline_requires.php deleted file mode 100644 index 3bbfa31f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_inline_requires.php +++ /dev/null @@ -1,19 +0,0 @@ -register(HotPath\C1::class)->addTag('container.hot_path')->setPublic(true); -$container->register(HotPath\C2::class)->addArgument(new Reference(HotPath\C3::class))->setPublic(true); -$container->register(HotPath\C3::class); -$container->register(ParentNotExists::class)->setPublic(true); - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_uninitialized_ref.php b/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_uninitialized_ref.php deleted file mode 100644 index 36c05c3f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/containers/container_uninitialized_ref.php +++ /dev/null @@ -1,49 +0,0 @@ -register('foo1', 'stdClass') - ->setPublic(true) -; - -$container - ->register('foo2', 'stdClass') - ->setPublic(false) -; - -$container - ->register('foo3', 'stdClass') - ->setPublic(false) -; - -$container - ->register('baz', 'stdClass') - ->setProperty('foo3', new Reference('foo3')) - ->setPublic(true) -; - -$container - ->register('bar', 'stdClass') - ->setProperty('foo1', new Reference('foo1', $container::IGNORE_ON_UNINITIALIZED_REFERENCE)) - ->setProperty('foo2', new Reference('foo2', $container::IGNORE_ON_UNINITIALIZED_REFERENCE)) - ->setProperty('foo3', new Reference('foo3', $container::IGNORE_ON_UNINITIALIZED_REFERENCE)) - ->setProperty('closures', [ - new ServiceClosureArgument(new Reference('foo1', $container::IGNORE_ON_UNINITIALIZED_REFERENCE)), - new ServiceClosureArgument(new Reference('foo2', $container::IGNORE_ON_UNINITIALIZED_REFERENCE)), - new ServiceClosureArgument(new Reference('foo3', $container::IGNORE_ON_UNINITIALIZED_REFERENCE)), - ]) - ->setProperty('iter', new IteratorArgument([ - 'foo1' => new Reference('foo1', $container::IGNORE_ON_UNINITIALIZED_REFERENCE), - 'foo2' => new Reference('foo2', $container::IGNORE_ON_UNINITIALIZED_REFERENCE), - 'foo3' => new Reference('foo3', $container::IGNORE_ON_UNINITIALIZED_REFERENCE), - ])) - ->setPublic(true) -; - -return $container; diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/import/import.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/directory/import/import.yml deleted file mode 100644 index 35ec4a04..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/import/import.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: ../recurse/ } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/recurse/simple.ini b/vendor/symfony/dependency-injection/Tests/Fixtures/directory/recurse/simple.ini deleted file mode 100644 index 0984cdac..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/recurse/simple.ini +++ /dev/null @@ -1,2 +0,0 @@ -[parameters] - ini = ini diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/recurse/simple.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/directory/recurse/simple.yml deleted file mode 100644 index f98ef12e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/recurse/simple.yml +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - yaml: yaml diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/simple.php b/vendor/symfony/dependency-injection/Tests/Fixtures/directory/simple.php deleted file mode 100644 index 4750324a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/directory/simple.php +++ /dev/null @@ -1,3 +0,0 @@ -setParameter('php', 'php'); diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services1.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services1.dot deleted file mode 100644 index e7401080..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services1.dot +++ /dev/null @@ -1,7 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services10-1.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services10-1.dot deleted file mode 100644 index 9fdf3410..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services10-1.dot +++ /dev/null @@ -1,10 +0,0 @@ -digraph sc { - ratio="normal" - node [fontsize="13" fontname="Verdana" shape="square"]; - edge [fontsize="12" fontname="Verdana" color="white" arrowhead="closed" arrowsize="1"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=square, fillcolor="grey", style="filled"]; - node_foo [label="foo\nFooClass\n", shape=square, fillcolor="grey", style="filled"]; - node_bar [label="bar\n\n", shape=square, fillcolor="red", style="empty"]; - node_foo -> node_bar [label="" style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services10.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services10.dot deleted file mode 100644 index 309388ea..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services10.dot +++ /dev/null @@ -1,10 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo [label="foo\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_bar [label="bar\n\n", shape=record, fillcolor="#ff9999", style="filled"]; - node_foo -> node_bar [label="" style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services13.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services13.dot deleted file mode 100644 index fffe8f1b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services13.dot +++ /dev/null @@ -1,10 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo [label="foo\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_bar [label="bar\nBarClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo -> node_bar [label="" style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services14.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services14.dot deleted file mode 100644 index e7401080..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services14.dot +++ /dev/null @@ -1,7 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services17.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services17.dot deleted file mode 100644 index e177fae2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services17.dot +++ /dev/null @@ -1,8 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo [label="foo\n%foo.class%\n", shape=record, fillcolor="#eeeeee", style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services18.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services18.dot deleted file mode 100644 index 4fbcceef..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services18.dot +++ /dev/null @@ -1,8 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_foo [label="foo\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services9.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services9.dot deleted file mode 100644 index 6a34c573..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services9.dot +++ /dev/null @@ -1,56 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo [label="foo (alias_for_foo)\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo_baz [label="foo.baz\nBazClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_bar [label="bar\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo_bar [label="foo_bar\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="dotted"]; - node_method_call1 [label="method_call1\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo_with_inline [label="foo_with_inline\nFoo\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_inlined [label="inlined\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_baz [label="baz\nBaz\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_request [label="request\nRequest\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_configurator_service [label="configurator_service\nConfClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_configured_service [label="configured_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_configurator_service_simple [label="configurator_service_simple\nConfClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_configured_service_simple [label="configured_service_simple\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_decorated [label="decorated\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_decorator_service [label="decorator_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_decorator_service_with_name [label="decorator_service_with_name\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_deprecated_service [label="deprecated_service\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_new_factory [label="new_factory\nFactoryClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_factory_service [label="factory_service\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_new_factory_service [label="new_factory_service\nFooBarBaz\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_service_from_static_method [label="service_from_static_method\nBar\\FooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_factory_simple [label="factory_simple\nSimpleFactoryClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_factory_service_simple [label="factory_service_simple\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_lazy_context [label="lazy_context\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_lazy_context_ignore_invalid_ref [label="lazy_context_ignore_invalid_ref\nLazyContext\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_tagged_iterator_foo [label="tagged_iterator_foo\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_tagged_iterator [label="tagged_iterator\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"]; - node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"]; - node_foobaz [label="foobaz\n\n", shape=record, fillcolor="#ff9999", style="filled"]; - node_invalid [label="invalid\n\n", shape=record, fillcolor="#ff9999", style="filled"]; - node_foo -> node_foo_baz [label="" style="filled"]; - node_foo -> node_service_container [label="" style="filled"]; - node_foo -> node_foo_baz [label="" style="dashed"]; - node_foo -> node_bar [label="setBar()" style="dashed"]; - node_bar -> node_foo_baz [label="" style="filled"]; - node_foo_bar -> node_deprecated_service [label="" style="filled"]; - node_method_call1 -> node_foo [label="setBar()" style="dashed"]; - node_method_call1 -> node_foo2 [label="setBar()" style="dashed"]; - node_method_call1 -> node_foo3 [label="setBar()" style="dashed"]; - node_method_call1 -> node_foobaz [label="setBar()" style="dashed"]; - node_foo_with_inline -> node_inlined [label="setBar()" style="dashed"]; - node_inlined -> node_baz [label="setBaz()" style="dashed"]; - node_baz -> node_foo_with_inline [label="setFoo()" style="dashed"]; - node_configurator_service -> node_baz [label="setFoo()" style="dashed"]; - node_lazy_context -> node_foo_baz [label="" style="filled" color="#9999ff"]; - node_lazy_context -> node_service_container [label="" style="filled" color="#9999ff"]; - node_lazy_context_ignore_invalid_ref -> node_foo_baz [label="" style="filled" color="#9999ff"]; - node_lazy_context_ignore_invalid_ref -> node_invalid [label="" style="filled" color="#9999ff"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services_inline.dot b/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services_inline.dot deleted file mode 100644 index b430b186..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/graphviz/services_inline.dot +++ /dev/null @@ -1,10 +0,0 @@ -digraph sc { - ratio="compress" - node [fontsize="11" fontname="Arial" shape="record"]; - edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - - node_service_container [label="service_container (Psr\Container\ContainerInterface, Symfony\Component\DependencyInjection\ContainerInterface)\nSymfony\\Component\\DependencyInjection\\ContainerInterface\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo [label="foo\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_bar [label="bar\nstdClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo -> node_bar [label="" style="filled"]; -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/FooVariadic.php b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/FooVariadic.php deleted file mode 100644 index 12861c56..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/FooVariadic.php +++ /dev/null @@ -1,16 +0,0 @@ -setParameter('project.configs', $configs); - $configs = array_filter($configs); - - if ($configs) { - $config = call_user_func_array('array_merge', $configs); - } else { - $config = []; - } - - $configuration->setDefinition('project.service.bar', new Definition('FooClass')); - $configuration->setParameter('project.parameter.bar', isset($config['foo']) ? $config['foo'] : 'foobar'); - - $configuration->setDefinition('project.service.foo', new Definition('FooClass')); - $configuration->setParameter('project.parameter.foo', isset($config['foo']) ? $config['foo'] : 'foobar'); - - return $configuration; - } - - public function getXsdValidationBasePath() - { - return false; - } - - public function getNamespace() - { - return 'http://www.example.com/schema/project'; - } - - public function getAlias() - { - return 'project'; - } - - public function getConfiguration(array $config, ContainerBuilder $container) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/ProjectWithXsdExtension.php b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/ProjectWithXsdExtension.php deleted file mode 100644 index 2ee2f12d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/ProjectWithXsdExtension.php +++ /dev/null @@ -1,19 +0,0 @@ -= 80000) { - require __DIR__.'/uniontype_classes.php'; -} - -class Foo -{ -} - -class Bar -{ - public function __construct(Foo $foo) - { - } -} - -interface AInterface -{ -} - -class A implements AInterface -{ - public static function create(Foo $foo) - { - } -} - -class B extends A -{ -} - -class C -{ - public function __construct(A $a) - { - } -} - -interface DInterface -{ -} - -interface EInterface extends DInterface -{ -} - -interface IInterface -{ -} - -class I implements IInterface -{ -} - -class F extends I implements EInterface -{ -} - -class G -{ - public function __construct(DInterface $d, EInterface $e, IInterface $i) - { - } -} - -class H -{ - public function __construct(B $b, DInterface $d) - { - } -} - -class D -{ - public function __construct(A $a, DInterface $d) - { - } -} - -class E -{ - public function __construct(D $d = null) - { - } -} - -class J -{ - public function __construct(I $i) - { - } -} - -class K -{ - public function __construct(IInterface $i) - { - } -} - -interface CollisionInterface -{ -} - -class CollisionA implements CollisionInterface -{ -} - -class CollisionB implements CollisionInterface -{ -} - -class CannotBeAutowired -{ - public function __construct(CollisionInterface $collision) - { - } -} - -class Lille -{ -} - -class Dunglas -{ - public function __construct(Lille $l) - { - } -} - -class LesTilleuls -{ - public function __construct(Dunglas $j, Dunglas $k) - { - } -} - -class OptionalParameter -{ - public function __construct(CollisionInterface $c = null, A $a, Foo $f = null) - { - } -} - -class BadTypeHintedArgument -{ - public function __construct(Dunglas $k, NotARealClass $r) - { - } -} -class BadParentTypeHintedArgument -{ - public function __construct(Dunglas $k, OptionalServiceClass $r) - { - } -} -class NotGuessableArgument -{ - public function __construct(Foo $k) - { - } -} -class NotGuessableArgumentForSubclass -{ - public function __construct(A $k) - { - } -} -class MultipleArguments -{ - public function __construct(A $k, $foo, Dunglas $dunglas, array $bar) - { - } -} - -class MultipleArgumentsOptionalScalar -{ - public function __construct(A $a, $foo = 'default_val', Lille $lille = null) - { - } -} -class MultipleArgumentsOptionalScalarLast -{ - public function __construct(A $a, Lille $lille, $foo = 'some_val') - { - } -} - -/* - * Classes used for testing createResourceForClass - */ -class ClassForResource -{ - public function __construct($foo, Bar $bar = null) - { - } - - public function setBar(Bar $bar) - { - } -} -class IdenticalClassResource extends ClassForResource -{ -} - -class ClassChangedConstructorArgs extends ClassForResource -{ - public function __construct($foo, Bar $bar, $baz) - { - } -} - -class SetterInjectionCollision -{ - /** - * @required - */ - public function setMultipleInstancesForOneArg(CollisionInterface $collision) - { - // The CollisionInterface cannot be autowired - there are multiple - - // should throw an exception - } -} - -class SetterInjection extends SetterInjectionParent -{ - /** - * @required - */ - public function setFoo(Foo $foo) - { - // should be called - } - - /** @inheritdoc*/ // <- brackets are missing on purpose - public function setDependencies(Foo $foo, A $a) - { - // should be called - } - - /** {@inheritdoc} */ - public function setWithCallsConfigured(A $a) - { - // this method has a calls configured on it - } - - public function notASetter(A $a) - { - // should be called only when explicitly specified - } - - /** - * @required*/ - public function setChildMethodWithoutDocBlock(A $a) - { - } -} - -class SetterInjectionParent -{ - /** @required*/ - public function setDependencies(Foo $foo, A $a) - { - // should be called - } - - public function notASetter(A $a) - { - // @required should be ignored when the child does not add @inheritdoc - } - - /** @required prefix is on purpose */ - public function setWithCallsConfigured(A $a) - { - } - - /** @required */ - public function setChildMethodWithoutDocBlock(A $a) - { - } -} - -class NotWireable -{ - public function setNotAutowireable(NotARealClass $n) - { - } - - public function setBar() - { - } - - public function setOptionalNotAutowireable(NotARealClass $n = null) - { - } - - public function setDifferentNamespace(\stdClass $n) - { - } - - public function setOptionalNoTypeHint($foo = null) - { - } - - public function setOptionalArgNoAutowireable($other = 'default_val') - { - } - - /** @required */ - protected function setProtectedMethod(A $a) - { - } -} - -class PrivateConstructor -{ - private function __construct() - { - } -} - -class ScalarSetter -{ - /** - * @required - */ - public function setDefaultLocale($defaultLocale) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/classes.php b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/classes.php deleted file mode 100644 index 33b043fa..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/classes.php +++ /dev/null @@ -1,136 +0,0 @@ -configure(); -} - -class BarClass extends BazClass -{ - protected $baz; - public $foo = 'foo'; - - public function setBaz(BazClass $baz) - { - $this->baz = $baz; - } - - public function getBaz() - { - return $this->baz; - } -} - -class BazClass -{ - protected $foo; - - public function setFoo(Foo $foo) - { - $this->foo = $foo; - } - - public function configure($instance) - { - $instance->configure(); - } - - public static function getInstance() - { - return new self(); - } - - public static function configureStatic($instance) - { - $instance->configure(); - } - - public static function configureStatic1() - { - } -} - -class BarUserClass -{ - public $bar; - - public function __construct(BarClass $bar) - { - $this->bar = $bar; - } -} - -class MethodCallClass -{ - public $simple; - public $complex; - private $callPassed = false; - - public function callMe() - { - $this->callPassed = is_scalar($this->simple) && is_object($this->complex); - } - - public function callPassed() - { - return $this->callPassed; - } -} - -class DummyProxyDumper implements ProxyDumper -{ - public function isProxyCandidate(Definition $definition) - { - return $definition->isLazy(); - } - - public function getProxyFactoryCode(Definition $definition, $id, $factoryCall = null) - { - return " // lazy factory for {$definition->getClass()}\n\n"; - } - - public function getProxyCode(Definition $definition) - { - return "// proxy code for {$definition->getClass()}\n"; - } -} - -class LazyContext -{ - public $lazyValues; - public $lazyEmptyValues; - - public function __construct($lazyValues, $lazyEmptyValues) - { - $this->lazyValues = $lazyValues; - $this->lazyEmptyValues = $lazyEmptyValues; - } -} - -class FoobarCircular -{ - public function __construct(FooCircular $foo) - { - $this->foo = $foo; - } -} - -class FooCircular -{ - public function __construct(BarCircular $bar) - { - $this->bar = $bar; - } -} - -class BarCircular -{ - public function addFoobar(FoobarCircular $foobar) - { - $this->foobar = $foobar; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/createphar.php b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/createphar.php deleted file mode 100644 index c675478f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/createphar.php +++ /dev/null @@ -1,47 +0,0 @@ -addFromString('ProjectWithXsdExtensionInPhar.php', <<<'EOT' -addFromString('schema/project-1.0.xsd', <<<'EOT' - - - - - - - - - - -EOT -); -$phar->setStub(''); diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/foo.php b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/foo.php deleted file mode 100644 index 20bc928b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/foo.php +++ /dev/null @@ -1,43 +0,0 @@ -arguments = $arguments; - } - - public static function getInstance($arguments = []) - { - $obj = new self($arguments); - $obj->called = true; - - return $obj; - } - - public function initialize() - { - $this->initialized = true; - } - - public function configure() - { - $this->configured = true; - } - - public function setBar($value = null) - { - $this->bar = $value; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/schema/project-1.0.xsd b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/schema/project-1.0.xsd deleted file mode 100644 index 282884e4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/schema/project-1.0.xsd +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/uniontype_classes.php b/vendor/symfony/dependency-injection/Tests/Fixtures/includes/uniontype_classes.php deleted file mode 100644 index 3a0c77c5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/includes/uniontype_classes.php +++ /dev/null @@ -1,24 +0,0 @@ -parameterBag = null; - - $this->services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php deleted file mode 100644 index 9e1abeb4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php +++ /dev/null @@ -1,55 +0,0 @@ -services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php deleted file mode 100644 index 2fe30f22..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php +++ /dev/null @@ -1,58 +0,0 @@ -parameterBag = null; - - $this->services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_without_constructor.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_without_constructor.php deleted file mode 100644 index c630ad09..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/custom_container_class_without_constructor.php +++ /dev/null @@ -1,55 +0,0 @@ -services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/php_with_wrong_ext.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/php/php_with_wrong_ext.yml deleted file mode 100644 index fdd31250..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/php_with_wrong_ext.yml +++ /dev/null @@ -1,3 +0,0 @@ -setParameter('with_wrong_ext', 'from php'); diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services1-1.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services1-1.php deleted file mode 100644 index 3c0ced8e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services1-1.php +++ /dev/null @@ -1,55 +0,0 @@ -services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services1.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services1.php deleted file mode 100644 index f7d49dd4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services1.php +++ /dev/null @@ -1,53 +0,0 @@ -services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services10.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services10.php deleted file mode 100644 index 96128299..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services10.php +++ /dev/null @@ -1,157 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->methodMap = [ - 'test' => 'getTestService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'test' shared service. - * - * @return \stdClass - */ - protected function getTestService() - { - return $this->services['test'] = new \stdClass(['only dot' => '.', 'concatenation as value' => '.\'\'.', 'concatenation from the start value' => '\'\'.', '.' => 'dot as a key', '.\'\'.' => 'concatenation as a key', '\'\'.' => 'concatenation from the start key', 'optimize concatenation' => 'string1-string2', 'optimize concatenation with empty string' => 'string1string2', 'optimize concatenation from the start' => 'start', 'optimize concatenation at the end' => 'end', 'new line' => 'string with '."\n".'new line']); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'empty_value' => '', - 'some_string' => '-', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services12.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services12.php deleted file mode 100644 index eb215596..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services12.php +++ /dev/null @@ -1,171 +0,0 @@ -targetDirs[$i] = $dir = \dirname($dir); - } - $this->parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->methodMap = [ - 'test' => 'getTestService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'test' shared service. - * - * @return \stdClass - */ - protected function getTestService() - { - return $this->services['test'] = new \stdClass(('file://'.$this->targetDirs[1]), [('file://'.$this->targetDirs[1]) => ($this->targetDirs[2].'/')]); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = [ - 'foo' => false, - 'buz' => false, - ]; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - switch ($name) { - case 'foo': $value = ('file://'.$this->targetDirs[1]); break; - case 'buz': $value = $this->targetDirs[2]; break; - default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - $this->loadedDynamicParameters[$name] = true; - - return $this->dynamicParameters[$name] = $value; - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'bar' => __DIR__, - 'baz' => (__DIR__.'/PhpDumperTest.php'), - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services13.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services13.php deleted file mode 100644 index 52f5cf25..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services13.php +++ /dev/null @@ -1,70 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'foo' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService() - { - $a = new \stdClass(); - $a->add($this); - - return $this->services['bar'] = new \stdClass($a); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services19.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services19.php deleted file mode 100644 index 6f6f6045..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services19.php +++ /dev/null @@ -1,181 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->methodMap = [ - 'service_from_anonymous_factory' => 'getServiceFromAnonymousFactoryService', - 'service_with_method_call_and_factory' => 'getServiceWithMethodCallAndFactoryService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'service_from_anonymous_factory' shared service. - * - * @return object A %env(FOO)% instance - */ - protected function getServiceFromAnonymousFactoryService() - { - return $this->services['service_from_anonymous_factory'] = (new ${($_ = $this->getEnv('FOO')) && false ?: "_"}())->getInstance(); - } - - /** - * Gets the public 'service_with_method_call_and_factory' shared service. - * - * @return \Bar\FooClass - */ - protected function getServiceWithMethodCallAndFactoryService() - { - $this->services['service_with_method_call_and_factory'] = $instance = new \Bar\FooClass(); - - $instance->setBar(\Bar\FooClass::getInstance()); - - return $instance; - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = [ - 'foo' => false, - ]; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - switch ($name) { - case 'foo': $value = $this->getEnv('FOO'); break; - default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - $this->loadedDynamicParameters[$name] = true; - - return $this->dynamicParameters[$name] = $value; - } - - private $normalizedParameterNames = [ - 'env(foo)' => 'env(FOO)', - ]; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'env(FOO)' => 'Bar\\FaooClass', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services24.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services24.php deleted file mode 100644 index 963118e2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services24.php +++ /dev/null @@ -1,66 +0,0 @@ -services = []; - $this->methodMap = [ - 'foo' => 'getFooService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'foo' shared autowired service. - * - * @return \Foo - */ - protected function getFooService() - { - return $this->services['foo'] = new \Foo(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services26.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services26.php deleted file mode 100644 index 95055207..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services26.php +++ /dev/null @@ -1,194 +0,0 @@ -targetDirs[$i] = $dir = \dirname($dir); - } - $this->parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'test' => 'getTestService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\Bar - */ - protected function getBarService() - { - return $this->services['bar'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\Bar($this->getEnv('QUZ')); - } - - /** - * Gets the public 'test' shared service. - * - * @return object A %env(FOO)% instance - */ - protected function getTestService() - { - $class = $this->getEnv('FOO'); - - return $this->services['test'] = new $class($this->getEnv('Bar'), 'foo'.$this->getEnv('string:FOO').'baz', $this->getEnv('int:Baz')); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = [ - 'bar' => false, - 'baz' => false, - 'json' => false, - 'db_dsn' => false, - 'env(json_file)' => false, - ]; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - switch ($name) { - case 'bar': $value = $this->getEnv('FOO'); break; - case 'baz': $value = $this->getEnv('int:Baz'); break; - case 'json': $value = $this->getEnv('json:file:json_file'); break; - case 'db_dsn': $value = $this->getEnv('resolve:DB'); break; - case 'env(json_file)': $value = ($this->targetDirs[1].'/array.json'); break; - default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - $this->loadedDynamicParameters[$name] = true; - - return $this->dynamicParameters[$name] = $value; - } - - private $normalizedParameterNames = [ - 'env(foo)' => 'env(FOO)', - 'env(db)' => 'env(DB)', - ]; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'project_dir' => '/foo/bar', - 'env(FOO)' => 'foo', - 'env(DB)' => 'sqlite://%project_dir%/var/data.db', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services33.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services33.php deleted file mode 100644 index 915d0537..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services33.php +++ /dev/null @@ -1,81 +0,0 @@ -services = []; - $this->normalizedIds = [ - 'bar\\foo' => 'Bar\\Foo', - 'foo\\foo' => 'Foo\\Foo', - ]; - $this->methodMap = [ - 'Bar\\Foo' => 'getFooService', - 'Foo\\Foo' => 'getFoo2Service', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'Bar\Foo' shared service. - * - * @return \Bar\Foo - */ - protected function getFooService() - { - return $this->services['Bar\\Foo'] = new \Bar\Foo(); - } - - /** - * Gets the public 'Foo\Foo' shared service. - * - * @return \Foo\Foo - */ - protected function getFoo2Service() - { - return $this->services['Foo\\Foo'] = new \Foo\Foo(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services8.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services8.php deleted file mode 100644 index e7a0214a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services8.php +++ /dev/null @@ -1,167 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'foo' => 'bar', - 'baz' => 'bar', - 'bar' => 'foo is %foo bar', - 'escape' => '@escapeme', - 'values' => [ - 0 => true, - 1 => false, - 2 => NULL, - 3 => 0, - 4 => 1000.3, - 5 => 'true', - 6 => 'false', - 7 => 'null', - ], - 'null string' => 'null', - 'string of digits' => '123', - 'string of digits prefixed with minus character' => '-123', - 'true string' => 'true', - 'false string' => 'false', - 'binary number string' => '0b0110', - 'numeric string' => '-1.2E2', - 'hexadecimal number string' => '0xFF', - 'float string' => '10100.1', - 'positive float string' => '+10100.1', - 'negative float string' => '-10100.1', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9.php deleted file mode 100644 index 6dd0baab..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9.php +++ /dev/null @@ -1,443 +0,0 @@ -getDefaultParameters())); - $this->normalizedIds = [ - 'psr\\container\\containerinterface' => 'Psr\\Container\\ContainerInterface', - 'symfony\\component\\dependencyinjection\\containerinterface' => 'Symfony\\Component\\DependencyInjection\\ContainerInterface', - ]; - $this->syntheticIds = [ - 'request' => true, - ]; - $this->methodMap = [ - 'bar' => 'getBarService', - 'baz' => 'getBazService', - 'configurator_service' => 'getConfiguratorServiceService', - 'configurator_service_simple' => 'getConfiguratorServiceSimpleService', - 'configured_service' => 'getConfiguredServiceService', - 'configured_service_simple' => 'getConfiguredServiceSimpleService', - 'decorated' => 'getDecoratedService', - 'decorator_service' => 'getDecoratorServiceService', - 'decorator_service_with_name' => 'getDecoratorServiceWithNameService', - 'deprecated_service' => 'getDeprecatedServiceService', - 'factory_service' => 'getFactoryServiceService', - 'factory_service_simple' => 'getFactoryServiceSimpleService', - 'factory_simple' => 'getFactorySimpleService', - 'foo' => 'getFooService', - 'foo.baz' => 'getFoo_BazService', - 'foo_bar' => 'getFooBarService', - 'foo_with_inline' => 'getFooWithInlineService', - 'inlined' => 'getInlinedService', - 'lazy_context' => 'getLazyContextService', - 'lazy_context_ignore_invalid_ref' => 'getLazyContextIgnoreInvalidRefService', - 'method_call1' => 'getMethodCall1Service', - 'new_factory' => 'getNewFactoryService', - 'new_factory_service' => 'getNewFactoryServiceService', - 'service_from_static_method' => 'getServiceFromStaticMethodService', - 'tagged_iterator' => 'getTaggedIteratorService', - 'tagged_iterator_foo' => 'getTaggedIteratorFooService', - ]; - $this->privates = [ - 'configurator_service' => true, - 'configurator_service_simple' => true, - 'factory_simple' => true, - 'inlined' => true, - 'new_factory' => true, - 'tagged_iterator_foo' => true, - ]; - $this->aliases = [ - 'Psr\\Container\\ContainerInterface' => 'service_container', - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => 'service_container', - 'alias_for_alias' => 'foo', - 'alias_for_foo' => 'foo', - ]; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \Bar\FooClass - */ - protected function getBarService() - { - $a = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - - $this->services['bar'] = $instance = new \Bar\FooClass('foo', $a, $this->getParameter('foo_bar')); - - $a->configure($instance); - - return $instance; - } - - /** - * Gets the public 'baz' shared service. - * - * @return \Baz - */ - protected function getBazService() - { - $this->services['baz'] = $instance = new \Baz(); - - $instance->setFoo(${($_ = isset($this->services['foo_with_inline']) ? $this->services['foo_with_inline'] : $this->getFooWithInlineService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'configured_service' shared service. - * - * @return \stdClass - */ - protected function getConfiguredServiceService() - { - $this->services['configured_service'] = $instance = new \stdClass(); - - ${($_ = isset($this->services['configurator_service']) ? $this->services['configurator_service'] : $this->getConfiguratorServiceService()) && false ?: '_'}->configureStdClass($instance); - - return $instance; - } - - /** - * Gets the public 'configured_service_simple' shared service. - * - * @return \stdClass - */ - protected function getConfiguredServiceSimpleService() - { - $this->services['configured_service_simple'] = $instance = new \stdClass(); - - ${($_ = isset($this->services['configurator_service_simple']) ? $this->services['configurator_service_simple'] : ($this->services['configurator_service_simple'] = new \ConfClass('bar'))) && false ?: '_'}->configureStdClass($instance); - - return $instance; - } - - /** - * Gets the public 'decorated' shared service. - * - * @return \stdClass - */ - protected function getDecoratedService() - { - return $this->services['decorated'] = new \stdClass(); - } - - /** - * Gets the public 'decorator_service' shared service. - * - * @return \stdClass - */ - protected function getDecoratorServiceService() - { - return $this->services['decorator_service'] = new \stdClass(); - } - - /** - * Gets the public 'decorator_service_with_name' shared service. - * - * @return \stdClass - */ - protected function getDecoratorServiceWithNameService() - { - return $this->services['decorator_service_with_name'] = new \stdClass(); - } - - /** - * Gets the public 'deprecated_service' shared service. - * - * @return \stdClass - * - * @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed. - */ - protected function getDeprecatedServiceService() - { - @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); - - return $this->services['deprecated_service'] = new \stdClass(); - } - - /** - * Gets the public 'factory_service' shared service. - * - * @return \Bar - */ - protected function getFactoryServiceService() - { - return $this->services['factory_service'] = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}->getInstance(); - } - - /** - * Gets the public 'factory_service_simple' shared service. - * - * @return \Bar - */ - protected function getFactoryServiceSimpleService() - { - return $this->services['factory_service_simple'] = ${($_ = isset($this->services['factory_simple']) ? $this->services['factory_simple'] : $this->getFactorySimpleService()) && false ?: '_'}->getInstance(); - } - - /** - * Gets the public 'foo' shared service. - * - * @return \Bar\FooClass - */ - protected function getFooService() - { - $a = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - - $this->services['foo'] = $instance = \Bar\FooClass::getInstance('foo', $a, [$this->getParameter('foo') => 'foo is '.$this->getParameter('foo').'', 'foobar' => $this->getParameter('foo')], true, $this); - - $instance->foo = 'bar'; - $instance->moo = $a; - $instance->qux = [$this->getParameter('foo') => 'foo is '.$this->getParameter('foo').'', 'foobar' => $this->getParameter('foo')]; - $instance->setBar(${($_ = isset($this->services['bar']) ? $this->services['bar'] : $this->getBarService()) && false ?: '_'}); - $instance->initialize(); - sc_configure($instance); - - return $instance; - } - - /** - * Gets the public 'foo.baz' shared service. - * - * @return object A %baz_class% instance - */ - protected function getFoo_BazService() - { - $this->services['foo.baz'] = $instance = \call_user_func([$this->getParameter('baz_class'), 'getInstance']); - - \call_user_func([$this->getParameter('baz_class'), 'configureStatic1'], $instance); - - return $instance; - } - - /** - * Gets the public 'foo_bar' service. - * - * @return object A %foo_class% instance - */ - protected function getFooBarService() - { - $class = $this->getParameter('foo_class'); - - return new $class(${($_ = isset($this->services['deprecated_service']) ? $this->services['deprecated_service'] : $this->getDeprecatedServiceService()) && false ?: '_'}); - } - - /** - * Gets the public 'foo_with_inline' shared service. - * - * @return \Foo - */ - protected function getFooWithInlineService() - { - $this->services['foo_with_inline'] = $instance = new \Foo(); - - $instance->setBar(${($_ = isset($this->services['inlined']) ? $this->services['inlined'] : $this->getInlinedService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'lazy_context' shared service. - * - * @return \LazyContext - */ - protected function getLazyContextService() - { - return $this->services['lazy_context'] = new \LazyContext(new RewindableGenerator(function () { - yield 'k1' => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - yield 'k2' => $this; - }, 2), new RewindableGenerator(function () { - return new \EmptyIterator(); - }, 0)); - } - - /** - * Gets the public 'lazy_context_ignore_invalid_ref' shared service. - * - * @return \LazyContext - */ - protected function getLazyContextIgnoreInvalidRefService() - { - return $this->services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function () { - yield 0 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - if ($this->has('invalid')) { - yield 1 => ${($_ = isset($this->services['invalid']) ? $this->services['invalid'] : $this->get('invalid', /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ 2)) && false ?: '_'}; - } - }, function () { - return 1 + (int) ($this->has('invalid')); - }), new RewindableGenerator(function () { - return new \EmptyIterator(); - }, 0)); - } - - /** - * Gets the public 'method_call1' shared service. - * - * @return \Bar\FooClass - */ - protected function getMethodCall1Service() - { - include_once '%path%foo.php'; - - $this->services['method_call1'] = $instance = new \Bar\FooClass(); - - $instance->setBar(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}); - $instance->setBar(${($_ = isset($this->services['foo2']) ? $this->services['foo2'] : $this->get('foo2', /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ 2)) && false ?: '_'}); - if ($this->has('foo3')) { - $instance->setBar(${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : $this->get('foo3', /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ 2)) && false ?: '_'}); - } - if ($this->has('foobaz')) { - $instance->setBar(${($_ = isset($this->services['foobaz']) ? $this->services['foobaz'] : $this->get('foobaz', /* ContainerInterface::NULL_ON_INVALID_REFERENCE */ 2)) && false ?: '_'}); - } - $instance->setBar((${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}->foo() . (($this->hasParameter("foo")) ? ($this->getParameter("foo")) : ("default")))); - - return $instance; - } - - /** - * Gets the public 'new_factory_service' shared service. - * - * @return \FooBarBaz - */ - protected function getNewFactoryServiceService() - { - $this->services['new_factory_service'] = $instance = ${($_ = isset($this->services['new_factory']) ? $this->services['new_factory'] : $this->getNewFactoryService()) && false ?: '_'}->getInstance(); - - $instance->foo = 'bar'; - - return $instance; - } - - /** - * Gets the public 'service_from_static_method' shared service. - * - * @return \Bar\FooClass - */ - protected function getServiceFromStaticMethodService() - { - return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance(); - } - - /** - * Gets the public 'tagged_iterator' shared service. - * - * @return \Bar - */ - protected function getTaggedIteratorService() - { - return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () { - return new \EmptyIterator(); - }, 0)); - } - - /** - * Gets the private 'configurator_service' shared service. - * - * @return \ConfClass - */ - protected function getConfiguratorServiceService() - { - $this->services['configurator_service'] = $instance = new \ConfClass(); - - $instance->setFoo(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->getBazService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the private 'configurator_service_simple' shared service. - * - * @return \ConfClass - */ - protected function getConfiguratorServiceSimpleService() - { - return $this->services['configurator_service_simple'] = new \ConfClass('bar'); - } - - /** - * Gets the private 'factory_simple' shared service. - * - * @return \SimpleFactoryClass - * - * @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed. - */ - protected function getFactorySimpleService() - { - @trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); - - return $this->services['factory_simple'] = new \SimpleFactoryClass('foo'); - } - - /** - * Gets the private 'inlined' shared service. - * - * @return \Bar - */ - protected function getInlinedService() - { - $this->services['inlined'] = $instance = new \Bar(); - - $instance->pub = 'pub'; - $instance->setBaz(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->getBazService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the private 'new_factory' shared service. - * - * @return \FactoryClass - */ - protected function getNewFactoryService() - { - $this->services['new_factory'] = $instance = new \FactoryClass(); - - $instance->foo = 'bar'; - - return $instance; - } - - /** - * Gets the private 'tagged_iterator_foo' shared service. - * - * @return \Bar - */ - protected function getTaggedIteratorFooService() - { - return $this->services['tagged_iterator_foo'] = new \Bar(); - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'baz_class' => 'BazClass', - 'foo_class' => 'Bar\\FooClass', - 'foo' => 'bar', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9_as_files.txt b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9_as_files.txt deleted file mode 100644 index ab7024fa..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9_as_files.txt +++ /dev/null @@ -1,508 +0,0 @@ -Array -( - [Container%s/removed-ids.php] => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'configurator_service' => true, - 'configurator_service_simple' => true, - 'decorated.pif-pouf' => true, - 'decorator_service.inner' => true, - 'factory_simple' => true, - 'inlined' => true, - 'new_factory' => true, - 'tagged_iterator_foo' => true, -]; - - [Container%s/getBazService.php] => services['baz'] = $instance = new \Baz(); - -$instance->setFoo(${($_ = isset($this->services['foo_with_inline']) ? $this->services['foo_with_inline'] : $this->load('getFooWithInlineService.php')) && false ?: '_'}); - -return $instance; - - [Container%s/getConfiguredServiceService.php] => services['configured_service'] = $instance = new \stdClass(); - -$a = new \ConfClass(); -$a->setFoo(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->load('getBazService.php')) && false ?: '_'}); - -$a->configureStdClass($instance); - -return $instance; - - [Container%s/getConfiguredServiceSimpleService.php] => services['configured_service_simple'] = $instance = new \stdClass(); - -(new \ConfClass('bar'))->configureStdClass($instance); - -return $instance; - - [Container%s/getDecoratorServiceService.php] => services['decorator_service'] = new \stdClass(); - - [Container%s/getDecoratorServiceWithNameService.php] => services['decorator_service_with_name'] = new \stdClass(); - - [Container%s/getDeprecatedServiceService.php] => services['deprecated_service'] = new \stdClass(); - - [Container%s/getFactoryServiceService.php] => services['factory_service'] = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->load('getFoo_BazService.php')) && false ?: '_'}->getInstance(); - - [Container%s/getFactoryServiceSimpleService.php] => services['factory_service_simple'] = ${($_ = isset($this->services['factory_simple']) ? $this->services['factory_simple'] : $this->load('getFactorySimpleService.php')) && false ?: '_'}->getInstance(); - - [Container%s/getFactorySimpleService.php] => services['factory_simple'] = new \SimpleFactoryClass('foo'); - - [Container%s/getFooService.php] => services['foo.baz']) ? $this->services['foo.baz'] : $this->load('getFoo_BazService.php')) && false ?: '_'}; - -$this->services['foo'] = $instance = \Bar\FooClass::getInstance('foo', $a, ['bar' => 'foo is bar', 'foobar' => 'bar'], true, $this); - -$instance->foo = 'bar'; -$instance->moo = $a; -$instance->qux = ['bar' => 'foo is bar', 'foobar' => 'bar']; -$instance->setBar(${($_ = isset($this->services['bar']) ? $this->services['bar'] : $this->getBarService()) && false ?: '_'}); -$instance->initialize(); -sc_configure($instance); - -return $instance; - - [Container%s/getFoo_BazService.php] => services['foo.baz'] = $instance = \BazClass::getInstance(); - -\BazClass::configureStatic1($instance); - -return $instance; - - [Container%s/getFooWithInlineService.php] => services['foo_with_inline'] = $instance = new \Foo(); - -$a = new \Bar(); -$a->pub = 'pub'; -$a->setBaz(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->load('getBazService.php')) && false ?: '_'}); - -$instance->setBar($a); - -return $instance; - - [Container%s/getLazyContextService.php] => services['lazy_context'] = new \LazyContext(new RewindableGenerator(function () { - yield 'k1' => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->load('getFoo_BazService.php')) && false ?: '_'}; - yield 'k2' => $this; -}, 2), new RewindableGenerator(function () { - return new \EmptyIterator(); -}, 0)); - - [Container%s/getLazyContextIgnoreInvalidRefService.php] => services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function () { - yield 0 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->load('getFoo_BazService.php')) && false ?: '_'}; -}, 1), new RewindableGenerator(function () { - return new \EmptyIterator(); -}, 0)); - - [Container%s/getMethodCall1Service.php] => targetDirs[0].'/Fixtures/includes/foo.php'); - -$this->services['method_call1'] = $instance = new \Bar\FooClass(); - -$instance->setBar(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->load('getFooService.php')) && false ?: '_'}); -$instance->setBar(NULL); -$instance->setBar((${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->load('getFooService.php')) && false ?: '_'}->foo() . (($this->hasParameter("foo")) ? ($this->getParameter("foo")) : ("default")))); - -return $instance; - - [Container%s/getNewFactoryServiceService.php] => foo = 'bar'; - -$this->services['new_factory_service'] = $instance = $a->getInstance(); - -$instance->foo = 'bar'; - -return $instance; - - [Container%s/getServiceFromStaticMethodService.php] => services['service_from_static_method'] = \Bar\FooClass::getInstance(); - - [Container%s/getTaggedIteratorService.php] => services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () { - yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->load('getFooService.php')) && false ?: '_'}; - yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : ($this->services['tagged_iterator_foo'] = new \Bar())) && false ?: '_'}; -}, 2)); - - [Container%s/getTaggedIteratorFooService.php] => services['tagged_iterator_foo'] = new \Bar(); - - [Container%s/ProjectServiceContainer.php] => targetDirs[0] = \dirname($containerDir); - for ($i = 1; $i <= 5; ++$i) { - $this->targetDirs[$i] = $dir = \dirname($dir); - } - $this->buildParameters = $buildParameters; - $this->containerDir = $containerDir; - $this->parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->syntheticIds = [ - 'request' => true, - ]; - $this->methodMap = [ - 'bar' => 'getBarService', - 'foo_bar' => 'getFooBarService', - ]; - $this->fileMap = [ - 'baz' => 'getBazService.php', - 'configured_service' => 'getConfiguredServiceService.php', - 'configured_service_simple' => 'getConfiguredServiceSimpleService.php', - 'decorator_service' => 'getDecoratorServiceService.php', - 'decorator_service_with_name' => 'getDecoratorServiceWithNameService.php', - 'deprecated_service' => 'getDeprecatedServiceService.php', - 'factory_service' => 'getFactoryServiceService.php', - 'factory_service_simple' => 'getFactoryServiceSimpleService.php', - 'factory_simple' => 'getFactorySimpleService.php', - 'foo' => 'getFooService.php', - 'foo.baz' => 'getFoo_BazService.php', - 'foo_with_inline' => 'getFooWithInlineService.php', - 'lazy_context' => 'getLazyContextService.php', - 'lazy_context_ignore_invalid_ref' => 'getLazyContextIgnoreInvalidRefService.php', - 'method_call1' => 'getMethodCall1Service.php', - 'new_factory_service' => 'getNewFactoryServiceService.php', - 'service_from_static_method' => 'getServiceFromStaticMethodService.php', - 'tagged_iterator' => 'getTaggedIteratorService.php', - 'tagged_iterator_foo' => 'getTaggedIteratorFooService.php', - ]; - $this->privates = [ - 'factory_simple' => true, - 'tagged_iterator_foo' => true, - ]; - $this->aliases = [ - 'alias_for_alias' => 'foo', - 'alias_for_foo' => 'foo', - 'decorated' => 'decorator_service_with_name', - ]; - } - - public function getRemovedIds() - { - return require $this->containerDir.\DIRECTORY_SEPARATOR.'removed-ids.php'; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - protected function load($file, $lazyLoad = true) - { - return require $this->containerDir.\DIRECTORY_SEPARATOR.$file; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \Bar\FooClass - */ - protected function getBarService() - { - $a = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->load('getFoo_BazService.php')) && false ?: '_'}; - - $this->services['bar'] = $instance = new \Bar\FooClass('foo', $a, $this->getParameter('foo_bar')); - - $a->configure($instance); - - return $instance; - } - - /** - * Gets the public 'foo_bar' service. - * - * @return \Bar\FooClass - */ - protected function getFooBarService() - { - return new \Bar\FooClass(${($_ = isset($this->services['deprecated_service']) ? $this->services['deprecated_service'] : $this->load('getDeprecatedServiceService.php')) && false ?: '_'}); - } - - public function getParameter($name) - { - $name = (string) $name; - if (isset($this->buildParameters[$name])) { - return $this->buildParameters[$name]; - } - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - if (isset($this->buildParameters[$name])) { - return true; - } - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - foreach ($this->buildParameters as $name => $value) { - $parameters[$name] = $value; - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'baz_class' => 'BazClass', - 'foo_class' => 'Bar\\FooClass', - 'foo' => 'bar', - ]; - } -} - - [ProjectServiceContainer.php] => '%s', - 'container.build_id' => '%s', - 'container.build_time' => %d, -], __DIR__.\DIRECTORY_SEPARATOR.'Container%s'); - -) diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9_compiled.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9_compiled.php deleted file mode 100644 index c9df13b2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services9_compiled.php +++ /dev/null @@ -1,475 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->syntheticIds = [ - 'request' => true, - ]; - $this->methodMap = [ - 'bar' => 'getBarService', - 'baz' => 'getBazService', - 'configured_service' => 'getConfiguredServiceService', - 'configured_service_simple' => 'getConfiguredServiceSimpleService', - 'decorator_service' => 'getDecoratorServiceService', - 'decorator_service_with_name' => 'getDecoratorServiceWithNameService', - 'deprecated_service' => 'getDeprecatedServiceService', - 'factory_service' => 'getFactoryServiceService', - 'factory_service_simple' => 'getFactoryServiceSimpleService', - 'factory_simple' => 'getFactorySimpleService', - 'foo' => 'getFooService', - 'foo.baz' => 'getFoo_BazService', - 'foo_bar' => 'getFooBarService', - 'foo_with_inline' => 'getFooWithInlineService', - 'lazy_context' => 'getLazyContextService', - 'lazy_context_ignore_invalid_ref' => 'getLazyContextIgnoreInvalidRefService', - 'method_call1' => 'getMethodCall1Service', - 'new_factory_service' => 'getNewFactoryServiceService', - 'service_from_static_method' => 'getServiceFromStaticMethodService', - 'tagged_iterator' => 'getTaggedIteratorService', - 'tagged_iterator_foo' => 'getTaggedIteratorFooService', - ]; - $this->privates = [ - 'factory_simple' => true, - 'tagged_iterator_foo' => true, - ]; - $this->aliases = [ - 'alias_for_alias' => 'foo', - 'alias_for_foo' => 'foo', - 'decorated' => 'decorator_service_with_name', - ]; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'configurator_service' => true, - 'configurator_service_simple' => true, - 'decorated.pif-pouf' => true, - 'decorator_service.inner' => true, - 'factory_simple' => true, - 'inlined' => true, - 'new_factory' => true, - 'tagged_iterator_foo' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \Bar\FooClass - */ - protected function getBarService() - { - $a = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - - $this->services['bar'] = $instance = new \Bar\FooClass('foo', $a, $this->getParameter('foo_bar')); - - $a->configure($instance); - - return $instance; - } - - /** - * Gets the public 'baz' shared service. - * - * @return \Baz - */ - protected function getBazService() - { - $this->services['baz'] = $instance = new \Baz(); - - $instance->setFoo(${($_ = isset($this->services['foo_with_inline']) ? $this->services['foo_with_inline'] : $this->getFooWithInlineService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'configured_service' shared service. - * - * @return \stdClass - */ - protected function getConfiguredServiceService() - { - $this->services['configured_service'] = $instance = new \stdClass(); - - $a = new \ConfClass(); - $a->setFoo(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->getBazService()) && false ?: '_'}); - - $a->configureStdClass($instance); - - return $instance; - } - - /** - * Gets the public 'configured_service_simple' shared service. - * - * @return \stdClass - */ - protected function getConfiguredServiceSimpleService() - { - $this->services['configured_service_simple'] = $instance = new \stdClass(); - - (new \ConfClass('bar'))->configureStdClass($instance); - - return $instance; - } - - /** - * Gets the public 'decorator_service' shared service. - * - * @return \stdClass - */ - protected function getDecoratorServiceService() - { - return $this->services['decorator_service'] = new \stdClass(); - } - - /** - * Gets the public 'decorator_service_with_name' shared service. - * - * @return \stdClass - */ - protected function getDecoratorServiceWithNameService() - { - return $this->services['decorator_service_with_name'] = new \stdClass(); - } - - /** - * Gets the public 'deprecated_service' shared service. - * - * @return \stdClass - * - * @deprecated The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed. - */ - protected function getDeprecatedServiceService() - { - @trigger_error('The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); - - return $this->services['deprecated_service'] = new \stdClass(); - } - - /** - * Gets the public 'factory_service' shared service. - * - * @return \Bar - */ - protected function getFactoryServiceService() - { - return $this->services['factory_service'] = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}->getInstance(); - } - - /** - * Gets the public 'factory_service_simple' shared service. - * - * @return \Bar - */ - protected function getFactoryServiceSimpleService() - { - return $this->services['factory_service_simple'] = ${($_ = isset($this->services['factory_simple']) ? $this->services['factory_simple'] : $this->getFactorySimpleService()) && false ?: '_'}->getInstance(); - } - - /** - * Gets the public 'foo' shared service. - * - * @return \Bar\FooClass - */ - protected function getFooService() - { - $a = ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - - $this->services['foo'] = $instance = \Bar\FooClass::getInstance('foo', $a, ['bar' => 'foo is bar', 'foobar' => 'bar'], true, $this); - - $instance->foo = 'bar'; - $instance->moo = $a; - $instance->qux = ['bar' => 'foo is bar', 'foobar' => 'bar']; - $instance->setBar(${($_ = isset($this->services['bar']) ? $this->services['bar'] : $this->getBarService()) && false ?: '_'}); - $instance->initialize(); - sc_configure($instance); - - return $instance; - } - - /** - * Gets the public 'foo.baz' shared service. - * - * @return \BazClass - */ - protected function getFoo_BazService() - { - $this->services['foo.baz'] = $instance = \BazClass::getInstance(); - - \BazClass::configureStatic1($instance); - - return $instance; - } - - /** - * Gets the public 'foo_bar' service. - * - * @return \Bar\FooClass - */ - protected function getFooBarService() - { - return new \Bar\FooClass(${($_ = isset($this->services['deprecated_service']) ? $this->services['deprecated_service'] : $this->getDeprecatedServiceService()) && false ?: '_'}); - } - - /** - * Gets the public 'foo_with_inline' shared service. - * - * @return \Foo - */ - protected function getFooWithInlineService() - { - $this->services['foo_with_inline'] = $instance = new \Foo(); - - $a = new \Bar(); - $a->pub = 'pub'; - $a->setBaz(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->getBazService()) && false ?: '_'}); - - $instance->setBar($a); - - return $instance; - } - - /** - * Gets the public 'lazy_context' shared service. - * - * @return \LazyContext - */ - protected function getLazyContextService() - { - return $this->services['lazy_context'] = new \LazyContext(new RewindableGenerator(function () { - yield 'k1' => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - yield 'k2' => $this; - }, 2), new RewindableGenerator(function () { - return new \EmptyIterator(); - }, 0)); - } - - /** - * Gets the public 'lazy_context_ignore_invalid_ref' shared service. - * - * @return \LazyContext - */ - protected function getLazyContextIgnoreInvalidRefService() - { - return $this->services['lazy_context_ignore_invalid_ref'] = new \LazyContext(new RewindableGenerator(function () { - yield 0 => ${($_ = isset($this->services['foo.baz']) ? $this->services['foo.baz'] : $this->getFoo_BazService()) && false ?: '_'}; - }, 1), new RewindableGenerator(function () { - return new \EmptyIterator(); - }, 0)); - } - - /** - * Gets the public 'method_call1' shared service. - * - * @return \Bar\FooClass - */ - protected function getMethodCall1Service() - { - include_once '%path%foo.php'; - - $this->services['method_call1'] = $instance = new \Bar\FooClass(); - - $instance->setBar(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}); - $instance->setBar(NULL); - $instance->setBar((${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}->foo() . (($this->hasParameter("foo")) ? ($this->getParameter("foo")) : ("default")))); - - return $instance; - } - - /** - * Gets the public 'new_factory_service' shared service. - * - * @return \FooBarBaz - */ - protected function getNewFactoryServiceService() - { - $a = new \FactoryClass(); - $a->foo = 'bar'; - - $this->services['new_factory_service'] = $instance = $a->getInstance(); - - $instance->foo = 'bar'; - - return $instance; - } - - /** - * Gets the public 'service_from_static_method' shared service. - * - * @return \Bar\FooClass - */ - protected function getServiceFromStaticMethodService() - { - return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance(); - } - - /** - * Gets the public 'tagged_iterator' shared service. - * - * @return \Bar - */ - protected function getTaggedIteratorService() - { - return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(function () { - yield 0 => ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}; - yield 1 => ${($_ = isset($this->services['tagged_iterator_foo']) ? $this->services['tagged_iterator_foo'] : ($this->services['tagged_iterator_foo'] = new \Bar())) && false ?: '_'}; - }, 2)); - } - - /** - * Gets the private 'factory_simple' shared service. - * - * @return \SimpleFactoryClass - * - * @deprecated The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed. - */ - protected function getFactorySimpleService() - { - @trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED); - - return $this->services['factory_simple'] = new \SimpleFactoryClass('foo'); - } - - /** - * Gets the private 'tagged_iterator_foo' shared service. - * - * @return \Bar - */ - protected function getTaggedIteratorFooService() - { - return $this->services['tagged_iterator_foo'] = new \Bar(); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'baz_class' => 'BazClass', - 'foo_class' => 'Bar\\FooClass', - 'foo' => 'bar', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_adawson.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_adawson.php deleted file mode 100644 index f4364df7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_adawson.php +++ /dev/null @@ -1,190 +0,0 @@ -services = []; - $this->normalizedIds = [ - 'app\\bus' => 'App\\Bus', - 'app\\db' => 'App\\Db', - 'app\\handler1' => 'App\\Handler1', - 'app\\handler2' => 'App\\Handler2', - 'app\\processor' => 'App\\Processor', - 'app\\registry' => 'App\\Registry', - 'app\\schema' => 'App\\Schema', - ]; - $this->methodMap = [ - 'App\\Bus' => 'getBusService', - 'App\\Db' => 'getDbService', - 'App\\Handler1' => 'getHandler1Service', - 'App\\Handler2' => 'getHandler2Service', - 'App\\Processor' => 'getProcessorService', - 'App\\Registry' => 'getRegistryService', - 'App\\Schema' => 'getSchemaService', - ]; - $this->privates = [ - 'App\\Handler1' => true, - 'App\\Handler2' => true, - 'App\\Processor' => true, - 'App\\Registry' => true, - 'App\\Schema' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'App\\Handler1' => true, - 'App\\Handler2' => true, - 'App\\Processor' => true, - 'App\\Registry' => true, - 'App\\Schema' => true, - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'App\Bus' shared service. - * - * @return \App\Bus - */ - protected function getBusService() - { - $this->services['App\\Bus'] = $instance = new \App\Bus(${($_ = isset($this->services['App\\Db']) ? $this->services['App\\Db'] : $this->getDbService()) && false ?: '_'}); - - $instance->handler1 = ${($_ = isset($this->services['App\\Handler1']) ? $this->services['App\\Handler1'] : $this->getHandler1Service()) && false ?: '_'}; - $instance->handler2 = ${($_ = isset($this->services['App\\Handler2']) ? $this->services['App\\Handler2'] : $this->getHandler2Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'App\Db' shared service. - * - * @return \App\Db - */ - protected function getDbService() - { - $this->services['App\\Db'] = $instance = new \App\Db(); - - $instance->schema = ${($_ = isset($this->services['App\\Schema']) ? $this->services['App\\Schema'] : $this->getSchemaService()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the private 'App\Handler1' shared service. - * - * @return \App\Handler1 - */ - protected function getHandler1Service() - { - $a = ${($_ = isset($this->services['App\\Processor']) ? $this->services['App\\Processor'] : $this->getProcessorService()) && false ?: '_'}; - - if (isset($this->services['App\\Handler1'])) { - return $this->services['App\\Handler1']; - } - - return $this->services['App\\Handler1'] = new \App\Handler1(${($_ = isset($this->services['App\\Db']) ? $this->services['App\\Db'] : $this->getDbService()) && false ?: '_'}, ${($_ = isset($this->services['App\\Schema']) ? $this->services['App\\Schema'] : $this->getSchemaService()) && false ?: '_'}, $a); - } - - /** - * Gets the private 'App\Handler2' shared service. - * - * @return \App\Handler2 - */ - protected function getHandler2Service() - { - $a = ${($_ = isset($this->services['App\\Processor']) ? $this->services['App\\Processor'] : $this->getProcessorService()) && false ?: '_'}; - - if (isset($this->services['App\\Handler2'])) { - return $this->services['App\\Handler2']; - } - - return $this->services['App\\Handler2'] = new \App\Handler2(${($_ = isset($this->services['App\\Db']) ? $this->services['App\\Db'] : $this->getDbService()) && false ?: '_'}, ${($_ = isset($this->services['App\\Schema']) ? $this->services['App\\Schema'] : $this->getSchemaService()) && false ?: '_'}, $a); - } - - /** - * Gets the private 'App\Processor' shared service. - * - * @return \App\Processor - */ - protected function getProcessorService() - { - $a = ${($_ = isset($this->services['App\\Registry']) ? $this->services['App\\Registry'] : $this->getRegistryService()) && false ?: '_'}; - - if (isset($this->services['App\\Processor'])) { - return $this->services['App\\Processor']; - } - - return $this->services['App\\Processor'] = new \App\Processor($a, ${($_ = isset($this->services['App\\Db']) ? $this->services['App\\Db'] : $this->getDbService()) && false ?: '_'}); - } - - /** - * Gets the private 'App\Registry' shared service. - * - * @return \App\Registry - */ - protected function getRegistryService() - { - $this->services['App\\Registry'] = $instance = new \App\Registry(); - - $instance->processor = [0 => ${($_ = isset($this->services['App\\Db']) ? $this->services['App\\Db'] : $this->getDbService()) && false ?: '_'}, 1 => ${($_ = isset($this->services['App\\Bus']) ? $this->services['App\\Bus'] : $this->getBusService()) && false ?: '_'}]; - - return $instance; - } - - /** - * Gets the private 'App\Schema' shared service. - * - * @return \App\Schema - */ - protected function getSchemaService() - { - $a = ${($_ = isset($this->services['App\\Db']) ? $this->services['App\\Db'] : $this->getDbService()) && false ?: '_'}; - - if (isset($this->services['App\\Schema'])) { - return $this->services['App\\Schema']; - } - - return $this->services['App\\Schema'] = new \App\Schema($a); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_almost_circular_private.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_almost_circular_private.php deleted file mode 100644 index 775235db..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_almost_circular_private.php +++ /dev/null @@ -1,514 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar2' => 'getBar2Service', - 'bar3' => 'getBar3Service', - 'bar6' => 'getBar6Service', - 'baz6' => 'getBaz6Service', - 'connection' => 'getConnectionService', - 'connection2' => 'getConnection2Service', - 'foo' => 'getFooService', - 'foo2' => 'getFoo2Service', - 'foo5' => 'getFoo5Service', - 'foo6' => 'getFoo6Service', - 'foobar4' => 'getFoobar4Service', - 'level2' => 'getLevel2Service', - 'level3' => 'getLevel3Service', - 'level4' => 'getLevel4Service', - 'level5' => 'getLevel5Service', - 'level6' => 'getLevel6Service', - 'listener3' => 'getListener3Service', - 'listener4' => 'getListener4Service', - 'logger' => 'getLoggerService', - 'manager' => 'getManagerService', - 'manager2' => 'getManager2Service', - 'manager3' => 'getManager3Service', - 'manager4' => 'getManager4Service', - 'multiuse1' => 'getMultiuse1Service', - 'root' => 'getRootService', - 'subscriber' => 'getSubscriberService', - ]; - $this->privates = [ - 'bar6' => true, - 'level2' => true, - 'level3' => true, - 'level4' => true, - 'level5' => true, - 'level6' => true, - 'manager4' => true, - 'multiuse1' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'bar' => true, - 'bar5' => true, - 'bar6' => true, - 'config' => true, - 'config2' => true, - 'connection3' => true, - 'connection4' => true, - 'dispatcher' => true, - 'dispatcher2' => true, - 'foo4' => true, - 'foobar' => true, - 'foobar2' => true, - 'foobar3' => true, - 'level2' => true, - 'level3' => true, - 'level4' => true, - 'level5' => true, - 'level6' => true, - 'logger2' => true, - 'manager4' => true, - 'multiuse1' => true, - 'subscriber2' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar2' shared service. - * - * @return \BarCircular - */ - protected function getBar2Service() - { - $this->services['bar2'] = $instance = new \BarCircular(); - - $instance->addFoobar(new \FoobarCircular(${($_ = isset($this->services['foo2']) ? $this->services['foo2'] : $this->getFoo2Service()) && false ?: '_'})); - - return $instance; - } - - /** - * Gets the public 'bar3' shared service. - * - * @return \BarCircular - */ - protected function getBar3Service() - { - $this->services['bar3'] = $instance = new \BarCircular(); - - $a = new \FoobarCircular(); - - $instance->addFoobar($a, $a); - - return $instance; - } - - /** - * Gets the public 'baz6' shared service. - * - * @return \stdClass - */ - protected function getBaz6Service() - { - $this->services['baz6'] = $instance = new \stdClass(); - - $instance->bar6 = ${($_ = isset($this->services['bar6']) ? $this->services['bar6'] : $this->getBar6Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'connection' shared service. - * - * @return \stdClass - */ - protected function getConnectionService() - { - $a = new \stdClass(); - - $b = new \stdClass(); - - $this->services['connection'] = $instance = new \stdClass($a, $b); - - $b->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'}; - - $a->subscriber = ${($_ = isset($this->services['subscriber']) ? $this->services['subscriber'] : $this->getSubscriberService()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'connection2' shared service. - * - * @return \stdClass - */ - protected function getConnection2Service() - { - $a = new \stdClass(); - - $b = new \stdClass(); - - $this->services['connection2'] = $instance = new \stdClass($a, $b); - - $c = new \stdClass($instance); - - $d = ${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'}; - - $c->handler2 = new \stdClass($d); - - $b->logger2 = $c; - - $a->subscriber2 = new \stdClass($d); - - return $instance; - } - - /** - * Gets the public 'foo' shared service. - * - * @return \FooCircular - */ - protected function getFooService() - { - $a = new \BarCircular(); - - $this->services['foo'] = $instance = new \FooCircular($a); - - $a->addFoobar(new \FoobarCircular($instance)); - - return $instance; - } - - /** - * Gets the public 'foo2' shared service. - * - * @return \FooCircular - */ - protected function getFoo2Service() - { - $a = ${($_ = isset($this->services['bar2']) ? $this->services['bar2'] : $this->getBar2Service()) && false ?: '_'}; - - if (isset($this->services['foo2'])) { - return $this->services['foo2']; - } - - return $this->services['foo2'] = new \FooCircular($a); - } - - /** - * Gets the public 'foo5' shared service. - * - * @return \stdClass - */ - protected function getFoo5Service() - { - $this->services['foo5'] = $instance = new \stdClass(); - - $a = new \stdClass($instance); - $a->foo = $instance; - - $instance->bar = $a; - - return $instance; - } - - /** - * Gets the public 'foo6' shared service. - * - * @return \stdClass - */ - protected function getFoo6Service() - { - $this->services['foo6'] = $instance = new \stdClass(); - - $instance->bar6 = ${($_ = isset($this->services['bar6']) ? $this->services['bar6'] : $this->getBar6Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'foobar4' shared service. - * - * @return \stdClass - */ - protected function getFoobar4Service() - { - $a = new \stdClass(); - - $this->services['foobar4'] = $instance = new \stdClass($a); - - $a->foobar = $instance; - - return $instance; - } - - /** - * Gets the public 'listener3' shared service. - * - * @return \stdClass - */ - protected function getListener3Service() - { - $this->services['listener3'] = $instance = new \stdClass(); - - $instance->manager = ${($_ = isset($this->services['manager3']) ? $this->services['manager3'] : $this->getManager3Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'listener4' shared service. - * - * @return \stdClass - */ - protected function getListener4Service() - { - $a = ${($_ = isset($this->services['manager4']) ? $this->services['manager4'] : $this->getManager4Service()) && false ?: '_'}; - - if (isset($this->services['listener4'])) { - return $this->services['listener4']; - } - - return $this->services['listener4'] = new \stdClass($a); - } - - /** - * Gets the public 'logger' shared service. - * - * @return \stdClass - */ - protected function getLoggerService() - { - $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; - - if (isset($this->services['logger'])) { - return $this->services['logger']; - } - - $this->services['logger'] = $instance = new \stdClass($a); - - $instance->handler = new \stdClass(${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'manager' shared service. - * - * @return \stdClass - */ - protected function getManagerService() - { - $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; - - if (isset($this->services['manager'])) { - return $this->services['manager']; - } - - return $this->services['manager'] = new \stdClass($a); - } - - /** - * Gets the public 'manager2' shared service. - * - * @return \stdClass - */ - protected function getManager2Service() - { - $a = ${($_ = isset($this->services['connection2']) ? $this->services['connection2'] : $this->getConnection2Service()) && false ?: '_'}; - - if (isset($this->services['manager2'])) { - return $this->services['manager2']; - } - - return $this->services['manager2'] = new \stdClass($a); - } - - /** - * Gets the public 'manager3' shared service. - * - * @return \stdClass - */ - protected function getManager3Service($lazyLoad = true) - { - $a = ${($_ = isset($this->services['listener3']) ? $this->services['listener3'] : $this->getListener3Service()) && false ?: '_'}; - - if (isset($this->services['manager3'])) { - return $this->services['manager3']; - } - $b = new \stdClass(); - $b->listener = [0 => $a]; - - return $this->services['manager3'] = new \stdClass($b); - } - - /** - * Gets the public 'root' shared service. - * - * @return \stdClass - */ - protected function getRootService() - { - return $this->services['root'] = new \stdClass(${($_ = isset($this->services['level2']) ? $this->services['level2'] : $this->getLevel2Service()) && false ?: '_'}, ${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the public 'subscriber' shared service. - * - * @return \stdClass - */ - protected function getSubscriberService() - { - $a = ${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}; - - if (isset($this->services['subscriber'])) { - return $this->services['subscriber']; - } - - return $this->services['subscriber'] = new \stdClass($a); - } - - /** - * Gets the private 'bar6' shared service. - * - * @return \stdClass - */ - protected function getBar6Service() - { - $a = ${($_ = isset($this->services['foo6']) ? $this->services['foo6'] : $this->getFoo6Service()) && false ?: '_'}; - - if (isset($this->services['bar6'])) { - return $this->services['bar6']; - } - - return $this->services['bar6'] = new \stdClass($a); - } - - /** - * Gets the private 'level2' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls - */ - protected function getLevel2Service() - { - $this->services['level2'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls(); - - $instance->call(${($_ = isset($this->services['level3']) ? $this->services['level3'] : $this->getLevel3Service()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the private 'level3' shared service. - * - * @return \stdClass - */ - protected function getLevel3Service() - { - return $this->services['level3'] = new \stdClass(${($_ = isset($this->services['level4']) ? $this->services['level4'] : $this->getLevel4Service()) && false ?: '_'}); - } - - /** - * Gets the private 'level4' shared service. - * - * @return \stdClass - */ - protected function getLevel4Service() - { - return $this->services['level4'] = new \stdClass(${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'}, ${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'}); - } - - /** - * Gets the private 'level5' shared service. - * - * @return \stdClass - */ - protected function getLevel5Service() - { - $a = ${($_ = isset($this->services['level6']) ? $this->services['level6'] : $this->getLevel6Service()) && false ?: '_'}; - - if (isset($this->services['level5'])) { - return $this->services['level5']; - } - - return $this->services['level5'] = new \stdClass($a); - } - - /** - * Gets the private 'level6' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls - */ - protected function getLevel6Service() - { - $this->services['level6'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls(); - - $instance->call(${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the private 'manager4' shared service. - * - * @return \stdClass - */ - protected function getManager4Service($lazyLoad = true) - { - $a = new \stdClass(); - - $this->services['manager4'] = $instance = new \stdClass($a); - - $a->listener = [0 => ${($_ = isset($this->services['listener4']) ? $this->services['listener4'] : $this->getListener4Service()) && false ?: '_'}]; - - return $instance; - } - - /** - * Gets the private 'multiuse1' shared service. - * - * @return \stdClass - */ - protected function getMultiuse1Service() - { - return $this->services['multiuse1'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_almost_circular_public.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_almost_circular_public.php deleted file mode 100644 index d3bab912..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_almost_circular_public.php +++ /dev/null @@ -1,640 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'bar3' => 'getBar3Service', - 'bar5' => 'getBar5Service', - 'bar6' => 'getBar6Service', - 'baz6' => 'getBaz6Service', - 'connection' => 'getConnectionService', - 'connection2' => 'getConnection2Service', - 'connection3' => 'getConnection3Service', - 'connection4' => 'getConnection4Service', - 'dispatcher' => 'getDispatcherService', - 'dispatcher2' => 'getDispatcher2Service', - 'foo' => 'getFooService', - 'foo2' => 'getFoo2Service', - 'foo4' => 'getFoo4Service', - 'foo5' => 'getFoo5Service', - 'foo6' => 'getFoo6Service', - 'foobar' => 'getFoobarService', - 'foobar2' => 'getFoobar2Service', - 'foobar3' => 'getFoobar3Service', - 'foobar4' => 'getFoobar4Service', - 'level2' => 'getLevel2Service', - 'level3' => 'getLevel3Service', - 'level4' => 'getLevel4Service', - 'level5' => 'getLevel5Service', - 'level6' => 'getLevel6Service', - 'listener3' => 'getListener3Service', - 'listener4' => 'getListener4Service', - 'logger' => 'getLoggerService', - 'manager' => 'getManagerService', - 'manager2' => 'getManager2Service', - 'manager3' => 'getManager3Service', - 'manager4' => 'getManager4Service', - 'multiuse1' => 'getMultiuse1Service', - 'root' => 'getRootService', - 'subscriber' => 'getSubscriberService', - ]; - $this->privates = [ - 'bar6' => true, - 'level2' => true, - 'level3' => true, - 'level4' => true, - 'level5' => true, - 'level6' => true, - 'manager4' => true, - 'multiuse1' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'bar2' => true, - 'bar6' => true, - 'config' => true, - 'config2' => true, - 'level2' => true, - 'level3' => true, - 'level4' => true, - 'level5' => true, - 'level6' => true, - 'logger2' => true, - 'manager4' => true, - 'multiuse1' => true, - 'subscriber2' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \BarCircular - */ - protected function getBarService() - { - $this->services['bar'] = $instance = new \BarCircular(); - - $instance->addFoobar(${($_ = isset($this->services['foobar']) ? $this->services['foobar'] : $this->getFoobarService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'bar3' shared service. - * - * @return \BarCircular - */ - protected function getBar3Service() - { - $this->services['bar3'] = $instance = new \BarCircular(); - - $a = ${($_ = isset($this->services['foobar3']) ? $this->services['foobar3'] : ($this->services['foobar3'] = new \FoobarCircular())) && false ?: '_'}; - - $instance->addFoobar($a, $a); - - return $instance; - } - - /** - * Gets the public 'bar5' shared service. - * - * @return \stdClass - */ - protected function getBar5Service() - { - $a = ${($_ = isset($this->services['foo5']) ? $this->services['foo5'] : $this->getFoo5Service()) && false ?: '_'}; - - if (isset($this->services['bar5'])) { - return $this->services['bar5']; - } - - $this->services['bar5'] = $instance = new \stdClass($a); - - $instance->foo = $a; - - return $instance; - } - - /** - * Gets the public 'baz6' shared service. - * - * @return \stdClass - */ - protected function getBaz6Service() - { - $this->services['baz6'] = $instance = new \stdClass(); - - $instance->bar6 = ${($_ = isset($this->services['bar6']) ? $this->services['bar6'] : $this->getBar6Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'connection' shared service. - * - * @return \stdClass - */ - protected function getConnectionService() - { - $a = ${($_ = isset($this->services['dispatcher']) ? $this->services['dispatcher'] : $this->getDispatcherService()) && false ?: '_'}; - - if (isset($this->services['connection'])) { - return $this->services['connection']; - } - $b = new \stdClass(); - - $this->services['connection'] = $instance = new \stdClass($a, $b); - - $b->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'connection2' shared service. - * - * @return \stdClass - */ - protected function getConnection2Service() - { - $a = ${($_ = isset($this->services['dispatcher2']) ? $this->services['dispatcher2'] : $this->getDispatcher2Service()) && false ?: '_'}; - - if (isset($this->services['connection2'])) { - return $this->services['connection2']; - } - $b = new \stdClass(); - - $this->services['connection2'] = $instance = new \stdClass($a, $b); - - $c = new \stdClass($instance); - $c->handler2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'}); - - $b->logger2 = $c; - - return $instance; - } - - /** - * Gets the public 'connection3' shared service. - * - * @return \stdClass - */ - protected function getConnection3Service() - { - $this->services['connection3'] = $instance = new \stdClass(); - - $instance->listener = [0 => ${($_ = isset($this->services['listener3']) ? $this->services['listener3'] : $this->getListener3Service()) && false ?: '_'}]; - - return $instance; - } - - /** - * Gets the public 'connection4' shared service. - * - * @return \stdClass - */ - protected function getConnection4Service() - { - $this->services['connection4'] = $instance = new \stdClass(); - - $instance->listener = [0 => ${($_ = isset($this->services['listener4']) ? $this->services['listener4'] : $this->getListener4Service()) && false ?: '_'}]; - - return $instance; - } - - /** - * Gets the public 'dispatcher' shared service. - * - * @return \stdClass - */ - protected function getDispatcherService($lazyLoad = true) - { - $this->services['dispatcher'] = $instance = new \stdClass(); - - $instance->subscriber = ${($_ = isset($this->services['subscriber']) ? $this->services['subscriber'] : $this->getSubscriberService()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'dispatcher2' shared service. - * - * @return \stdClass - */ - protected function getDispatcher2Service($lazyLoad = true) - { - $this->services['dispatcher2'] = $instance = new \stdClass(); - - $instance->subscriber2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'foo' shared service. - * - * @return \FooCircular - */ - protected function getFooService() - { - $a = ${($_ = isset($this->services['bar']) ? $this->services['bar'] : $this->getBarService()) && false ?: '_'}; - - if (isset($this->services['foo'])) { - return $this->services['foo']; - } - - return $this->services['foo'] = new \FooCircular($a); - } - - /** - * Gets the public 'foo2' shared service. - * - * @return \FooCircular - */ - protected function getFoo2Service() - { - $a = new \BarCircular(); - - $this->services['foo2'] = $instance = new \FooCircular($a); - - $a->addFoobar(${($_ = isset($this->services['foobar2']) ? $this->services['foobar2'] : $this->getFoobar2Service()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'foo4' service. - * - * @return \stdClass - */ - protected function getFoo4Service() - { - $instance = new \stdClass(); - - $instance->foobar = ${($_ = isset($this->services['foobar4']) ? $this->services['foobar4'] : $this->getFoobar4Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'foo5' shared service. - * - * @return \stdClass - */ - protected function getFoo5Service() - { - $this->services['foo5'] = $instance = new \stdClass(); - - $instance->bar = ${($_ = isset($this->services['bar5']) ? $this->services['bar5'] : $this->getBar5Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'foo6' shared service. - * - * @return \stdClass - */ - protected function getFoo6Service() - { - $this->services['foo6'] = $instance = new \stdClass(); - - $instance->bar6 = ${($_ = isset($this->services['bar6']) ? $this->services['bar6'] : $this->getBar6Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'foobar' shared service. - * - * @return \FoobarCircular - */ - protected function getFoobarService() - { - $a = ${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}; - - if (isset($this->services['foobar'])) { - return $this->services['foobar']; - } - - return $this->services['foobar'] = new \FoobarCircular($a); - } - - /** - * Gets the public 'foobar2' shared service. - * - * @return \FoobarCircular - */ - protected function getFoobar2Service() - { - $a = ${($_ = isset($this->services['foo2']) ? $this->services['foo2'] : $this->getFoo2Service()) && false ?: '_'}; - - if (isset($this->services['foobar2'])) { - return $this->services['foobar2']; - } - - return $this->services['foobar2'] = new \FoobarCircular($a); - } - - /** - * Gets the public 'foobar3' shared service. - * - * @return \FoobarCircular - */ - protected function getFoobar3Service() - { - return $this->services['foobar3'] = new \FoobarCircular(); - } - - /** - * Gets the public 'foobar4' shared service. - * - * @return \stdClass - */ - protected function getFoobar4Service() - { - $a = new \stdClass(); - - $this->services['foobar4'] = $instance = new \stdClass($a); - - $a->foobar = $instance; - - return $instance; - } - - /** - * Gets the public 'listener3' shared service. - * - * @return \stdClass - */ - protected function getListener3Service() - { - $this->services['listener3'] = $instance = new \stdClass(); - - $instance->manager = ${($_ = isset($this->services['manager3']) ? $this->services['manager3'] : $this->getManager3Service()) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'listener4' shared service. - * - * @return \stdClass - */ - protected function getListener4Service() - { - $a = ${($_ = isset($this->services['manager4']) ? $this->services['manager4'] : $this->getManager4Service()) && false ?: '_'}; - - if (isset($this->services['listener4'])) { - return $this->services['listener4']; - } - - return $this->services['listener4'] = new \stdClass($a); - } - - /** - * Gets the public 'logger' shared service. - * - * @return \stdClass - */ - protected function getLoggerService() - { - $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; - - if (isset($this->services['logger'])) { - return $this->services['logger']; - } - - $this->services['logger'] = $instance = new \stdClass($a); - - $instance->handler = new \stdClass(${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'manager' shared service. - * - * @return \stdClass - */ - protected function getManagerService() - { - $a = ${($_ = isset($this->services['connection']) ? $this->services['connection'] : $this->getConnectionService()) && false ?: '_'}; - - if (isset($this->services['manager'])) { - return $this->services['manager']; - } - - return $this->services['manager'] = new \stdClass($a); - } - - /** - * Gets the public 'manager2' shared service. - * - * @return \stdClass - */ - protected function getManager2Service() - { - $a = ${($_ = isset($this->services['connection2']) ? $this->services['connection2'] : $this->getConnection2Service()) && false ?: '_'}; - - if (isset($this->services['manager2'])) { - return $this->services['manager2']; - } - - return $this->services['manager2'] = new \stdClass($a); - } - - /** - * Gets the public 'manager3' shared service. - * - * @return \stdClass - */ - protected function getManager3Service($lazyLoad = true) - { - $a = ${($_ = isset($this->services['connection3']) ? $this->services['connection3'] : $this->getConnection3Service()) && false ?: '_'}; - - if (isset($this->services['manager3'])) { - return $this->services['manager3']; - } - - return $this->services['manager3'] = new \stdClass($a); - } - - /** - * Gets the public 'root' shared service. - * - * @return \stdClass - */ - protected function getRootService() - { - return $this->services['root'] = new \stdClass(${($_ = isset($this->services['level2']) ? $this->services['level2'] : $this->getLevel2Service()) && false ?: '_'}, ${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the public 'subscriber' shared service. - * - * @return \stdClass - */ - protected function getSubscriberService() - { - $a = ${($_ = isset($this->services['manager']) ? $this->services['manager'] : $this->getManagerService()) && false ?: '_'}; - - if (isset($this->services['subscriber'])) { - return $this->services['subscriber']; - } - - return $this->services['subscriber'] = new \stdClass($a); - } - - /** - * Gets the private 'bar6' shared service. - * - * @return \stdClass - */ - protected function getBar6Service() - { - $a = ${($_ = isset($this->services['foo6']) ? $this->services['foo6'] : $this->getFoo6Service()) && false ?: '_'}; - - if (isset($this->services['bar6'])) { - return $this->services['bar6']; - } - - return $this->services['bar6'] = new \stdClass($a); - } - - /** - * Gets the private 'level2' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls - */ - protected function getLevel2Service() - { - $this->services['level2'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls(); - - $instance->call(${($_ = isset($this->services['level3']) ? $this->services['level3'] : $this->getLevel3Service()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the private 'level3' shared service. - * - * @return \stdClass - */ - protected function getLevel3Service() - { - return $this->services['level3'] = new \stdClass(${($_ = isset($this->services['level4']) ? $this->services['level4'] : $this->getLevel4Service()) && false ?: '_'}); - } - - /** - * Gets the private 'level4' shared service. - * - * @return \stdClass - */ - protected function getLevel4Service() - { - return $this->services['level4'] = new \stdClass(${($_ = isset($this->services['multiuse1']) ? $this->services['multiuse1'] : ($this->services['multiuse1'] = new \stdClass())) && false ?: '_'}, ${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'}); - } - - /** - * Gets the private 'level5' shared service. - * - * @return \stdClass - */ - protected function getLevel5Service() - { - $a = ${($_ = isset($this->services['level6']) ? $this->services['level6'] : $this->getLevel6Service()) && false ?: '_'}; - - if (isset($this->services['level5'])) { - return $this->services['level5']; - } - - return $this->services['level5'] = new \stdClass($a); - } - - /** - * Gets the private 'level6' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls - */ - protected function getLevel6Service() - { - $this->services['level6'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\FooForCircularWithAddCalls(); - - $instance->call(${($_ = isset($this->services['level5']) ? $this->services['level5'] : $this->getLevel5Service()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the private 'manager4' shared service. - * - * @return \stdClass - */ - protected function getManager4Service($lazyLoad = true) - { - $a = ${($_ = isset($this->services['connection4']) ? $this->services['connection4'] : $this->getConnection4Service()) && false ?: '_'}; - - if (isset($this->services['manager4'])) { - return $this->services['manager4']; - } - - return $this->services['manager4'] = new \stdClass($a); - } - - /** - * Gets the private 'multiuse1' shared service. - * - * @return \stdClass - */ - protected function getMultiuse1Service() - { - return $this->services['multiuse1'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_array_params.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_array_params.php deleted file mode 100644 index dd1ca0a6..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_array_params.php +++ /dev/null @@ -1,176 +0,0 @@ -targetDirs[$i] = $dir = \dirname($dir); - } - $this->parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \BarClass - */ - protected function getBarService() - { - $this->services['bar'] = $instance = new \BarClass(); - - $instance->setBaz($this->parameters['array_1'], $this->getParameter('array_2'), '%array_1%', $this->parameters['array_1']); - - return $instance; - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = [ - 'array_2' => false, - ]; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - switch ($name) { - case 'array_2': $value = [ - 0 => ($this->targetDirs[2].'/Dumper'), - ]; break; - default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - $this->loadedDynamicParameters[$name] = true; - - return $this->dynamicParameters[$name] = $value; - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'array_1' => [ - 0 => 123, - ], - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_base64_env.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_base64_env.php deleted file mode 100644 index 709a3c4f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_base64_env.php +++ /dev/null @@ -1,151 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = [ - 'hello' => false, - ]; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - switch ($name) { - case 'hello': $value = $this->getEnv('base64:foo'); break; - default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - $this->loadedDynamicParameters[$name] = true; - - return $this->dynamicParameters[$name] = $value; - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'env(foo)' => 'd29ybGQ=', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_dedup_lazy_proxy.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_dedup_lazy_proxy.php deleted file mode 100644 index 096b3b39..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_dedup_lazy_proxy.php +++ /dev/null @@ -1,88 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'foo' => 'getFooService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - protected function createProxy($class, \Closure $factory) - { - return $factory(); - } - - /** - * Gets the public 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService($lazyLoad = true) - { - // lazy factory for stdClass - - return new \stdClass(); - } - - /** - * Gets the public 'foo' shared service. - * - * @return \stdClass - */ - protected function getFooService($lazyLoad = true) - { - // lazy factory for stdClass - - return new \stdClass(); - } -} - -// proxy code for stdClass diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_deep_graph.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_deep_graph.php deleted file mode 100644 index 0e3eed27..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_deep_graph.php +++ /dev/null @@ -1,93 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'foo' => 'getFooService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService() - { - $this->services['bar'] = $instance = new \stdClass(); - - $instance->p5 = new \stdClass(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}); - - return $instance; - } - - /** - * Gets the public 'foo' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Dumper\FooForDeepGraph - */ - protected function getFooService() - { - $a = ${($_ = isset($this->services['bar']) ? $this->services['bar'] : $this->getBarService()) && false ?: '_'}; - - if (isset($this->services['foo'])) { - return $this->services['foo']; - } - $b = new \stdClass(); - - $c = new \stdClass(); - $c->p3 = new \stdClass(); - - $b->p2 = $c; - - return $this->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\FooForDeepGraph($a, $b); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_env_in_id.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_env_in_id.php deleted file mode 100644 index e0e4827d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_env_in_id.php +++ /dev/null @@ -1,188 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->normalizedIds = [ - 'bar_%env(bar)%' => 'bar_%env(BAR)%', - ]; - $this->methodMap = [ - 'bar' => 'getBarService', - 'bar_%env(BAR)%' => 'getBarenvBARService', - 'foo' => 'getFooService', - ]; - $this->privates = [ - 'bar_%env(BAR)%' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'bar_%env(BAR)%' => true, - 'baz_%env(BAR)%' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService() - { - return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : ($this->services['bar_%env(BAR)%'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the public 'foo' shared service. - * - * @return \stdClass - */ - protected function getFooService() - { - return $this->services['foo'] = new \stdClass(${($_ = isset($this->services['bar_%env(BAR)%']) ? $this->services['bar_%env(BAR)%'] : ($this->services['bar_%env(BAR)%'] = new \stdClass())) && false ?: '_'}, ['baz_'.$this->getEnv('string:BAR') => new \stdClass()]); - } - - /** - * Gets the private 'bar_%env(BAR)%' shared service. - * - * @return \stdClass - */ - protected function getBarenvBARService() - { - return $this->services['bar_%env(BAR)%'] = new \stdClass(); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = [ - 'env(bar)' => 'env(BAR)', - ]; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'env(BAR)' => 'bar', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_inline_requires.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_inline_requires.php deleted file mode 100644 index 84187883..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_inline_requires.php +++ /dev/null @@ -1,215 +0,0 @@ -targetDirs[$i] = $dir = \dirname($dir); - } - $this->parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->normalizedIds = [ - 'symfony\\component\\dependencyinjection\\tests\\fixtures\\includes\\hotpath\\c1' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C1', - 'symfony\\component\\dependencyinjection\\tests\\fixtures\\includes\\hotpath\\c2' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C2', - 'symfony\\component\\dependencyinjection\\tests\\fixtures\\includes\\hotpath\\c3' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3', - 'symfony\\component\\dependencyinjection\\tests\\fixtures\\parentnotexists' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\ParentNotExists', - ]; - $this->methodMap = [ - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\ParentNotExists' => 'getParentNotExistsService', - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C1' => 'getC1Service', - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C2' => 'getC2Service', - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3' => 'getC3Service', - ]; - $this->privates = [ - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3' => true, - ]; - - $this->aliases = []; - - $this->privates['service_container'] = function () { - include_once $this->targetDirs[1].'/includes/HotPath/I1.php'; - include_once $this->targetDirs[1].'/includes/HotPath/P1.php'; - include_once $this->targetDirs[1].'/includes/HotPath/T1.php'; - include_once $this->targetDirs[1].'/includes/HotPath/C1.php'; - }; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists - */ - protected function getParentNotExistsService() - { - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\ParentNotExists'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists(); - } - - /** - * Gets the public 'Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C1' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C1 - */ - protected function getC1Service() - { - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C1'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C1(); - } - - /** - * Gets the public 'Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2 - */ - protected function getC2Service() - { - include_once $this->targetDirs[1].'/includes/HotPath/C2.php'; - include_once $this->targetDirs[1].'/includes/HotPath/C3.php'; - - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C2'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C2(${($_ = isset($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3']) ? $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3'] : ($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3())) && false ?: '_'}); - } - - /** - * Gets the private 'Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3 - */ - protected function getC3Service() - { - include_once $this->targetDirs[1].'/includes/HotPath/C3.php'; - - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\includes\\HotPath\\C3'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\includes\HotPath\C3(); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'inline_requires' => true, - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_inline_self_ref.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_inline_self_ref.php deleted file mode 100644 index 906b0cdc..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_inline_self_ref.php +++ /dev/null @@ -1,78 +0,0 @@ -services = []; - $this->normalizedIds = [ - 'app\\foo' => 'App\\Foo', - ]; - $this->methodMap = [ - 'App\\Foo' => 'getFooService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'App\Foo' shared service. - * - * @return \App\Foo - */ - protected function getFooService() - { - $a = new \App\Bar(); - - $b = new \App\Baz($a); - $b->bar = $a; - - $this->services['App\\Foo'] = $instance = new \App\Foo($b); - - $a->foo = $instance; - - return $instance; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_legacy_privates.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_legacy_privates.php deleted file mode 100644 index 9a060617..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_legacy_privates.php +++ /dev/null @@ -1,193 +0,0 @@ -targetDirs[$i] = $dir = \dirname($dir); - } - $this->services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'private' => 'getPrivateService', - 'private_alias' => 'getPrivateAliasService', - 'private_alias_decorator' => 'getPrivateAliasDecoratorService', - 'private_child' => 'getPrivateChildService', - 'private_decorator' => 'getPrivateDecoratorService', - 'private_not_inlined' => 'getPrivateNotInlinedService', - 'private_not_removed' => 'getPrivateNotRemovedService', - 'private_parent' => 'getPrivateParentService', - 'public_child' => 'getPublicChildService', - ]; - $this->privates = [ - 'decorated_private' => true, - 'decorated_private_alias' => true, - 'private' => true, - 'private_alias' => true, - 'private_child' => true, - 'private_not_inlined' => true, - 'private_not_removed' => true, - 'private_parent' => true, - ]; - $this->aliases = [ - 'alias_to_private' => 'private', - 'decorated_private' => 'private_decorator', - 'decorated_private_alias' => 'private_alias_decorator', - ]; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'decorated_private' => true, - 'decorated_private_alias' => true, - 'foo' => true, - 'private' => true, - 'private_alias' => true, - 'private_alias_decorator.inner' => true, - 'private_child' => true, - 'private_decorator.inner' => true, - 'private_not_inlined' => true, - 'private_not_removed' => true, - 'private_parent' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService() - { - return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['private_not_inlined']) ? $this->services['private_not_inlined'] : ($this->services['private_not_inlined'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the public 'private_alias_decorator' shared service. - * - * @return \stdClass - */ - protected function getPrivateAliasDecoratorService() - { - return $this->services['private_alias_decorator'] = new \stdClass(); - } - - /** - * Gets the public 'private_decorator' shared service. - * - * @return \stdClass - */ - protected function getPrivateDecoratorService() - { - return $this->services['private_decorator'] = new \stdClass(); - } - - /** - * Gets the public 'public_child' shared service. - * - * @return \stdClass - */ - protected function getPublicChildService() - { - return $this->services['public_child'] = new \stdClass(); - } - - /** - * Gets the private 'private' shared service. - * - * @return \stdClass - */ - protected function getPrivateService() - { - return $this->services['private'] = new \stdClass(); - } - - /** - * Gets the private 'private_alias' shared service. - * - * @return \stdClass - */ - protected function getPrivateAliasService() - { - return $this->services['private_alias'] = new \stdClass(); - } - - /** - * Gets the private 'private_child' shared service. - * - * @return \stdClass - */ - protected function getPrivateChildService() - { - return $this->services['private_child'] = new \stdClass(); - } - - /** - * Gets the private 'private_not_inlined' shared service. - * - * @return \stdClass - */ - protected function getPrivateNotInlinedService() - { - return $this->services['private_not_inlined'] = new \stdClass(); - } - - /** - * Gets the private 'private_not_removed' shared service. - * - * @return \stdClass - */ - protected function getPrivateNotRemovedService() - { - return $this->services['private_not_removed'] = new \stdClass(); - } - - /** - * Gets the private 'private_parent' shared service. - * - * @return \stdClass - */ - protected function getPrivateParentService() - { - return $this->services['private_parent'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_locator.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_locator.php deleted file mode 100644 index 3826d5a6..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_locator.php +++ /dev/null @@ -1,184 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar_service' => 'getBarServiceService', - 'baz_service' => 'getBazServiceService', - 'foo_service' => 'getFooServiceService', - 'translator.loader_1' => 'getTranslator_Loader1Service', - 'translator.loader_2' => 'getTranslator_Loader2Service', - 'translator.loader_3' => 'getTranslator_Loader3Service', - 'translator_1' => 'getTranslator1Service', - 'translator_2' => 'getTranslator2Service', - 'translator_3' => 'getTranslator3Service', - ]; - $this->privates = [ - 'baz_service' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'baz_service' => true, - 'translator.loader_1_locator' => true, - 'translator.loader_2_locator' => true, - 'translator.loader_3_locator' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar_service' shared service. - * - * @return \stdClass - */ - protected function getBarServiceService() - { - return $this->services['bar_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the public 'foo_service' shared service. - * - * @return \Symfony\Component\DependencyInjection\ServiceLocator - */ - protected function getFooServiceService() - { - return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\ServiceLocator(['bar' => function () { - return ${($_ = isset($this->services['bar_service']) ? $this->services['bar_service'] : $this->getBarServiceService()) && false ?: '_'}; - }, 'baz' => function () { - $f = function (\stdClass $v) { return $v; }; return $f(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'}); - }, 'nil' => function () { - return NULL; - }]); - } - - /** - * Gets the public 'translator.loader_1' shared service. - * - * @return \stdClass - */ - protected function getTranslator_Loader1Service() - { - return $this->services['translator.loader_1'] = new \stdClass(); - } - - /** - * Gets the public 'translator.loader_2' shared service. - * - * @return \stdClass - */ - protected function getTranslator_Loader2Service() - { - return $this->services['translator.loader_2'] = new \stdClass(); - } - - /** - * Gets the public 'translator.loader_3' shared service. - * - * @return \stdClass - */ - protected function getTranslator_Loader3Service() - { - return $this->services['translator.loader_3'] = new \stdClass(); - } - - /** - * Gets the public 'translator_1' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator - */ - protected function getTranslator1Service() - { - return $this->services['translator_1'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator(new \Symfony\Component\DependencyInjection\ServiceLocator(['translator.loader_1' => function () { - return ${($_ = isset($this->services['translator.loader_1']) ? $this->services['translator.loader_1'] : ($this->services['translator.loader_1'] = new \stdClass())) && false ?: '_'}; - }])); - } - - /** - * Gets the public 'translator_2' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator - */ - protected function getTranslator2Service() - { - $this->services['translator_2'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator(new \Symfony\Component\DependencyInjection\ServiceLocator(['translator.loader_2' => function () { - return ${($_ = isset($this->services['translator.loader_2']) ? $this->services['translator.loader_2'] : ($this->services['translator.loader_2'] = new \stdClass())) && false ?: '_'}; - }])); - - $instance->addResource('db', ${($_ = isset($this->services['translator.loader_2']) ? $this->services['translator.loader_2'] : ($this->services['translator.loader_2'] = new \stdClass())) && false ?: '_'}, 'nl'); - - return $instance; - } - - /** - * Gets the public 'translator_3' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator - */ - protected function getTranslator3Service() - { - $this->services['translator_3'] = $instance = new \Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator(new \Symfony\Component\DependencyInjection\ServiceLocator(['translator.loader_3' => function () { - return ${($_ = isset($this->services['translator.loader_3']) ? $this->services['translator.loader_3'] : ($this->services['translator.loader_3'] = new \stdClass())) && false ?: '_'}; - }])); - - $a = ${($_ = isset($this->services['translator.loader_3']) ? $this->services['translator.loader_3'] : ($this->services['translator.loader_3'] = new \stdClass())) && false ?: '_'}; - - $instance->addResource('db', $a, 'nl'); - $instance->addResource('db', $a, 'en'); - - return $instance; - } - - /** - * Gets the private 'baz_service' shared service. - * - * @return \stdClass - */ - protected function getBazServiceService() - { - return $this->services['baz_service'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_non_shared_lazy.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_non_shared_lazy.php deleted file mode 100644 index 4cea5d2d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_non_shared_lazy.php +++ /dev/null @@ -1,92 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'foo' => 'getFooService', - ]; - $this->privates = [ - 'bar' => true, - 'foo' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'bar' => true, - 'foo' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - protected function createProxy($class, \Closure $factory) - { - return $factory(); - } - - /** - * Gets the private 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService() - { - return $this->services['bar'] = new \stdClass(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'}); - } - - /** - * Gets the private 'foo' service. - * - * @return \stdClass - */ - protected function getFooService($lazyLoad = true) - { - // lazy factory for stdClass - - return new \stdClass(); - } -} - -// proxy code for stdClass diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_private_frozen.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_private_frozen.php deleted file mode 100644 index 95995dec..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_private_frozen.php +++ /dev/null @@ -1,92 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar_service' => 'getBarServiceService', - 'baz_service' => 'getBazServiceService', - 'foo_service' => 'getFooServiceService', - ]; - $this->privates = [ - 'baz_service' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'baz_service' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar_service' shared service. - * - * @return \stdClass - */ - protected function getBarServiceService() - { - return $this->services['bar_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the public 'foo_service' shared service. - * - * @return \stdClass - */ - protected function getFooServiceService() - { - return $this->services['foo_service'] = new \stdClass(${($_ = isset($this->services['baz_service']) ? $this->services['baz_service'] : ($this->services['baz_service'] = new \stdClass())) && false ?: '_'}); - } - - /** - * Gets the private 'baz_service' shared service. - * - * @return \stdClass - */ - protected function getBazServiceService() - { - return $this->services['baz_service'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_private_in_expression.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_private_in_expression.php deleted file mode 100644 index 56d73c25..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_private_in_expression.php +++ /dev/null @@ -1,82 +0,0 @@ -services = []; - $this->methodMap = [ - 'private_foo' => 'getPrivateFooService', - 'public_foo' => 'getPublicFooService', - ]; - $this->privates = [ - 'private_foo' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'private_bar' => true, - 'private_foo' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'public_foo' shared service. - * - * @return \stdClass - */ - protected function getPublicFooService() - { - return $this->services['public_foo'] = new \stdClass(${($_ = isset($this->services['private_foo']) ? $this->services['private_foo'] : ($this->services['private_foo'] = new \stdClass())) && false ?: '_'}->bar); - } - - /** - * Gets the private 'private_foo' shared service. - * - * @return \stdClass - */ - protected function getPrivateFooService() - { - return $this->services['private_foo'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_rot13_env.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_rot13_env.php deleted file mode 100644 index a7ad1f1c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_rot13_env.php +++ /dev/null @@ -1,180 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->normalizedIds = [ - 'symfony\\component\\dependencyinjection\\tests\\dumper\\rot13envvarprocessor' => 'Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor', - ]; - $this->methodMap = [ - 'Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor' => 'getRot13EnvVarProcessorService', - 'container.env_var_processors_locator' => 'getContainer_EnvVarProcessorsLocatorService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor - */ - protected function getRot13EnvVarProcessorService() - { - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor(); - } - - /** - * Gets the public 'container.env_var_processors_locator' shared service. - * - * @return \Symfony\Component\DependencyInjection\ServiceLocator - */ - protected function getContainer_EnvVarProcessorsLocatorService() - { - return $this->services['container.env_var_processors_locator'] = new \Symfony\Component\DependencyInjection\ServiceLocator(['rot13' => function () { - return ${($_ = isset($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor']) ? $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor'] : ($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Dumper\\Rot13EnvVarProcessor'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\Rot13EnvVarProcessor())) && false ?: '_'}; - }]); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = [ - 'hello' => false, - ]; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - switch ($name) { - case 'hello': $value = $this->getEnv('rot13:foo'); break; - default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - $this->loadedDynamicParameters[$name] = true; - - return $this->dynamicParameters[$name] = $value; - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - 'env(foo)' => 'jbeyq', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_subscriber.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_subscriber.php deleted file mode 100644 index ca89e01c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_subscriber.php +++ /dev/null @@ -1,106 +0,0 @@ -services = []; - $this->normalizedIds = [ - 'symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition', - 'symfony\\component\\dependencyinjection\\tests\\fixtures\\testservicesubscriber' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber', - ]; - $this->methodMap = [ - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'getCustomDefinitionService', - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'getTestServiceSubscriberService', - 'foo_service' => 'getFooServiceService', - ]; - $this->privates = [ - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true, - 'service_locator.jmktfsv' => true, - 'service_locator.jmktfsv.foo_service' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber - */ - protected function getTestServiceSubscriberService() - { - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber(); - } - - /** - * Gets the public 'foo_service' shared autowired service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber - */ - protected function getFooServiceService() - { - return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber((new \Symfony\Component\DependencyInjection\ServiceLocator(['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => function () { - $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition']) ? $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition'] : ($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition())) && false ?: '_'}); - }, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => function () { - $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber']) ? $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber'] : ($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber())) && false ?: '_'}); - }, 'bar' => function () { - $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber']) ? $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber'] : ($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber())) && false ?: '_'}); - }, 'baz' => function () { - $f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition']) ? $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition'] : ($this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition())) && false ?: '_'}); - }]))->withContext('foo_service', $this)); - } - - /** - * Gets the private 'Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition' shared service. - * - * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition - */ - protected function getCustomDefinitionService() - { - return $this->services['Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_tsantos.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_tsantos.php deleted file mode 100644 index b314feff..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_tsantos.php +++ /dev/null @@ -1,87 +0,0 @@ -services = []; - $this->normalizedIds = [ - 'tsantos\\serializer\\serializerinterface' => 'TSantos\\Serializer\\SerializerInterface', - ]; - $this->methodMap = [ - 'tsantos_serializer' => 'getTsantosSerializerService', - ]; - $this->aliases = [ - 'TSantos\\Serializer\\SerializerInterface' => 'tsantos_serializer', - ]; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'tsantos_serializer' shared service. - * - * @return \TSantos\Serializer\EventEmitterSerializer - */ - protected function getTsantosSerializerService() - { - $a = new \TSantos\Serializer\NormalizerRegistry(); - - $b = new \TSantos\Serializer\Normalizer\CollectionNormalizer(); - - $c = new \TSantos\Serializer\EventDispatcher\EventDispatcher(); - $c->addSubscriber(new \TSantos\SerializerBundle\EventListener\StopwatchListener(new \Symfony\Component\Stopwatch\Stopwatch(true))); - - $this->services['tsantos_serializer'] = $instance = new \TSantos\Serializer\EventEmitterSerializer(new \TSantos\Serializer\Encoder\JsonEncoder(), $a, $c); - - $b->setSerializer($instance); - $d = new \TSantos\Serializer\Normalizer\JsonNormalizer(); - $d->setSerializer($instance); - - $a->add(new \TSantos\Serializer\Normalizer\ObjectNormalizer(new \TSantos\SerializerBundle\Serializer\CircularReferenceHandler())); - $a->add($b); - $a->add($d); - - return $instance; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_uninitialized_ref.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_uninitialized_ref.php deleted file mode 100644 index a338c9d5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_uninitialized_ref.php +++ /dev/null @@ -1,134 +0,0 @@ -services = []; - $this->methodMap = [ - 'bar' => 'getBarService', - 'baz' => 'getBazService', - 'foo1' => 'getFoo1Service', - 'foo3' => 'getFoo3Service', - ]; - $this->privates = [ - 'foo3' => true, - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - 'foo2' => true, - 'foo3' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar' shared service. - * - * @return \stdClass - */ - protected function getBarService() - { - $this->services['bar'] = $instance = new \stdClass(); - - $instance->foo1 = ${($_ = isset($this->services['foo1']) ? $this->services['foo1'] : null) && false ?: '_'}; - $instance->foo2 = null; - $instance->foo3 = ${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : null) && false ?: '_'}; - $instance->closures = [0 => function () { - return ${($_ = isset($this->services['foo1']) ? $this->services['foo1'] : null) && false ?: '_'}; - }, 1 => function () { - return null; - }, 2 => function () { - return ${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : null) && false ?: '_'}; - }]; - $instance->iter = new RewindableGenerator(function () { - if (isset($this->services['foo1'])) { - yield 'foo1' => ${($_ = isset($this->services['foo1']) ? $this->services['foo1'] : null) && false ?: '_'}; - } - if (false) { - yield 'foo2' => null; - } - if (isset($this->services['foo3'])) { - yield 'foo3' => ${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : null) && false ?: '_'}; - } - }, function () { - return 0 + (int) (isset($this->services['foo1'])) + (int) (false) + (int) (isset($this->services['foo3'])); - }); - - return $instance; - } - - /** - * Gets the public 'baz' shared service. - * - * @return \stdClass - */ - protected function getBazService() - { - $this->services['baz'] = $instance = new \stdClass(); - - $instance->foo3 = ${($_ = isset($this->services['foo3']) ? $this->services['foo3'] : ($this->services['foo3'] = new \stdClass())) && false ?: '_'}; - - return $instance; - } - - /** - * Gets the public 'foo1' shared service. - * - * @return \stdClass - */ - protected function getFoo1Service() - { - return $this->services['foo1'] = new \stdClass(); - } - - /** - * Gets the private 'foo3' shared service. - * - * @return \stdClass - */ - protected function getFoo3Service() - { - return $this->services['foo3'] = new \stdClass(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_unsupported_characters.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_unsupported_characters.php deleted file mode 100644 index 9e7e817d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/services_unsupported_characters.php +++ /dev/null @@ -1,178 +0,0 @@ -parameters = $this->getDefaultParameters(); - - $this->services = []; - $this->methodMap = [ - 'bar$' => 'getBarService', - 'bar$!' => 'getBar2Service', - 'foo*/oh-no' => 'getFooohnoService', - ]; - - $this->aliases = []; - } - - public function getRemovedIds() - { - return [ - 'Psr\\Container\\ContainerInterface' => true, - 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, - ]; - } - - public function compile() - { - throw new LogicException('You cannot compile a dumped container that was already compiled.'); - } - - public function isCompiled() - { - return true; - } - - public function isFrozen() - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); - - return true; - } - - /** - * Gets the public 'bar$' shared service. - * - * @return \FooClass - */ - protected function getBarService() - { - return $this->services['bar$'] = new \FooClass(); - } - - /** - * Gets the public 'bar$!' shared service. - * - * @return \FooClass - */ - protected function getBar2Service() - { - return $this->services['bar$!'] = new \FooClass(); - } - - /** - * Gets the public 'foo oh-no' shared service. - * - * @return \FooClass - */ - protected function getFooohnoService() - { - return $this->services['foo*/oh-no'] = new \FooClass(); - } - - public function getParameter($name) - { - $name = (string) $name; - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - $name = $this->normalizeParameterName($name); - - if (!(isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters))) { - throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); - } - } - if (isset($this->loadedDynamicParameters[$name])) { - return $this->loadedDynamicParameters[$name] ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - - return $this->parameters[$name]; - } - - public function hasParameter($name) - { - $name = (string) $name; - $name = $this->normalizeParameterName($name); - - return isset($this->parameters[$name]) || isset($this->loadedDynamicParameters[$name]) || array_key_exists($name, $this->parameters); - } - - public function setParameter($name, $value) - { - throw new LogicException('Impossible to call set() on a frozen ParameterBag.'); - } - - public function getParameterBag() - { - if (null === $this->parameterBag) { - $parameters = $this->parameters; - foreach ($this->loadedDynamicParameters as $name => $loaded) { - $parameters[$name] = $loaded ? $this->dynamicParameters[$name] : $this->getDynamicParameter($name); - } - $this->parameterBag = new FrozenParameterBag($parameters); - } - - return $this->parameterBag; - } - - private $loadedDynamicParameters = []; - private $dynamicParameters = []; - - /** - * Computes a dynamic parameter. - * - * @param string $name The name of the dynamic parameter to load - * - * @return mixed The value of the dynamic parameter - * - * @throws InvalidArgumentException When the dynamic parameter does not exist - */ - private function getDynamicParameter($name) - { - throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); - } - - private $normalizedParameterNames = []; - - private function normalizeParameterName($name) - { - if (isset($this->normalizedParameterNames[$normalizedName = strtolower($name)]) || isset($this->parameters[$normalizedName]) || array_key_exists($normalizedName, $this->parameters)) { - $normalizedName = isset($this->normalizedParameterNames[$normalizedName]) ? $this->normalizedParameterNames[$normalizedName] : $normalizedName; - if ((string) $name !== $normalizedName) { - @trigger_error(sprintf('Parameter names will be made case sensitive in Symfony 4.0. Using "%s" instead of "%s" is deprecated since Symfony 3.4.', $name, $normalizedName), E_USER_DEPRECATED); - } - } else { - $normalizedName = $this->normalizedParameterNames[$normalizedName] = (string) $name; - } - - return $normalizedName; - } - - /** - * Gets the default parameters. - * - * @return array An array of the default parameters - */ - protected function getDefaultParameters() - { - return [ - '\'' => 'oh-no', - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/php/simple.php b/vendor/symfony/dependency-injection/Tests/Fixtures/php/simple.php deleted file mode 100644 index aa4df998..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/php/simple.php +++ /dev/null @@ -1,3 +0,0 @@ -setParameter('foo', 'foo'); diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/class_from_id.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/class_from_id.xml deleted file mode 100644 index 5b741009..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/class_from_id.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/defaults_bindings.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/defaults_bindings.xml deleted file mode 100644 index d943dfad..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/defaults_bindings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - value - - value - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/defaults_bindings2.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/defaults_bindings2.xml deleted file mode 100644 index db41330f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/defaults_bindings2.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - overridden - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extension1/services.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extension1/services.xml deleted file mode 100644 index 1323dd5f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extension1/services.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extension2/services.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extension2/services.xml deleted file mode 100644 index f9c01225..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extension2/services.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services1.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services1.xml deleted file mode 100644 index 792fa070..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services1.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BAR - - - - - - - - - %project.parameter.foo% - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services2.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services2.xml deleted file mode 100644 index 65c90696..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services2.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BAR - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services3.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services3.xml deleted file mode 100644 index 4c818448..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services3.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BAR - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services4.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services4.xml deleted file mode 100644 index 2c33c3a7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services4.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services5.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services5.xml deleted file mode 100644 index c0343373..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services5.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services6.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services6.xml deleted file mode 100644 index da2b4bf2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services6.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services7.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services7.xml deleted file mode 100644 index fa5c364b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/extensions/services7.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/legacy_invalid_alias_definition.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/legacy_invalid_alias_definition.xml deleted file mode 100644 index a5387b25..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/legacy_invalid_alias_definition.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/namespaces.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/namespaces.xml deleted file mode 100644 index 9dc27fad..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/namespaces.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - foo - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/nested_service_without_id.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/nested_service_without_id.xml deleted file mode 100644 index cfeed0ff..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/nested_service_without_id.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/nonvalid.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/nonvalid.xml deleted file mode 100644 index e7b5bc97..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/nonvalid.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services1.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services1.xml deleted file mode 100644 index 7d8674a3..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services1.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services10.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services10.xml deleted file mode 100644 index 921070e1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services10.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services13.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services13.xml deleted file mode 100644 index 9d86b8e5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services13.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services14.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services14.xml deleted file mode 100644 index 639075f5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services14.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - app - - - - - - app - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services2.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services2.xml deleted file mode 100644 index 243a289f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services2.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - a string - bar - - 0 - 4 - null - true - true - false - on - off - 1.3 - 1000.3 - a string - - foo - bar - - - - value - - PHP_EOL - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services21.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services21.xml deleted file mode 100644 index 20dd4cf4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services21.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services22.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services22.xml deleted file mode 100644 index 6de7945b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services22.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - Bar - Baz - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services23.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services23.xml deleted file mode 100644 index eb56fd11..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services23.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services24.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services24.xml deleted file mode 100644 index 23c91cdc..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services24.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services28.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services28.xml deleted file mode 100644 index 6b53c098..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services28.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services3.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services3.xml deleted file mode 100644 index 5f0afeb4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services3.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - foo - - true - false - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services4.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services4.xml deleted file mode 100644 index 399da815..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services4.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services4_bad_import.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services4_bad_import.xml deleted file mode 100644 index b30178f9..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services4_bad_import.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services5.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services5.xml deleted file mode 100644 index 6c6a1424..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services5.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services6.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services6.xml deleted file mode 100644 index 84eb57bb..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services6.xml +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - %path%/foo.php - - - foo - - - true - false - - - - - - - - - - - - - - - service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default") - - - - - foo - - - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services7.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services7.xml deleted file mode 100644 index 5b322105..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services7.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services8.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services8.xml deleted file mode 100644 index 4b07bbb7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services8.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - %baz% - bar - foo is %%foo bar - @escapeme - - true - false - null - 0 - 1000.3 - true - false - null - - null - 123 - -123 - true - false - 0b0110 - -1.2E2 - 0xFF - 10100.1 - +10100.1 - -10100.1 - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services9.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services9.xml deleted file mode 100644 index 128c1bac..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services9.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - - BazClass - Bar\FooClass - bar - - - - - - - foo - - - foo is %foo% - %foo% - - true - - bar - - - foo is %foo% - %foo% - - - - - - - - - - - - - - foo - - %foo_bar% - - - - - - - %path%foo.php - - - - - - - - - - - - - - service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default") - - - - - - - - - pub - - - - - - - - - - - - - - - - - - - - bar - - - - - - - - - The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. - - - bar - - - - - - bar - - - - - - - foo - The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_abstract.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_abstract.xml deleted file mode 100644 index 47fd3a53..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_abstract.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_autoconfigure.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_autoconfigure.xml deleted file mode 100644 index 91cfa5f4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_autoconfigure.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_autoconfigure_with_parent.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_autoconfigure_with_parent.xml deleted file mode 100644 index 97a8facf..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_autoconfigure_with_parent.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_bindings.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_bindings.xml deleted file mode 100644 index 0fb57daa..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_bindings.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - null - quz - factory - - - - - - null - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_defaults_with_parent.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_defaults_with_parent.xml deleted file mode 100644 index bb151189..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_defaults_with_parent.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_deprecated.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_deprecated.xml deleted file mode 100644 index ae3a0b08..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_deprecated.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - The "%service_id%" service is deprecated. - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_dump_load.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_dump_load.xml deleted file mode 100644 index 7a91166c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_dump_load.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_inline_not_candidate.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_inline_not_candidate.xml deleted file mode 100644 index e6857813..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_inline_not_candidate.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_instanceof.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_instanceof.xml deleted file mode 100644 index 097687e1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_instanceof.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_instanceof_with_parent.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_instanceof_with_parent.xml deleted file mode 100644 index c2fce5eb..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_instanceof_with_parent.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_named_args.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_named_args.xml deleted file mode 100644 index 68ade19d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_named_args.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - ABCD - null - - 123 - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_prototype.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_prototype.xml deleted file mode 100644 index 9d1d622d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_prototype.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_tsantos.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_tsantos.xml deleted file mode 100644 index 2a35f468..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_tsantos.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_without_id.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_without_id.xml deleted file mode 100644 index fe65f08f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/services_without_id.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/tag_with_empty_name.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/tag_with_empty_name.xml deleted file mode 100644 index 08e3e78f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/tag_with_empty_name.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/tag_without_name.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/tag_without_name.xml deleted file mode 100644 index 1ff39290..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/tag_without_name.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/with_key_outside_collection.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/with_key_outside_collection.xml deleted file mode 100644 index 1f6d3207..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/with_key_outside_collection.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - foo - bar - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/withdoctype.xml b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/withdoctype.xml deleted file mode 100644 index f217d5bc..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/withdoctype.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/xml_with_wrong_ext.php b/vendor/symfony/dependency-injection/Tests/Fixtures/xml/xml_with_wrong_ext.php deleted file mode 100644 index dcf167db..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/xml/xml_with_wrong_ext.php +++ /dev/null @@ -1,9 +0,0 @@ - - - - - from xml - - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services.yml deleted file mode 100644 index fe54b898..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services.yml +++ /dev/null @@ -1,14 +0,0 @@ -imports: - # Ensure the anonymous services count is reset after importing a file - - { resource: anonymous_services_in_instanceof.yml } - -services: - _defaults: - autowire: true - - Foo: - arguments: - - !service - class: Bar - autowire: true - factory: [ !service { class: Quz }, 'constructFoo' ] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_alias.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_alias.yml deleted file mode 100644 index 96546b83..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_alias.yml +++ /dev/null @@ -1,7 +0,0 @@ -services: - Bar: ~ - - Foo: - arguments: - - !service - alias: Bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_in_instanceof.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_in_instanceof.yml deleted file mode 100644 index ea0bebaf..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_in_instanceof.yml +++ /dev/null @@ -1,15 +0,0 @@ -services: - _instanceof: - # Ensure previous conditionals aren't applied on anonymous services - Quz: - autowire: true - - DummyInterface: - properties: - foo: !service { class: Anonymous } - - # Ensure next conditionals are not considered as services - Bar: - autowire: true - - Dummy: ~ diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_in_parameters.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_in_parameters.yml deleted file mode 100644 index 9d9bea34..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/anonymous_services_in_parameters.yml +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - foo: [ !service { } ] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_calls.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_calls.yml deleted file mode 100644 index 3f34b07e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_calls.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - method_call1: - class: FooClass - calls: foo diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_decorates.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_decorates.yml deleted file mode 100644 index 79c048a8..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_decorates.yml +++ /dev/null @@ -1,7 +0,0 @@ -services: - foo: - class: stdClass - bar: - class: stdClass - decorates: "@foo" - arguments: ["@bar.inner"] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_empty_defaults.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_empty_defaults.yml deleted file mode 100644 index 85d910e3..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_empty_defaults.yml +++ /dev/null @@ -1,2 +0,0 @@ -services: - _defaults: diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_empty_instanceof.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_empty_instanceof.yml deleted file mode 100644 index 2c8ce09f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_empty_instanceof.yml +++ /dev/null @@ -1,2 +0,0 @@ -services: - _instanceof: diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_format.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_format.yml deleted file mode 100644 index 1f58cac6..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_format.yml +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - FOO: bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_import.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_import.yml deleted file mode 100644 index 2dbbcbf2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_import.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: ~ } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_imports.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_imports.yml deleted file mode 100644 index 1ce9d57c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_imports.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - foo:bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_parameters.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_parameters.yml deleted file mode 100644 index bbd13ac0..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_parameters.yml +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - foo:bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_service.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_service.yml deleted file mode 100644 index 811af3c0..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_service.yml +++ /dev/null @@ -1,2 +0,0 @@ -services: - foo: bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_services.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_services.yml deleted file mode 100644 index cfbf17ce..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_services.yml +++ /dev/null @@ -1 +0,0 @@ -services: foo diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_types1.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_types1.yml deleted file mode 100644 index 891e0149..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_types1.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - foo_service: - class: FooClass - # types is not an array - autowiring_types: 1 diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_types2.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_types2.yml deleted file mode 100644 index fb1d53e1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bad_types2.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - foo_service: - class: FooClass - # autowiring_types is not a string - autowiring_types: [ 1 ] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag1.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag1.yml deleted file mode 100644 index 14536fdb..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag1.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - foo_service: - class: FooClass - # tags is not an array - tags: string diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag2.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag2.yml deleted file mode 100644 index 90288144..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag2.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - foo_service: - class: FooClass - tags: - # tag is missing the name key - foo_tag: { foo: bar } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag3.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag3.yml deleted file mode 100644 index 72ec4e8f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/badtag3.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - foo_service: - class: FooClass - tags: - # tag-attribute is not a scalar - - { name: foo, bar: { foo: foo, bar: bar } } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bar/services.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bar/services.yml deleted file mode 100644 index 0f846f5f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/bar/services.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - AppBundle\Foo: - arguments: - - !service {class: AppBundle\Bar } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/class_from_id.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/class_from_id.yml deleted file mode 100644 index 33f0b2ea..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/class_from_id.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass: - autowire: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/defaults_bindings.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/defaults_bindings.yml deleted file mode 100644 index ca5e5048..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/defaults_bindings.yml +++ /dev/null @@ -1,11 +0,0 @@ -services: - _defaults: - bind: - $quz: value - $foo: [value] - - bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Bar - - foo: - class: stdClass diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/defaults_bindings2.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/defaults_bindings2.yml deleted file mode 100644 index 01fc5af6..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/defaults_bindings2.yml +++ /dev/null @@ -1,7 +0,0 @@ -services: - _defaults: - bind: - $quz: overridden - - bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/foo/services.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/foo/services.yml deleted file mode 100644 index 76eee552..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/foo/services.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - AppBundle\Hello: - arguments: - - !service {class: AppBundle\World} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/_child.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/_child.yml deleted file mode 100644 index 89d8b914..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/_child.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - child_service: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/expected.yml deleted file mode 100644 index ca08caad..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/expected.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - child_service_expected: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - # the parent has autoconfigure true, but that does not cascade to the child - autoconfigure: false - # an autoconfigured "instanceof" is setup for IntegrationTestStub - # but its calls are NOT added, because the class was only - # set on the parent, not the child - #calls: - # - [enableSummer, [true]] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/main.yml deleted file mode 100644 index 02533bf0..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_child_not_applied/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: _child.yml } - -services: - parent_service: - autoconfigure: true - abstract: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/_child.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/_child.yml deleted file mode 100644 index 5319c204..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/_child.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - child_service: - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/expected.yml deleted file mode 100644 index c1dca076..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/expected.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - child_service_expected: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - # autoconfigure is set on the parent, but not on the child - autoconfigure: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/main.yml deleted file mode 100644 index ab9877d1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: _child.yml } - -services: - parent_service: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - autoconfigure: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/_child.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/_child.yml deleted file mode 100644 index 5319c204..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/_child.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - child_service: - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/expected.yml deleted file mode 100644 index 02cf0037..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/expected.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - child_service_expected: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - # from an autoconfigured "instanceof" applied to parent class - # but NOT inherited down to child - # tags: [from_autoconfigure] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/main.yml deleted file mode 100644 index ab9877d1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/autoconfigure_parent_child_tags/main.yml +++ /dev/null @@ -1,7 +0,0 @@ -imports: - - { resource: _child.yml } - -services: - parent_service: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - autoconfigure: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/child_parent/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/child_parent/expected.yml deleted file mode 100644 index 54cd91c2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/child_parent/expected.yml +++ /dev/null @@ -1,9 +0,0 @@ -services: - # child_service in the end should be identical to this - child_service_expected: - class: stdClass - autowire: false - public: true - lazy: true - # ONLY the child tag, the parent tag does not inherit - tags: [from_child] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/child_parent/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/child_parent/main.yml deleted file mode 100644 index edaa3a3b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/child_parent/main.yml +++ /dev/null @@ -1,13 +0,0 @@ -services: - parent_service: - abstract: true - lazy: true - autowire: false - public: false - tags: [from_parent] - - child_service: - class: stdClass - parent: parent_service - public: true - tags: [from_child] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_child_tags/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_child_tags/expected.yml deleted file mode 100644 index cb36636e..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_child_tags/expected.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - child_service_expected: - class: stdClass - # set explicitly on child (not overridden by parent) - autoconfigure: false - # set explicitly on child - autowire: true - tags: [from_defaults] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_child_tags/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_child_tags/main.yml deleted file mode 100644 index b5dc66ff..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_child_tags/main.yml +++ /dev/null @@ -1,18 +0,0 @@ -services: - _defaults: - autoconfigure: true - autowire: true - tags: [from_defaults] - - parent_service: - class: stdClass - # will not override child - autoconfigure: true - # parent definitions are not applied to children - tags: [from_parent] - - child_service: - parent: parent_service - # _defaults is ok because these are explicitly set - autoconfigure: false - autowire: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_instanceof_importance/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_instanceof_importance/expected.yml deleted file mode 100644 index e9161dcc..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_instanceof_importance/expected.yml +++ /dev/null @@ -1,26 +0,0 @@ -services: - # main_service should look like this in the end - main_service_expected: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - # _instanceof overrides _defaults - autowire: false - # inherited from _defaults - autoconfigure: true - # from _instanceof - shared: false - # service definition overrides _instanceof - public: true - - tags: - - { name: foo_tag, tag_option: from_service } - # these 2 are from instanceof - - { name: foo_tag, tag_option: from_instanceof } - - { name: bar_tag } - - { name: from_defaults } - # calls from instanceof are kept, but this comes later - calls: - # first call is from instanceof - - [setSunshine, [bright]] - # - - [enableSummer, [true]] - - [setSunshine, [warm]] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_instanceof_importance/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_instanceof_importance/main.yml deleted file mode 100644 index 406a351d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_instanceof_importance/main.yml +++ /dev/null @@ -1,30 +0,0 @@ -services: - _defaults: - autowire: true - autoconfigure: true - public: true - tags: [from_defaults] - - _instanceof: - Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStubParent: - autowire: false - shared: false - public: false - tags: - - { name: foo_tag, tag_option: from_instanceof } - calls: - - [setSunshine, [bright]] - - Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub: - tags: - - { name: bar_tag } - - main_service: - class: Symfony\Component\DependencyInjection\Tests\Compiler\IntegrationTestStub - public: true - tags: - - { name: foo_tag, tag_option: from_service } - # calls from instanceof are kept, but this comes later - calls: - - [enableSummer, [true]] - - [setSunshine, [warm]] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/_child.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/_child.yml deleted file mode 100644 index 86ef83c2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/_child.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - # loaded here to avoid defaults in other file - child_service: - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/expected.yml deleted file mode 100644 index 012672ff..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/expected.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - child_service_expected: - class: stdClass - # _defaults is applied to the parent, but autoconfigure: true - # does not cascade to the child - autoconfigure: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/main.yml deleted file mode 100644 index 8b90b4e9..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/defaults_parent_child/main.yml +++ /dev/null @@ -1,9 +0,0 @@ -imports: - - { resource: _child.yml } - -services: - _defaults: - autoconfigure: true - - parent_service: - class: stdClass diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/_child.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/_child.yml deleted file mode 100644 index 86ef83c2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/_child.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - # loaded here to avoid defaults in other file - child_service: - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/expected.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/expected.yml deleted file mode 100644 index 074ed01d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/expected.yml +++ /dev/null @@ -1,7 +0,0 @@ -services: - child_service_expected: - class: stdClass - # applied to _instanceof of parent - autowire: true - # from _instanceof, applies to parent, but does NOT inherit to here - # tags: [from_instanceof] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/main.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/main.yml deleted file mode 100644 index 44cf9b00..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/integration/instanceof_parent_child/main.yml +++ /dev/null @@ -1,11 +0,0 @@ -imports: - - { resource: _child.yml } - -services: - _instanceof: - stdClass: - autowire: true - tags: [from_instanceof] - - parent_service: - class: stdClass diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/legacy_invalid_alias_definition.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/legacy_invalid_alias_definition.yml deleted file mode 100644 index 00c011c1..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/legacy_invalid_alias_definition.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - foo: - alias: bar - factory: foo - parent: quz diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/legacy_invalid_definition.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/legacy_invalid_definition.yml deleted file mode 100644 index 8487e854..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/legacy_invalid_definition.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - # This definition is valid and should not raise any deprecation notice - foo: - class: stdClass - arguments: [ 'foo', 'bar' ] - - # This definition is invalid and must raise a deprecation notice - bar: - class: stdClass - private: true # the "private" keyword is invalid diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/nonvalid1.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/nonvalid1.yml deleted file mode 100644 index 4eddb872..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/nonvalid1.yml +++ /dev/null @@ -1,2 +0,0 @@ -foo: - bar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/nonvalid2.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/nonvalid2.yml deleted file mode 100644 index c508d536..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/nonvalid2.yml +++ /dev/null @@ -1 +0,0 @@ -false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/null_config.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/null_config.yml deleted file mode 100644 index e88e12e2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/null_config.yml +++ /dev/null @@ -1 +0,0 @@ -project: ~ diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services1.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services1.yml deleted file mode 100644 index 071742f2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services1.yml +++ /dev/null @@ -1,11 +0,0 @@ -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - Psr\Container\ContainerInterface: - alias: service_container - public: false - Symfony\Component\DependencyInjection\ContainerInterface: - alias: service_container - public: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services10.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services10.yml deleted file mode 100644 index c66084cd..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services10.yml +++ /dev/null @@ -1,9 +0,0 @@ -parameters: - project.parameter.foo: BAR - -services: - project.service.foo: - class: BAR - -project: - test: '%project.parameter.foo%' diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services11.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services11.yml deleted file mode 100644 index 40126f00..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services11.yml +++ /dev/null @@ -1 +0,0 @@ -foobarfoobar: {} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services13.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services13.yml deleted file mode 100644 index d52d355c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services13.yml +++ /dev/null @@ -1,3 +0,0 @@ -# used to test imports in XML -parameters: - imported_from_yaml: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services14.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services14.yml deleted file mode 100644 index 4c188c5f..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services14.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - factory: { class: FooBarClass, factory: baz:getClass} - factory_with_static_call: { class: FooBarClass, factory: FooBacFactory::createFooBar} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services2.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services2.yml deleted file mode 100644 index e05d69d7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services2.yml +++ /dev/null @@ -1,13 +0,0 @@ -parameters: - foo: bar - values: - - true - - false - - 0 - - 1000.3 - - !php/const PHP_INT_MAX - bar: foo - escape: '@@escapeme' - foo_bar: '@foo_bar' - mixedcase: - MixedCaseKey: value diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services21.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services21.yml deleted file mode 100644 index a2617c16..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services21.yml +++ /dev/null @@ -1,15 +0,0 @@ -services: - manager: - class: UserManager - arguments: - - true - calls: - - method: setLogger - arguments: - - '@logger' - - method: setClass - arguments: - - User - tags: - - name: manager - alias: user diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services22.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services22.yml deleted file mode 100644 index 55d015ba..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services22.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - foo_service: - class: FooClass - autowiring_types: [ Foo, Bar ] - - baz_service: - class: Baz - autowiring_types: Foo diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services23.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services23.yml deleted file mode 100644 index 1984c177..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services23.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - bar_service: - class: BarClass - autowire: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services24.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services24.yml deleted file mode 100644 index f59354e3..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services24.yml +++ /dev/null @@ -1,16 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - foo: - class: Foo - public: true - autowire: true - Psr\Container\ContainerInterface: - alias: service_container - public: false - Symfony\Component\DependencyInjection\ContainerInterface: - alias: service_container - public: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services26.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services26.yml deleted file mode 100644 index a1f235a7..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services26.yml +++ /dev/null @@ -1,22 +0,0 @@ -parameters: - project_dir: '/foo/bar' - env(FOO): foo - env(DB): 'sqlite://%%project_dir%%/var/data.db' - bar: '%env(FOO)%' - baz: '%env(int:Baz)%' - json: '%env(json:file:json_file)%' - db_dsn: '%env(resolve:DB)%' - -services: - test: - public: true - class: '%env(FOO)%' - arguments: - - '%env(Bar)%' - - 'foo%bar%baz' - - '%baz%' - bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Bar - public: true - bind: - $quz: '%env(QUZ)%' diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services28.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services28.yml deleted file mode 100644 index fd0ce4cf..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services28.yml +++ /dev/null @@ -1,34 +0,0 @@ -services: - _defaults: - public: false - autowire: true - tags: - - name: foo - - Acme\Foo: ~ - - with_defaults: - class: Foo - - with_null: - class: Foo - public: true - autowire: ~ - - no_defaults: - class: Foo - public: true - autowire: false - tags: [] - - with_defaults_aliased: - alias: with_defaults - - with_defaults_aliased_short: '@with_defaults' - - Acme\WithShortCutArgs: [foo] - - child_def: - parent: with_defaults - public: true - autowire: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services3.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services3.yml deleted file mode 100644 index 0e92cdf5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services3.yml +++ /dev/null @@ -1,5 +0,0 @@ -parameters: - foo: foo - values: - - true - - false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services31_invalid_tags.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services31_invalid_tags.yml deleted file mode 100644 index a6061a90..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services31_invalid_tags.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - _defaults: - tags: ['foo'] - - Foo\Bar: - tags: invalid diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services4.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services4.yml deleted file mode 100644 index 073f5554..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services4.yml +++ /dev/null @@ -1,8 +0,0 @@ -imports: - - services2.yml - - { resource: services3.yml } - - { resource: "../php/simple.php" } - - { resource: "../ini/parameters.ini", class: Symfony\Component\DependencyInjection\Loader\IniFileLoader } - - { resource: "../ini/parameters2.ini" } - - { resource: "../xml/services13.xml" } - - { resource: "../xml/xml_with_wrong_ext.php", type: xml } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services4_bad_import.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services4_bad_import.yml deleted file mode 100644 index f7089fc4..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services4_bad_import.yml +++ /dev/null @@ -1,2 +0,0 @@ -imports: - - { resource: foo_fake.yml, ignore_errors: true } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services6.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services6.yml deleted file mode 100644 index 1ee6c6ec..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services6.yml +++ /dev/null @@ -1,43 +0,0 @@ -services: - foo: { class: FooClass } - baz: { class: BazClass } - not_shared: { class: FooClass, shared: false } - file: { class: FooClass, file: '%path%/foo.php' } - arguments: { class: FooClass, arguments: [foo, '@foo', [true, false]] } - configurator1: { class: FooClass, configurator: sc_configure } - configurator2: { class: FooClass, configurator: ['@baz', configure] } - configurator3: { class: FooClass, configurator: [BazClass, configureStatic] } - method_call1: - class: FooClass - calls: - - [ setBar, [] ] - - [ setBar ] - - [ setBar, ['@=service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")'] ] - method_call2: - class: FooClass - calls: - - [ setBar, [ foo, '@foo', [true, false] ] ] - request: - class: Request - synthetic: true - lazy: true - decorator_service: - decorates: decorated - decorator_service_with_name: - decorates: decorated - decoration_inner_name: decorated.pif-pouf - decorator_service_with_name_and_priority: - decorates: decorated - decoration_inner_name: decorated.pif-pouf - decoration_priority: 5 - new_factory1: { class: FooBarClass, factory: factory} - new_factory2: { class: FooBarClass, factory: ['@baz', getClass]} - new_factory3: { class: FooBarClass, factory: [BazClass, getInstance]} - new_factory4: { class: BazClass, factory: [~, getInstance]} - Acme\WithShortCutArgs: [foo, '@baz'] - alias_for_foo: '@foo' - another_alias_for_foo: - alias: foo - public: false - another_third_alias_for_foo: - alias: foo diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services7.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services7.yml deleted file mode 100644 index 09064f20..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services7.yml +++ /dev/null @@ -1,2 +0,0 @@ -services: - foo: { class: BarClass } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services8.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services8.yml deleted file mode 100644 index 002b1d4b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services8.yml +++ /dev/null @@ -1,29 +0,0 @@ -parameters: - foo: '%baz%' - baz: bar - bar: 'foo is %%foo bar' - escape: '@@escapeme' - values: [true, false, null, 0, 1000.3, 'true', 'false', 'null'] - null string: 'null' - string of digits: '123' - string of digits prefixed with minus character: '-123' - true string: 'true' - false string: 'false' - binary number string: '0b0110' - numeric string: '-1.2E2' - hexadecimal number string: '0xFF' - float string: '10100.1' - positive float string: '+10100.1' - negative float string: '-10100.1' - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - Psr\Container\ContainerInterface: - alias: service_container - public: false - Symfony\Component\DependencyInjection\ContainerInterface: - alias: service_container - public: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services9.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services9.yml deleted file mode 100644 index 2501ddcc..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services9.yml +++ /dev/null @@ -1,163 +0,0 @@ -parameters: - baz_class: BazClass - foo_class: Bar\FooClass - foo: bar - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - foo: - class: Bar\FooClass - tags: - - { name: foo, foo: foo } - - { name: foo, bar: bar, baz: baz } - arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', foobar: '%foo%' }, true, '@service_container'] - properties: { foo: bar, moo: '@foo.baz', qux: { '%foo%': 'foo is %foo%', foobar: '%foo%' } } - calls: - - [setBar, ['@bar']] - - [initialize, { }] - - factory: [Bar\FooClass, getInstance] - configurator: sc_configure - public: true - foo.baz: - class: '%baz_class%' - factory: ['%baz_class%', getInstance] - configurator: ['%baz_class%', configureStatic1] - public: true - bar: - class: Bar\FooClass - arguments: [foo, '@foo.baz', '%foo_bar%'] - configurator: ['@foo.baz', configure] - public: true - foo_bar: - class: '%foo_class%' - shared: false - arguments: ['@deprecated_service'] - public: true - method_call1: - class: Bar\FooClass - file: '%path%foo.php' - calls: - - [setBar, ['@foo']] - - [setBar, ['@?foo2']] - - [setBar, ['@?foo3']] - - [setBar, ['@?foobaz']] - - [setBar, ['@=service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")']] - public: true - - foo_with_inline: - class: Foo - calls: - - [setBar, ['@inlined']] - public: true - - inlined: - class: Bar - public: false - properties: { pub: pub } - calls: - - [setBaz, ['@baz']] - - baz: - class: Baz - calls: - - [setFoo, ['@foo_with_inline']] - public: true - - request: - class: Request - synthetic: true - public: true - configurator_service: - class: ConfClass - public: false - calls: - - [setFoo, ['@baz']] - - configured_service: - class: stdClass - configurator: ['@configurator_service', configureStdClass] - public: true - configurator_service_simple: - class: ConfClass - public: false - arguments: ['bar'] - configured_service_simple: - class: stdClass - configurator: ['@configurator_service_simple', configureStdClass] - public: true - decorated: - class: stdClass - public: true - decorator_service: - class: stdClass - decorates: decorated - public: true - decorator_service_with_name: - class: stdClass - decorates: decorated - decoration_inner_name: decorated.pif-pouf - public: true - deprecated_service: - class: stdClass - deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. - public: true - new_factory: - class: FactoryClass - public: false - properties: { foo: bar } - factory_service: - class: Bar - factory: ['@foo.baz', getInstance] - public: true - new_factory_service: - class: FooBarBaz - properties: { foo: bar } - factory: ['@new_factory', getInstance] - public: true - service_from_static_method: - class: Bar\FooClass - factory: [Bar\FooClass, getInstance] - public: true - factory_simple: - class: SimpleFactoryClass - deprecated: The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed. - public: false - arguments: ['foo'] - factory_service_simple: - class: Bar - factory: ['@factory_simple', getInstance] - public: true - lazy_context: - class: LazyContext - arguments: [!iterator {'k1': '@foo.baz', 'k2': '@service_container'}, !iterator []] - public: true - lazy_context_ignore_invalid_ref: - class: LazyContext - arguments: [!iterator ['@foo.baz', '@?invalid'], !iterator []] - public: true - tagged_iterator_foo: - class: Bar - tags: - - { name: foo } - public: false - tagged_iterator: - class: Bar - arguments: - - !tagged foo - public: true - Psr\Container\ContainerInterface: - alias: service_container - public: false - Symfony\Component\DependencyInjection\ContainerInterface: - alias: service_container - public: false - alias_for_foo: - alias: 'foo' - public: true - alias_for_alias: - alias: 'foo' - public: true diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_adawson.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_adawson.yml deleted file mode 100644 index 2a26f38a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_adawson.yml +++ /dev/null @@ -1,28 +0,0 @@ -services: - App\Db: - public: true - properties: - schema: '@App\Schema' - - App\Bus: - public: true - arguments: ['@App\Db'] - properties: - handler1: '@App\Handler1' - handler2: '@App\Handler2' - - App\Handler1: - ['@App\Db', '@App\Schema', '@App\Processor'] - - App\Handler2: - ['@App\Db', '@App\Schema', '@App\Processor'] - - App\Processor: - ['@App\Registry', '@App\Db'] - - App\Registry: - properties: - processor: ['@App\Db', '@App\Bus'] - - App\Schema: - arguments: ['@App\Db'] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_autoconfigure.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_autoconfigure.yml deleted file mode 100644 index 809c9f47..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_autoconfigure.yml +++ /dev/null @@ -1,9 +0,0 @@ - -services: - _defaults: - autoconfigure: true - - use_defaults_settings: ~ - - override_defaults_settings_to_false: - autoconfigure: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_autoconfigure_with_parent.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_autoconfigure_with_parent.yml deleted file mode 100644 index c6e30801..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_autoconfigure_with_parent.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - parent_service: - class: stdClass - - child_service: - class: stdClass - autoconfigure: true - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_bindings.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_bindings.yml deleted file mode 100644 index 48ad0404..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_bindings.yml +++ /dev/null @@ -1,16 +0,0 @@ -services: - _defaults: - bind: - NonExistent: ~ - $quz: quz - $factory: factory - - bar: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\Bar - autowire: true - bind: - Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface: '@Symfony\Component\DependencyInjection\Tests\Fixtures\Bar' - $foo: [ ~ ] - - Symfony\Component\DependencyInjection\Tests\Fixtures\Bar: - factory: [ ~, 'create' ] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_configurator_short_syntax.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_configurator_short_syntax.yml deleted file mode 100644 index cc5c2be5..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_configurator_short_syntax.yml +++ /dev/null @@ -1,8 +0,0 @@ -services: - foo_bar: - class: FooBarClass - configurator: foo_bar_configurator:configure - - foo_bar_with_static_call: - class: FooBarClass - configurator: FooBarConfigurator::configureFooBar diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_deep_graph.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_deep_graph.yml deleted file mode 100644 index f16329ae..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_deep_graph.yml +++ /dev/null @@ -1,24 +0,0 @@ - -services: - foo: - class: Symfony\Component\DependencyInjection\Tests\Dumper\FooForDeepGraph - public: true - arguments: - - '@bar' - - !service - class: stdClass - properties: - p2: !service - class: stdClass - properties: - p3: !service - class: stdClass - - bar: - class: stdClass - public: true - properties: - p5: !service - class: stdClass - arguments: ['@foo'] - diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_defaults_with_parent.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_defaults_with_parent.yml deleted file mode 100644 index 28dec4ce..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_defaults_with_parent.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - _defaults: - autowire: true - - parent_service: - class: stdClass - - child_service: - class: stdClass - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_dump_load.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_dump_load.yml deleted file mode 100644 index 8f3e153a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_dump_load.yml +++ /dev/null @@ -1,15 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - synthetic: true - foo: - autoconfigure: true - abstract: true - arguments: ['@!bar'] - Psr\Container\ContainerInterface: - alias: service_container - public: false - Symfony\Component\DependencyInjection\ContainerInterface: - alias: service_container - public: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_inline.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_inline.yml deleted file mode 100644 index b985cabd..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_inline.yml +++ /dev/null @@ -1,16 +0,0 @@ - -services: - service_container: - class: Symfony\Component\DependencyInjection\ContainerInterface - public: true - synthetic: true - foo: - class: Class1 - public: true - arguments: [!service { class: Class2, arguments: [!service { class: Class2 }] }] - Psr\Container\ContainerInterface: - alias: service_container - public: false - Symfony\Component\DependencyInjection\ContainerInterface: - alias: service_container - public: false diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_instanceof.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_instanceof.yml deleted file mode 100644 index a58cc079..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_instanceof.yml +++ /dev/null @@ -1,11 +0,0 @@ -services: - _instanceof: - Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface: - autowire: true - lazy: true - tags: - - { name: foo } - - { name: bar } - - Symfony\Component\DependencyInjection\Tests\Fixtures\Bar: ~ - Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface: '@Symfony\Component\DependencyInjection\Tests\Fixtures\Bar' diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_instanceof_with_parent.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_instanceof_with_parent.yml deleted file mode 100644 index fb21cdf2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_instanceof_with_parent.yml +++ /dev/null @@ -1,11 +0,0 @@ -services: - _instanceof: - FooInterface: - autowire: true - - parent_service: - class: stdClass - - child_service: - class: stdClass - parent: parent_service diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_legacy_privates.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_legacy_privates.yml deleted file mode 100644 index 0fd20446..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_legacy_privates.yml +++ /dev/null @@ -1,27 +0,0 @@ -services: - _defaults: {public: true} - - foo: {class: stdClass, public: false} - - bar: - class: stdClass - arguments: [ '@private_not_inlined' ] - - private: {class: stdClass, public: false} - decorated_private: {class: stdClass} - decorated_private_alias: '@foo' - alias_to_private: '@private' - private_alias: {alias: foo, public: false} - - private_decorator: - class: stdClass - decorates: 'decorated_private' - - private_alias_decorator: - class: stdClass - decorates: 'decorated_private_alias' - - private_not_inlined: {class: stdClass, public: false} - private_not_removed: {class: stdClass, public: false} - - public_child: {parent: private, public: true} diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_named_args.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_named_args.yml deleted file mode 100644 index 97e31014..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_named_args.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy: { 0: ~, $apiKey: ABCD } - - another_one: - class: Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy - arguments: - $apiKey: ABCD - Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass: ~ - calls: - - ['setApiKey', { $apiKey: '123' }] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype.yml deleted file mode 100644 index 8c0b202a..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\: - resource: ../Prototype - exclude: '../Prototype/{OtherDir,BadClasses}' diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype_namespace.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype_namespace.yml deleted file mode 100644 index 5c30d011..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype_namespace.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - dir1: - namespace: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\ - resource: ../Prototype/OtherDir/*/Dir1 - tags: [foo] - - dir2: - namespace: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\ - resource: ../Prototype/OtherDir/*/Dir2 - tags: [bar] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype_namespace_without_resource.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype_namespace_without_resource.yml deleted file mode 100644 index abd370ef..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_prototype_namespace_without_resource.yml +++ /dev/null @@ -1,4 +0,0 @@ -services: - dir1: - namespace: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\ - tags: [foo] diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_underscore.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_underscore.yml deleted file mode 100644 index 0cdbf903..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/services_underscore.yml +++ /dev/null @@ -1,3 +0,0 @@ -services: - _foo: - class: Foo diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_empty_string.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_empty_string.yml deleted file mode 100644 index 0ea5f53d..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_empty_string.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - foo_service: - class: FooClass - tags: - # tag name is an empty string - - { name: '', foo: bar } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_no_string.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_no_string.yml deleted file mode 100644 index f24cafd2..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_no_string.yml +++ /dev/null @@ -1,6 +0,0 @@ -services: - foo_service: - class: FooClass - tags: - # tag name is not a string - - { name: [], foo: bar } diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_only.yml b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_only.yml deleted file mode 100644 index 90180b0b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/tag_name_only.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - foo_service: - class: FooClass - tags: - - foo diff --git a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/yaml_with_wrong_ext.ini b/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/yaml_with_wrong_ext.ini deleted file mode 100644 index 1395458b..00000000 --- a/vendor/symfony/dependency-injection/Tests/Fixtures/yaml/yaml_with_wrong_ext.ini +++ /dev/null @@ -1,2 +0,0 @@ -parameters: - with_wrong_ext: from yaml diff --git a/vendor/symfony/dependency-injection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php b/vendor/symfony/dependency-injection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php deleted file mode 100644 index 7f757297..00000000 --- a/vendor/symfony/dependency-injection/Tests/LazyProxy/Instantiator/RealServiceInstantiatorTest.php +++ /dev/null @@ -1,36 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\LazyProxy\Instantiator; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator; - -/** - * Tests for {@see \Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator}. - * - * @author Marco Pivetta - */ -class RealServiceInstantiatorTest extends TestCase -{ - public function testInstantiateProxy() - { - $instantiator = new RealServiceInstantiator(); - $instance = new \stdClass(); - $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); - $callback = function () use ($instance) { - return $instance; - }; - - $this->assertSame($instance, $instantiator->instantiateProxy($container, new Definition(), 'foo', $callback)); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/LazyProxy/PhpDumper/NullDumperTest.php b/vendor/symfony/dependency-injection/Tests/LazyProxy/PhpDumper/NullDumperTest.php deleted file mode 100644 index 5ae14932..00000000 --- a/vendor/symfony/dependency-injection/Tests/LazyProxy/PhpDumper/NullDumperTest.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\LazyProxy\PhpDumper; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper; - -/** - * Tests for {@see \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper}. - * - * @author Marco Pivetta - */ -class NullDumperTest extends TestCase -{ - public function testNullDumper() - { - $dumper = new NullDumper(); - $definition = new Definition('stdClass'); - - $this->assertFalse($dumper->isProxyCandidate($definition)); - $this->assertSame('', $dumper->getProxyFactoryCode($definition, 'foo', '(false)')); - $this->assertSame('', $dumper->getProxyCode($definition)); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/ClosureLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/ClosureLoaderTest.php deleted file mode 100644 index 125e09b6..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/ClosureLoaderTest.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\ClosureLoader; - -class ClosureLoaderTest extends TestCase -{ - public function testSupports() - { - $loader = new ClosureLoader(new ContainerBuilder()); - - $this->assertTrue($loader->supports(function ($container) {}), '->supports() returns true if the resource is loadable'); - $this->assertFalse($loader->supports('foo.foo'), '->supports() returns true if the resource is loadable'); - } - - public function testLoad() - { - $loader = new ClosureLoader($container = new ContainerBuilder()); - - $loader->load(function ($container) { - $container->setParameter('foo', 'foo'); - }); - - $this->assertEquals('foo', $container->getParameter('foo'), '->load() loads a \Closure resource'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/DirectoryLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/DirectoryLoaderTest.php deleted file mode 100644 index b4f969a0..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/DirectoryLoaderTest.php +++ /dev/null @@ -1,78 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Loader\LoaderResolver; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\DirectoryLoader; -use Symfony\Component\DependencyInjection\Loader\IniFileLoader; -use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; - -class DirectoryLoaderTest extends TestCase -{ - private static $fixturesPath; - - private $container; - private $loader; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - } - - protected function setUp() - { - $locator = new FileLocator(self::$fixturesPath); - $this->container = new ContainerBuilder(); - $this->loader = new DirectoryLoader($this->container, $locator); - $resolver = new LoaderResolver([ - new PhpFileLoader($this->container, $locator), - new IniFileLoader($this->container, $locator), - new YamlFileLoader($this->container, $locator), - $this->loader, - ]); - $this->loader->setResolver($resolver); - } - - public function testDirectoryCanBeLoadedRecursively() - { - $this->loader->load('directory/'); - $this->assertEquals(['ini' => 'ini', 'yaml' => 'yaml', 'php' => 'php'], $this->container->getParameterBag()->all(), '->load() takes a single directory'); - } - - public function testImports() - { - $this->loader->resolve('directory/import/import.yml')->load('directory/import/import.yml'); - $this->assertEquals(['ini' => 'ini', 'yaml' => 'yaml'], $this->container->getParameterBag()->all(), '->load() takes a single file that imports a directory'); - } - - public function testExceptionIsRaisedWhenDirectoryDoesNotExist() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The file "foo" does not exist (in:'); - $this->loader->load('foo/'); - } - - public function testSupports() - { - $loader = new DirectoryLoader(new ContainerBuilder(), new FileLocator()); - - $this->assertTrue($loader->supports('directory/'), '->supports("directory/") returns true'); - $this->assertTrue($loader->supports('directory/', 'directory'), '->supports("directory/", "directory") returns true'); - $this->assertFalse($loader->supports('directory'), '->supports("directory") returns false'); - $this->assertTrue($loader->supports('directory', 'directory'), '->supports("directory", "directory") returns true'); - $this->assertFalse($loader->supports('directory', 'foo'), '->supports("directory", "foo") returns false'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/FileLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/FileLoaderTest.php deleted file mode 100644 index ad0a30ba..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/FileLoaderTest.php +++ /dev/null @@ -1,246 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface as PsrContainerInterface; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Loader\LoaderResolver; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; -use Symfony\Component\DependencyInjection\Loader\FileLoader; -use Symfony\Component\DependencyInjection\Loader\IniFileLoader; -use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\MissingParent; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\FooInterface; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\AnotherSub\DeeperBaz; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\OtherDir\Baz; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\BarInterface; - -class FileLoaderTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../'); - } - - public function testImportWithGlobPattern() - { - $container = new ContainerBuilder(); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath)); - - $resolver = new LoaderResolver([ - new IniFileLoader($container, new FileLocator(self::$fixturesPath.'/ini')), - new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')), - new PhpFileLoader($container, new FileLocator(self::$fixturesPath.'/php')), - new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')), - ]); - - $loader->setResolver($resolver); - $loader->import('{F}ixtures/{xml,yaml}/services2.{yml,xml}'); - - $actual = $container->getParameterBag()->all(); - $expected = [ - 'a string', - 'foo' => 'bar', - 'values' => [ - 0, - 'integer' => 4, - 100 => null, - 'true', - true, - false, - 'on', - 'off', - 'float' => 1.3, - 1000.3, - 'a string', - ['foo', 'bar'], - ], - 'mixedcase' => ['MixedCaseKey' => 'value'], - 'constant' => \PHP_EOL, - 'bar' => '%foo%', - 'escape' => '@escapeme', - 'foo_bar' => new Reference('foo_bar'), - ]; - - $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files'); - } - - public function testRegisterClasses() - { - $container = new ContainerBuilder(); - $container->setParameter('sub_dir', 'Sub'); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); - - $loader->registerClasses(new Definition(), 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\\', 'Prototype/%sub_dir%/*'); - - $this->assertEquals( - ['service_container', Bar::class], - array_keys($container->getDefinitions()) - ); - $this->assertEquals( - [ - PsrContainerInterface::class, - ContainerInterface::class, - BarInterface::class, - ], - array_keys($container->getAliases()) - ); - } - - public function testRegisterClassesWithExclude() - { - $container = new ContainerBuilder(); - $container->setParameter('other_dir', 'OtherDir'); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); - - $loader->registerClasses( - new Definition(), - 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', - 'Prototype/*', - // load everything, except OtherDir/AnotherSub & Foo.php - 'Prototype/{%other_dir%/AnotherSub,Foo.php}' - ); - - $this->assertTrue($container->has(Bar::class)); - $this->assertTrue($container->has(Baz::class)); - $this->assertFalse($container->has(Foo::class)); - $this->assertFalse($container->has(DeeperBaz::class)); - - $this->assertEquals( - [ - PsrContainerInterface::class, - ContainerInterface::class, - BarInterface::class, - ], - array_keys($container->getAliases()) - ); - - $loader->registerClasses( - new Definition(), - 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', - 'Prototype/*', - 'Prototype/NotExistingDir' - ); - } - - public function testNestedRegisterClasses() - { - $container = new ContainerBuilder(); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); - - $prototype = new Definition(); - $prototype->setPublic(true)->setPrivate(true); - $loader->registerClasses($prototype, 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/*'); - - $this->assertTrue($container->has(Bar::class)); - $this->assertTrue($container->has(Baz::class)); - $this->assertTrue($container->has(Foo::class)); - - $this->assertEquals( - [ - PsrContainerInterface::class, - ContainerInterface::class, - FooInterface::class, - ], - array_keys($container->getAliases()) - ); - - $alias = $container->getAlias(FooInterface::class); - $this->assertSame(Foo::class, (string) $alias); - $this->assertFalse($alias->isPublic()); - $this->assertFalse($alias->isPrivate()); - } - - public function testMissingParentClass() - { - $container = new ContainerBuilder(); - $container->setParameter('bad_classes_dir', 'BadClasses'); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); - - $loader->registerClasses( - (new Definition())->setPublic(false), - 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\BadClasses\\', - 'Prototype/%bad_classes_dir%/*' - ); - - $this->assertTrue($container->has(MissingParent::class)); - - $this->assertMatchesRegularExpression( - '{Class "?Symfony\\\\Component\\\\DependencyInjection\\\\Tests\\\\Fixtures\\\\Prototype\\\\BadClasses\\\\MissingClass"? not found}', - $container->getDefinition(MissingParent::class)->getErrors()[0] - ); - } - - public function testRegisterClassesWithBadPrefix() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Expected to find class "Symfony\\\Component\\\DependencyInjection\\\Tests\\\Fixtures\\\Prototype\\\Bar" in file ".+" while importing services from resource "Prototype\/Sub\/\*", but it was not found\! Check the namespace prefix used with the resource/'); - $container = new ContainerBuilder(); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); - - // the Sub is missing from namespace prefix - $loader->registerClasses(new Definition(), 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', 'Prototype/Sub/*'); - } - - /** - * @dataProvider getIncompatibleExcludeTests - */ - public function testRegisterClassesWithIncompatibleExclude($resourcePattern, $excludePattern) - { - $container = new ContainerBuilder(); - $loader = new TestFileLoader($container, new FileLocator(self::$fixturesPath.'/Fixtures')); - - try { - $loader->registerClasses( - new Definition(), - 'Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\\', - $resourcePattern, - $excludePattern - ); - } catch (InvalidArgumentException $e) { - $this->assertEquals( - sprintf('Invalid "exclude" pattern when importing classes for "Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\": make sure your "exclude" pattern (%s) is a subset of the "resource" pattern (%s).', $excludePattern, $resourcePattern), - $e->getMessage() - ); - } - } - - public function getIncompatibleExcludeTests() - { - yield ['Prototype/*', 'yaml/*', false]; - yield ['Prototype/OtherDir/*', 'Prototype/*', false]; - } -} - -class TestFileLoader extends FileLoader -{ - public function load($resource, $type = null) - { - return $resource; - } - - public function supports($resource, $type = null) - { - return false; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/GlobFileLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/GlobFileLoaderTest.php deleted file mode 100644 index 74822f55..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/GlobFileLoaderTest.php +++ /dev/null @@ -1,44 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Resource\GlobResource; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\GlobFileLoader; - -class GlobFileLoaderTest extends TestCase -{ - public function testSupports() - { - $loader = new GlobFileLoader(new ContainerBuilder(), new FileLocator()); - - $this->assertTrue($loader->supports('any-path', 'glob'), '->supports() returns true if the resource has the glob type'); - $this->assertFalse($loader->supports('any-path'), '->supports() returns false if the resource is not of glob type'); - } - - public function testLoadAddsTheGlobResourceToTheContainer() - { - $loader = new GlobFileLoaderWithoutImport($container = new ContainerBuilder(), new FileLocator()); - $loader->load(__DIR__.'/../Fixtures/config/*'); - - $this->assertEquals(new GlobResource(__DIR__.'/../Fixtures/config', '/*', false), $container->getResources()[1]); - } -} - -class GlobFileLoaderWithoutImport extends GlobFileLoader -{ - public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null) - { - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/IniFileLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/IniFileLoaderTest.php deleted file mode 100644 index 8f261bfc..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/IniFileLoaderTest.php +++ /dev/null @@ -1,127 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\IniFileLoader; - -class IniFileLoaderTest extends TestCase -{ - protected $container; - protected $loader; - - protected function setUp() - { - $this->container = new ContainerBuilder(); - $this->loader = new IniFileLoader($this->container, new FileLocator(realpath(__DIR__.'/../Fixtures/').'/ini')); - } - - public function testIniFileCanBeLoaded() - { - $this->loader->load('parameters.ini'); - $this->assertEquals(['foo' => 'bar', 'bar' => '%foo%'], $this->container->getParameterBag()->all(), '->load() takes a single file name as its first argument'); - } - - /** - * @dataProvider getTypeConversions - */ - public function testTypeConversions($key, $value, $supported) - { - $this->loader->load('types.ini'); - $parameters = $this->container->getParameterBag()->all(); - $this->assertSame($value, $parameters[$key], '->load() converts values to PHP types'); - } - - /** - * @dataProvider getTypeConversions - * @requires PHP 5.6.1 - * This test illustrates where our conversions differs from INI_SCANNER_TYPED introduced in PHP 5.6.1 - */ - public function testTypeConversionsWithNativePhp($key, $value, $supported) - { - if (\defined('HHVM_VERSION_ID')) { - $this->markTestSkipped(); - } - - if (!$supported) { - $this->markTestSkipped(sprintf('Converting the value "%s" to "%s" is not supported by the IniFileLoader.', $key, $value)); - } - - $expected = parse_ini_file(__DIR__.'/../Fixtures/ini/types.ini', true, \INI_SCANNER_TYPED); - $this->assertSame($value, $expected['parameters'][$key], '->load() converts values to PHP types'); - } - - public function getTypeConversions() - { - return [ - ['true_comment', true, true], - ['true', true, true], - ['false', false, true], - ['on', true, true], - ['off', false, true], - ['yes', true, true], - ['no', false, true], - ['none', false, true], - ['null', null, true], - ['constant', \PHP_VERSION, true], - ['12', 12, true], - ['12_string', '12', true], - ['12_quoted_number', 12, false], // INI_SCANNER_RAW removes the double quotes - ['12_comment', 12, true], - ['12_string_comment', '12', true], - ['12_quoted_number_comment', 12, false], // INI_SCANNER_RAW removes the double quotes - ['-12', -12, true], - ['1', 1, true], - ['0', 0, true], - ['0b0110', bindec('0b0110'), false], // not supported by INI_SCANNER_TYPED - ['11112222333344445555', '1111,2222,3333,4444,5555', true], - ['0777', 0777, false], // not supported by INI_SCANNER_TYPED - ['255', 0xFF, false], // not supported by INI_SCANNER_TYPED - ['100.0', 1e2, false], // not supported by INI_SCANNER_TYPED - ['-120.0', -1.2E2, false], // not supported by INI_SCANNER_TYPED - ['-10100.1', -10100.1, false], // not supported by INI_SCANNER_TYPED - ['-10,100.1', '-10,100.1', true], - ]; - } - - public function testExceptionIsRaisedWhenIniFileDoesNotExist() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The file "foo.ini" does not exist (in:'); - $this->loader->load('foo.ini'); - } - - public function testExceptionIsRaisedWhenIniFileCannotBeParsed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The "nonvalid.ini" file is not valid.'); - @$this->loader->load('nonvalid.ini'); - } - - public function testExceptionIsRaisedWhenIniFileIsAlmostValid() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The "almostvalid.ini" file is not valid.'); - @$this->loader->load('almostvalid.ini'); - } - - public function testSupports() - { - $loader = new IniFileLoader(new ContainerBuilder(), new FileLocator()); - - $this->assertTrue($loader->supports('foo.ini'), '->supports() returns true if the resource is loadable'); - $this->assertFalse($loader->supports('foo.foo'), '->supports() returns false if the resource is not loadable'); - $this->assertTrue($loader->supports('with_wrong_ext.yml', 'ini'), '->supports() returns true if the resource with forced type is loadable'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/LoaderResolverTest.php b/vendor/symfony/dependency-injection/Tests/Loader/LoaderResolverTest.php deleted file mode 100644 index 9167e18c..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/LoaderResolverTest.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Loader\LoaderResolver; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\ClosureLoader; -use Symfony\Component\DependencyInjection\Loader\IniFileLoader; -use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; - -class LoaderResolverTest extends TestCase -{ - private static $fixturesPath; - - /** @var LoaderResolver */ - private $resolver; - - protected function setUp() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - - $container = new ContainerBuilder(); - $this->resolver = new LoaderResolver([ - new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')), - new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')), - new IniFileLoader($container, new FileLocator(self::$fixturesPath.'/ini')), - new PhpFileLoader($container, new FileLocator(self::$fixturesPath.'/php')), - new ClosureLoader($container), - ]); - } - - public function provideResourcesToLoad() - { - return [ - ['ini_with_wrong_ext.xml', 'ini', IniFileLoader::class], - ['xml_with_wrong_ext.php', 'xml', XmlFileLoader::class], - ['php_with_wrong_ext.yml', 'php', PhpFileLoader::class], - ['yaml_with_wrong_ext.ini', 'yaml', YamlFileLoader::class], - ]; - } - - /** - * @dataProvider provideResourcesToLoad - */ - public function testResolvesForcedType($resource, $type, $expectedClass) - { - $this->assertInstanceOf($expectedClass, $this->resolver->resolve($resource, $type)); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/PhpFileLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/PhpFileLoaderTest.php deleted file mode 100644 index e1812305..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/PhpFileLoaderTest.php +++ /dev/null @@ -1,101 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Dumper\PhpDumper; -use Symfony\Component\DependencyInjection\Dumper\YamlDumper; -use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; - -class PhpFileLoaderTest extends TestCase -{ - public function testSupports() - { - $loader = new PhpFileLoader(new ContainerBuilder(), new FileLocator()); - - $this->assertTrue($loader->supports('foo.php'), '->supports() returns true if the resource is loadable'); - $this->assertFalse($loader->supports('foo.foo'), '->supports() returns false if the resource is not loadable'); - $this->assertTrue($loader->supports('with_wrong_ext.yml', 'php'), '->supports() returns true if the resource with forced type is loadable'); - } - - public function testLoad() - { - $loader = new PhpFileLoader($container = new ContainerBuilder(), new FileLocator()); - - $loader->load(__DIR__.'/../Fixtures/php/simple.php'); - - $this->assertEquals('foo', $container->getParameter('foo'), '->load() loads a PHP file resource'); - } - - public function testConfigServices() - { - $fixtures = realpath(__DIR__.'/../Fixtures'); - $loader = new PhpFileLoader($container = new ContainerBuilder(), new FileLocator()); - $loader->load($fixtures.'/config/services9.php'); - - $container->compile(); - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile($fixtures.'/php/services9_compiled.php', str_replace(str_replace('\\', '\\\\', $fixtures.\DIRECTORY_SEPARATOR.'includes'.\DIRECTORY_SEPARATOR), '%path%', $dumper->dump())); - } - - /** - * @dataProvider provideConfig - */ - public function testConfig($file) - { - $fixtures = realpath(__DIR__.'/../Fixtures'); - $loader = new PhpFileLoader($container = new ContainerBuilder(), new FileLocator()); - $loader->load($fixtures.'/config/'.$file.'.php'); - - $container->compile(); - - $dumper = new YamlDumper($container); - $this->assertStringEqualsFile($fixtures.'/config/'.$file.'.expected.yml', $dumper->dump()); - } - - public function provideConfig() - { - yield ['basic']; - yield ['defaults']; - yield ['instanceof']; - yield ['prototype']; - yield ['child']; - - if (\PHP_VERSION_ID >= 70000) { - yield ['php7']; - } - } - - public function testAutoConfigureAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The service "child_service" cannot have a "parent" and also have "autoconfigure". Try disabling autoconfiguration for the service.'); - $fixtures = realpath(__DIR__.'/../Fixtures'); - $container = new ContainerBuilder(); - $loader = new PhpFileLoader($container, new FileLocator()); - $loader->load($fixtures.'/config/services_autoconfigure_with_parent.php'); - $container->compile(); - } - - public function testFactoryShortNotationNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Invalid factory "factory:method": the `service:method` notation is not available when using PHP-based DI configuration. Use "[ref(\'factory\'), \'method\']" instead.'); - $fixtures = realpath(__DIR__.'/../Fixtures'); - $container = new ContainerBuilder(); - $loader = new PhpFileLoader($container, new FileLocator()); - $loader->load($fixtures.'/config/factory_short_notation.php'); - $container->compile(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/XmlFileLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/XmlFileLoaderTest.php deleted file mode 100644 index c65ebdcf..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/XmlFileLoaderTest.php +++ /dev/null @@ -1,833 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Loader\LoaderResolver; -use Symfony\Component\Config\Resource\FileResource; -use Symfony\Component\Config\Resource\GlobResource; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Dumper\PhpDumper; -use Symfony\Component\DependencyInjection\Loader\IniFileLoader; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar; -use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype; -use Symfony\Component\ExpressionLanguage\Expression; - -class XmlFileLoaderTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - require_once self::$fixturesPath.'/includes/foo.php'; - require_once self::$fixturesPath.'/includes/ProjectExtension.php'; - require_once self::$fixturesPath.'/includes/ProjectWithXsdExtension.php'; - } - - public function testLoad() - { - $loader = new XmlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/ini')); - - try { - $loader->load('foo.xml'); - $this->fail('->load() throws an InvalidArgumentException if the loaded file does not exist'); - } catch (\Exception $e) { - $this->assertInstanceOf('InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the loaded file does not exist'); - $this->assertStringStartsWith('The file "foo.xml" does not exist (in:', $e->getMessage(), '->load() throws an InvalidArgumentException if the loaded file does not exist'); - } - } - - public function testParseFile() - { - $loader = new XmlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/ini')); - $r = new \ReflectionObject($loader); - $m = $r->getMethod('parseFileToDOM'); - $m->setAccessible(true); - - try { - $m->invoke($loader, self::$fixturesPath.'/ini/parameters.ini'); - $this->fail('->parseFileToDOM() throws an InvalidArgumentException if the loaded file is not a valid XML file'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->parseFileToDOM() throws an InvalidArgumentException if the loaded file is not a valid XML file'); - $this->assertMatchesRegularExpression(sprintf('#^Unable to parse file ".+%s": .+.$#', 'parameters.ini'), $e->getMessage(), '->parseFileToDOM() throws an InvalidArgumentException if the loaded file is not a valid XML file'); - - $e = $e->getPrevious(); - $this->assertInstanceOf('InvalidArgumentException', $e, '->parseFileToDOM() throws an InvalidArgumentException if the loaded file is not a valid XML file'); - $this->assertStringStartsWith('[ERROR 4] Start tag expected, \'<\' not found (in', $e->getMessage(), '->parseFileToDOM() throws an InvalidArgumentException if the loaded file is not a valid XML file'); - } - - $loader = new XmlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/xml')); - - try { - $m->invoke($loader, self::$fixturesPath.'/xml/nonvalid.xml'); - $this->fail('->parseFileToDOM() throws an InvalidArgumentException if the loaded file does not validate the XSD'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->parseFileToDOM() throws an InvalidArgumentException if the loaded file does not validate the XSD'); - $this->assertMatchesRegularExpression(sprintf('#^Unable to parse file ".+%s": .+.$#', 'nonvalid.xml'), $e->getMessage(), '->parseFileToDOM() throws an InvalidArgumentException if the loaded file is not a valid XML file'); - - $e = $e->getPrevious(); - $this->assertInstanceOf('InvalidArgumentException', $e, '->parseFileToDOM() throws an InvalidArgumentException if the loaded file does not validate the XSD'); - $this->assertStringStartsWith('[ERROR 1845] Element \'nonvalid\': No matching global declaration available for the validation root. (in', $e->getMessage(), '->parseFileToDOM() throws an InvalidArgumentException if the loaded file does not validate the XSD'); - } - - $xml = $m->invoke($loader, self::$fixturesPath.'/xml/services1.xml'); - $this->assertInstanceOf('DOMDocument', $xml, '->parseFileToDOM() returns an SimpleXMLElement object'); - } - - public function testLoadWithExternalEntitiesDisabled() - { - if (\LIBXML_VERSION < 20900) { - $disableEntities = libxml_disable_entity_loader(true); - } - - $containerBuilder = new ContainerBuilder(); - $loader = new XmlFileLoader($containerBuilder, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services2.xml'); - - if (\LIBXML_VERSION < 20900) { - libxml_disable_entity_loader($disableEntities); - } - - $this->assertGreaterThan(0, $containerBuilder->getParameterBag()->all(), 'Parameters can be read from the config file.'); - } - - public function testLoadParameters() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services2.xml'); - - $actual = $container->getParameterBag()->all(); - $expected = [ - 'a string', - 'foo' => 'bar', - 'values' => [ - 0, - 'integer' => 4, - 100 => null, - 'true', - true, - false, - 'on', - 'off', - 'float' => 1.3, - 1000.3, - 'a string', - ['foo', 'bar'], - ], - 'mixedcase' => ['MixedCaseKey' => 'value'], - 'constant' => \PHP_EOL, - ]; - - $this->assertEquals($expected, $actual, '->load() converts XML values to PHP ones'); - } - - public function testLoadImports() - { - $container = new ContainerBuilder(); - $resolver = new LoaderResolver([ - new IniFileLoader($container, new FileLocator(self::$fixturesPath.'/ini')), - new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yml')), - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')), - ]); - $loader->setResolver($resolver); - $loader->load('services4.xml'); - - $actual = $container->getParameterBag()->all(); - $expected = [ - 'a string', - 'foo' => 'bar', - 'values' => [ - 0, - 'integer' => 4, - 100 => null, - 'true', - true, - false, - 'on', - 'off', - 'float' => 1.3, - 1000.3, - 'a string', - ['foo', 'bar'], - ], - 'mixedcase' => ['MixedCaseKey' => 'value'], - 'constant' => \PHP_EOL, - 'bar' => '%foo%', - 'imported_from_ini' => true, - 'imported_from_yaml' => true, - 'with_wrong_ext' => 'from yaml', - ]; - - $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files'); - $this->assertTrue($actual['imported_from_ini']); - - // Bad import throws no exception due to ignore_errors value. - $loader->load('services4_bad_import.xml'); - } - - public function testLoadAnonymousServices() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services5.xml'); - $services = $container->getDefinitions(); - $this->assertCount(7, $services, '->load() attributes unique ids to anonymous services'); - - // anonymous service as an argument - $args = $services['foo']->getArguments(); - $this->assertCount(1, $args, '->load() references anonymous services as "normal" ones'); - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Reference', $args[0], '->load() converts anonymous services to references to "normal" services'); - $this->assertArrayHasKey((string) $args[0], $services, '->load() makes a reference to the created ones'); - $inner = $services[(string) $args[0]]; - $this->assertEquals('BarClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); - $this->assertFalse($inner->isPublic()); - - // inner anonymous services - $args = $inner->getArguments(); - $this->assertCount(1, $args, '->load() references anonymous services as "normal" ones'); - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Reference', $args[0], '->load() converts anonymous services to references to "normal" services'); - $this->assertArrayHasKey((string) $args[0], $services, '->load() makes a reference to the created ones'); - $inner = $services[(string) $args[0]]; - $this->assertEquals('BazClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); - $this->assertFalse($inner->isPublic()); - - // anonymous service as a property - $properties = $services['foo']->getProperties(); - $property = $properties['p']; - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Reference', $property, '->load() converts anonymous services to references to "normal" services'); - $this->assertArrayHasKey((string) $property, $services, '->load() makes a reference to the created ones'); - $inner = $services[(string) $property]; - $this->assertEquals('BuzClass', $inner->getClass(), '->load() uses the same configuration as for the anonymous ones'); - $this->assertFalse($inner->isPublic()); - - // "wild" service - $service = $container->findTaggedServiceIds('biz_tag'); - $this->assertCount(1, $service); - - foreach ($service as $id => $tag) { - $service = $container->getDefinition($id); - } - $this->assertEquals('BizClass', $service->getClass(), '->load() uses the same configuration as for the anonymous ones'); - $this->assertTrue($service->isPublic()); - - // anonymous services are shared when using decoration definitions - $container->compile(); - $services = $container->getDefinitions(); - $fooArgs = $services['foo']->getArguments(); - $barArgs = $services['bar']->getArguments(); - $this->assertSame($fooArgs[0], $barArgs[0]); - } - - /** - * @group legacy - * @expectedDeprecation Top-level anonymous services are deprecated since Symfony 3.4, the "id" attribute will be required in version 4.0 in %sservices_without_id.xml at line 5. - */ - public function testLoadAnonymousServicesWithoutId() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_without_id.xml'); - } - - public function testLoadAnonymousNestedServices() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('nested_service_without_id.xml'); - - $this->assertTrue($container->hasDefinition('FooClass')); - $arguments = $container->getDefinition('FooClass')->getArguments(); - $this->assertInstanceOf(Reference::class, array_shift($arguments)); - } - - public function testLoadServices() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services6.xml'); - $services = $container->getDefinitions(); - $this->assertArrayHasKey('foo', $services, '->load() parses elements'); - $this->assertFalse($services['not_shared']->isShared(), '->load() parses shared flag'); - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Definition', $services['foo'], '->load() converts element to Definition instances'); - $this->assertEquals('FooClass', $services['foo']->getClass(), '->load() parses the class attribute'); - $this->assertEquals('%path%/foo.php', $services['file']->getFile(), '->load() parses the file tag'); - $this->assertEquals(['foo', new Reference('foo'), [true, false]], $services['arguments']->getArguments(), '->load() parses the argument tags'); - $this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals([new Reference('baz'), 'configure'], $services['configurator2']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals(['BazClass', 'configureStatic'], $services['configurator3']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals([['setBar', []], ['setBar', [new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')]]], $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag'); - $this->assertEquals([['setBar', ['foo', new Reference('foo'), [true, false]]]], $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag'); - $this->assertEquals('factory', $services['new_factory1']->getFactory(), '->load() parses the factory tag'); - $this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag'); - $this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag'); - $this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class'); - - $aliases = $container->getAliases(); - $this->assertArrayHasKey('alias_for_foo', $aliases, '->load() parses elements'); - $this->assertEquals('foo', (string) $aliases['alias_for_foo'], '->load() parses aliases'); - $this->assertTrue($aliases['alias_for_foo']->isPublic()); - $this->assertArrayHasKey('another_alias_for_foo', $aliases); - $this->assertEquals('foo', (string) $aliases['another_alias_for_foo']); - $this->assertFalse($aliases['another_alias_for_foo']->isPublic()); - - $this->assertEquals(['decorated', null, 0], $services['decorator_service']->getDecoratedService()); - $this->assertEquals(['decorated', 'decorated.pif-pouf', 0], $services['decorator_service_with_name']->getDecoratedService()); - $this->assertEquals(['decorated', 'decorated.pif-pouf', 5], $services['decorator_service_with_name_and_priority']->getDecoratedService()); - } - - public function testParsesIteratorArgument() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services9.xml'); - - $lazyDefinition = $container->getDefinition('lazy_context'); - - $this->assertEquals([new IteratorArgument(['k1' => new Reference('foo.baz'), 'k2' => new Reference('service_container')]), new IteratorArgument([])], $lazyDefinition->getArguments(), '->load() parses lazy arguments'); - } - - public function testParsesTags() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services10.xml'); - - $services = $container->findTaggedServiceIds('foo_tag'); - $this->assertCount(1, $services); - - foreach ($services as $id => $tagAttributes) { - foreach ($tagAttributes as $attributes) { - $this->assertArrayHasKey('other_option', $attributes); - $this->assertEquals('lorem', $attributes['other_option']); - $this->assertArrayHasKey('other-option', $attributes, 'unnormalized tag attributes should not be removed'); - - $this->assertEquals('ciz', $attributes['some_option'], 'no overriding should be done when normalizing'); - $this->assertEquals('cat', $attributes['some-option']); - - $this->assertArrayNotHasKey('an_other_option', $attributes, 'normalization should not be done when an underscore is already found'); - } - } - } - - public function testParseTagsWithoutNameThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('tag_without_name.xml'); - } - - public function testParseTagWithEmptyNameThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The tag name for service ".+" in .* must be a non-empty string/'); - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('tag_with_empty_name.xml'); - } - - public function testDeprecated() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_deprecated.xml'); - - $this->assertTrue($container->getDefinition('foo')->isDeprecated()); - $message = 'The "foo" service is deprecated. You should stop using it, as it will soon be removed.'; - $this->assertSame($message, $container->getDefinition('foo')->getDeprecationMessage('foo')); - - $this->assertTrue($container->getDefinition('bar')->isDeprecated()); - $message = 'The "bar" service is deprecated.'; - $this->assertSame($message, $container->getDefinition('bar')->getDeprecationMessage('bar')); - } - - public function testConvertDomElementToArray() - { - $doc = new \DOMDocument('1.0'); - $doc->loadXML('bar'); - $this->assertEquals('bar', XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - - $doc = new \DOMDocument('1.0'); - $doc->loadXML(''); - $this->assertEquals(['foo' => 'bar'], XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - - $doc = new \DOMDocument('1.0'); - $doc->loadXML('bar'); - $this->assertEquals(['foo' => 'bar'], XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - - $doc = new \DOMDocument('1.0'); - $doc->loadXML('barbar'); - $this->assertEquals(['foo' => ['value' => 'bar', 'foo' => 'bar']], XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - - $doc = new \DOMDocument('1.0'); - $doc->loadXML(''); - $this->assertEquals(['foo' => null], XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - - $doc = new \DOMDocument('1.0'); - $doc->loadXML(''); - $this->assertEquals(['foo' => null], XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - - $doc = new \DOMDocument('1.0'); - $doc->loadXML(''); - $this->assertEquals(['foo' => [['foo' => 'bar'], ['foo' => 'bar']]], XmlFileLoader::convertDomElementToArray($doc->documentElement), '::convertDomElementToArray() converts a \DomElement to an array'); - } - - public function testExtensions() - { - $container = new ContainerBuilder(); - $container->registerExtension(new \ProjectExtension()); - $container->registerExtension(new \ProjectWithXsdExtension()); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - - // extension without an XSD - $loader->load('extensions/services1.xml'); - $container->compile(); - $services = $container->getDefinitions(); - $parameters = $container->getParameterBag()->all(); - - $this->assertArrayHasKey('project.service.bar', $services, '->load() parses extension elements'); - $this->assertArrayHasKey('project.parameter.bar', $parameters, '->load() parses extension elements'); - - $this->assertEquals('BAR', $services['project.service.foo']->getClass(), '->load() parses extension elements'); - $this->assertEquals('BAR', $parameters['project.parameter.foo'], '->load() parses extension elements'); - - // extension with an XSD - $container = new ContainerBuilder(); - $container->registerExtension(new \ProjectExtension()); - $container->registerExtension(new \ProjectWithXsdExtension()); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('extensions/services2.xml'); - $container->compile(); - $services = $container->getDefinitions(); - $parameters = $container->getParameterBag()->all(); - - $this->assertArrayHasKey('project.service.bar', $services, '->load() parses extension elements'); - $this->assertArrayHasKey('project.parameter.bar', $parameters, '->load() parses extension elements'); - - $this->assertEquals('BAR', $services['project.service.foo']->getClass(), '->load() parses extension elements'); - $this->assertEquals('BAR', $parameters['project.parameter.foo'], '->load() parses extension elements'); - - $container = new ContainerBuilder(); - $container->registerExtension(new \ProjectExtension()); - $container->registerExtension(new \ProjectWithXsdExtension()); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - - // extension with an XSD (does not validate) - try { - $loader->load('extensions/services3.xml'); - $this->fail('->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - $this->assertMatchesRegularExpression(sprintf('#^Unable to parse file ".+%s": .+.$#', 'services3.xml'), $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - - $e = $e->getPrevious(); - $this->assertInstanceOf('InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - $this->assertStringContainsString('The attribute \'bar\' is not allowed', $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - } - - // non-registered extension - try { - $loader->load('extensions/services4.xml'); - $this->fail('->load() throws an InvalidArgumentException if the tag is not valid'); - } catch (\Exception $e) { - $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tag is not valid'); - $this->assertStringStartsWith('There is no extension able to load the configuration for "project:bar" (in', $e->getMessage(), '->load() throws an InvalidArgumentException if the tag is not valid'); - } - } - - public function testExtensionInPhar() - { - if (\extension_loaded('suhosin') && false === strpos(ini_get('suhosin.executor.include.whitelist'), 'phar')) { - $this->markTestSkipped('To run this test, add "phar" to the "suhosin.executor.include.whitelist" settings in your php.ini file.'); - } - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM makes this test conflict with those run in separate processes.'); - } - - require_once self::$fixturesPath.'/includes/ProjectWithXsdExtensionInPhar.phar'; - - // extension with an XSD in PHAR archive - $container = new ContainerBuilder(); - $container->registerExtension(new \ProjectWithXsdExtensionInPhar()); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('extensions/services6.xml'); - - // extension with an XSD in PHAR archive (does not validate) - try { - $loader->load('extensions/services7.xml'); - $this->fail('->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - $this->assertMatchesRegularExpression(sprintf('#^Unable to parse file ".+%s": .+.$#', 'services7.xml'), $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - - $e = $e->getPrevious(); - $this->assertInstanceOf('InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - $this->assertStringContainsString('The attribute \'bar\' is not allowed', $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration does not validate the XSD'); - } - } - - public function testSupports() - { - $loader = new XmlFileLoader(new ContainerBuilder(), new FileLocator()); - - $this->assertTrue($loader->supports('foo.xml'), '->supports() returns true if the resource is loadable'); - $this->assertFalse($loader->supports('foo.foo'), '->supports() returns false if the resource is not loadable'); - $this->assertTrue($loader->supports('with_wrong_ext.yml', 'xml'), '->supports() returns true if the resource with forced type is loadable'); - } - - public function testNoNamingConflictsForAnonymousServices() - { - $container = new ContainerBuilder(); - - $loader1 = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml/extension1')); - $loader1->load('services.xml'); - $services = $container->getDefinitions(); - $this->assertCount(3, $services, '->load() attributes unique ids to anonymous services'); - $loader2 = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml/extension2')); - $loader2->load('services.xml'); - $services = $container->getDefinitions(); - $this->assertCount(5, $services, '->load() attributes unique ids to anonymous services'); - - $services = $container->getDefinitions(); - $args1 = $services['extension1.foo']->getArguments(); - $inner1 = $services[(string) $args1[0]]; - $this->assertEquals('BarClass1', $inner1->getClass(), '->load() uses the same configuration as for the anonymous ones'); - $args2 = $services['extension2.foo']->getArguments(); - $inner2 = $services[(string) $args2[0]]; - $this->assertEquals('BarClass2', $inner2->getClass(), '->load() uses the same configuration as for the anonymous ones'); - } - - public function testDocTypeIsNotAllowed() - { - $container = new ContainerBuilder(); - - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - - // document types are not allowed. - try { - $loader->load('withdoctype.xml'); - $this->fail('->load() throws an InvalidArgumentException if the configuration contains a document type'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration contains a document type'); - $this->assertMatchesRegularExpression(sprintf('#^Unable to parse file ".+%s": .+.$#', 'withdoctype.xml'), $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration contains a document type'); - - $e = $e->getPrevious(); - $this->assertInstanceOf('InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the configuration contains a document type'); - $this->assertSame('Document types are not allowed.', $e->getMessage(), '->load() throws an InvalidArgumentException if the configuration contains a document type'); - } - } - - public function testXmlNamespaces() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('namespaces.xml'); - $services = $container->getDefinitions(); - - $this->assertArrayHasKey('foo', $services, '->load() parses elements'); - $this->assertCount(1, $services['foo']->getTag('foo.tag'), '->load parses elements'); - $this->assertEquals([['setBar', ['foo']]], $services['foo']->getMethodCalls(), '->load() parses the tag'); - } - - public function testLoadIndexedArguments() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services14.xml'); - - $this->assertEquals(['index_0' => 'app'], $container->findDefinition('logger')->getArguments()); - } - - public function testLoadInlinedServices() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services21.xml'); - - $foo = $container->getDefinition('foo'); - - $fooFactory = $foo->getFactory(); - $this->assertInstanceOf(Reference::class, $fooFactory[0]); - $this->assertTrue($container->has((string) $fooFactory[0])); - $fooFactoryDefinition = $container->getDefinition((string) $fooFactory[0]); - $this->assertSame('FooFactory', $fooFactoryDefinition->getClass()); - $this->assertSame('createFoo', $fooFactory[1]); - - $fooFactoryFactory = $fooFactoryDefinition->getFactory(); - $this->assertInstanceOf(Reference::class, $fooFactoryFactory[0]); - $this->assertTrue($container->has((string) $fooFactoryFactory[0])); - $this->assertSame('Foobar', $container->getDefinition((string) $fooFactoryFactory[0])->getClass()); - $this->assertSame('createFooFactory', $fooFactoryFactory[1]); - - $fooConfigurator = $foo->getConfigurator(); - $this->assertInstanceOf(Reference::class, $fooConfigurator[0]); - $this->assertTrue($container->has((string) $fooConfigurator[0])); - $fooConfiguratorDefinition = $container->getDefinition((string) $fooConfigurator[0]); - $this->assertSame('Bar', $fooConfiguratorDefinition->getClass()); - $this->assertSame('configureFoo', $fooConfigurator[1]); - - $barConfigurator = $fooConfiguratorDefinition->getConfigurator(); - $this->assertInstanceOf(Reference::class, $barConfigurator[0]); - $this->assertSame('Baz', $container->getDefinition((string) $barConfigurator[0])->getClass()); - $this->assertSame('configureBar', $barConfigurator[1]); - } - - /** - * @group legacy - */ - public function testType() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services22.xml'); - - $this->assertEquals(['Bar', 'Baz'], $container->getDefinition('foo')->getAutowiringTypes()); - } - - public function testAutowire() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services23.xml'); - - $this->assertTrue($container->getDefinition('bar')->isAutowired()); - } - - public function testClassFromId() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('class_from_id.xml'); - $container->compile(); - - $this->assertEquals(CaseSensitiveClass::class, $container->getDefinition(CaseSensitiveClass::class)->getClass()); - } - - public function testPrototype() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_prototype.xml'); - - $ids = array_keys($container->getDefinitions()); - sort($ids); - $this->assertSame([Prototype\Foo::class, Prototype\Sub\Bar::class, 'service_container'], $ids); - - $resources = $container->getResources(); - - $fixturesDir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR; - $resources = array_map('strval', $resources); - $this->assertContains((string) (new FileResource($fixturesDir.'xml'.\DIRECTORY_SEPARATOR.'services_prototype.xml')), $resources); - $this->assertContains((string) (new GlobResource($fixturesDir.'Prototype', '/*', true)), $resources); - $this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo', $resources); - $this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar', $resources); - } - - /** - * @group legacy - * @expectedDeprecation Using the attribute "class" is deprecated for the service "bar" which is defined as an alias %s. - * @expectedDeprecation Using the element "tag" is deprecated for the service "bar" which is defined as an alias %s. - * @expectedDeprecation Using the element "factory" is deprecated for the service "bar" which is defined as an alias %s. - */ - public function testAliasDefinitionContainsUnsupportedElements() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - - $loader->load('legacy_invalid_alias_definition.xml'); - - $this->assertTrue($container->has('bar')); - } - - public function testArgumentWithKeyOutsideCollection() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('with_key_outside_collection.xml'); - - $this->assertSame(['type' => 'foo', 'bar'], $container->getDefinition('foo')->getArguments()); - } - - public function testDefaults() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services28.xml'); - - $this->assertFalse($container->getDefinition('with_defaults')->isPublic()); - $this->assertSame(['foo' => [[]]], $container->getDefinition('with_defaults')->getTags()); - $this->assertTrue($container->getDefinition('with_defaults')->isAutowired()); - $this->assertArrayNotHasKey('public', $container->getDefinition('with_defaults')->getChanges()); - $this->assertArrayNotHasKey('autowire', $container->getDefinition('with_defaults')->getChanges()); - - $container->compile(); - - $this->assertTrue($container->getDefinition('no_defaults')->isPublic()); - - $this->assertSame(['foo' => [[]]], $container->getDefinition('no_defaults')->getTags()); - - $this->assertFalse($container->getDefinition('no_defaults')->isAutowired()); - - $this->assertTrue($container->getDefinition('child_def')->isPublic()); - $this->assertSame(['foo' => [[]]], $container->getDefinition('child_def')->getTags()); - $this->assertFalse($container->getDefinition('child_def')->isAutowired()); - - $definitions = $container->getDefinitions(); - $this->assertSame('service_container', key($definitions)); - - array_shift($definitions); - $anonymous = current($definitions); - $this->assertSame('bar', key($definitions)); - $this->assertTrue($anonymous->isPublic()); - $this->assertTrue($anonymous->isAutowired()); - $this->assertSame(['foo' => [[]]], $anonymous->getTags()); - } - - public function testNamedArguments() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_named_args.xml'); - - $this->assertEquals(['$apiKey' => 'ABCD', CaseSensitiveClass::class => null], $container->getDefinition(NamedArgumentsDummy::class)->getArguments()); - - $container->compile(); - - $this->assertEquals([null, 'ABCD'], $container->getDefinition(NamedArgumentsDummy::class)->getArguments()); - $this->assertEquals([['setApiKey', ['123']]], $container->getDefinition(NamedArgumentsDummy::class)->getMethodCalls()); - } - - public function testInstanceof() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_instanceof.xml'); - $container->compile(); - - $definition = $container->getDefinition(Bar::class); - $this->assertTrue($definition->isAutowired()); - $this->assertTrue($definition->isLazy()); - $this->assertSame(['foo' => [[]], 'bar' => [[]]], $definition->getTags()); - } - - public function testInstanceOfAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The service "child_service" cannot use the "parent" option in the same file where "instanceof" configuration is defined as using both is not supported. Move your child definitions to a separate file.'); - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_instanceof_with_parent.xml'); - $container->compile(); - } - - public function testAutoConfigureAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The service "child_service" cannot have a "parent" and also have "autoconfigure". Try setting autoconfigure="false" for the service.'); - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_autoconfigure_with_parent.xml'); - $container->compile(); - } - - public function testDefaultsAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Attribute "autowire" on service "child_service" cannot be inherited from "defaults" when a "parent" is set. Move your child definitions to a separate file or define this attribute explicitly.'); - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_defaults_with_parent.xml'); - $container->compile(); - } - - public function testAutoConfigureInstanceof() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_autoconfigure.xml'); - - $this->assertTrue($container->getDefinition('use_defaults_settings')->isAutoconfigured()); - $this->assertFalse($container->getDefinition('override_defaults_settings_to_false')->isAutoconfigured()); - } - - public function testBindings() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_bindings.xml'); - $container->compile(); - - $definition = $container->getDefinition('bar'); - $this->assertEquals([ - 'NonExistent' => null, - BarInterface::class => new Reference(Bar::class), - '$foo' => [null], - '$quz' => 'quz', - '$factory' => 'factory', - ], array_map(function ($v) { return $v->getValues()[0]; }, $definition->getBindings())); - $this->assertEquals([ - 'quz', - null, - new Reference(Bar::class), - [null], - ], $definition->getArguments()); - - $definition = $container->getDefinition(Bar::class); - $this->assertEquals([ - null, - 'factory', - ], $definition->getArguments()); - $this->assertEquals([ - 'NonExistent' => null, - '$quz' => 'quz', - '$factory' => 'factory', - ], array_map(function ($v) { return $v->getValues()[0]; }, $definition->getBindings())); - } - - public function testTsantosContainer() - { - $container = new ContainerBuilder(); - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('services_tsantos.xml'); - $container->compile(); - - $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_tsantos.php', $dumper->dump()); - } - - /** - * The pass may throw an exception, which will cause the test to fail. - */ - public function testOverriddenDefaultsBindings() - { - $container = new ContainerBuilder(); - - $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); - $loader->load('defaults_bindings.xml'); - $loader->load('defaults_bindings2.xml'); - - (new ResolveBindingsPass())->process($container); - - $this->assertSame('overridden', $container->get('bar')->quz); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/Loader/YamlFileLoaderTest.php b/vendor/symfony/dependency-injection/Tests/Loader/YamlFileLoaderTest.php deleted file mode 100644 index 3a5cc380..00000000 --- a/vendor/symfony/dependency-injection/Tests/Loader/YamlFileLoaderTest.php +++ /dev/null @@ -1,736 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\FileLocator; -use Symfony\Component\Config\Loader\LoaderResolver; -use Symfony\Component\Config\Resource\FileResource; -use Symfony\Component\Config\Resource\GlobResource; -use Symfony\Component\DependencyInjection\Argument\IteratorArgument; -use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Loader\IniFileLoader; -use Symfony\Component\DependencyInjection\Loader\PhpFileLoader; -use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; -use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar; -use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface; -use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; -use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; -use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype; -use Symfony\Component\ExpressionLanguage\Expression; - -class YamlFileLoaderTest extends TestCase -{ - protected static $fixturesPath; - - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - require_once self::$fixturesPath.'/includes/foo.php'; - require_once self::$fixturesPath.'/includes/ProjectExtension.php'; - } - - public function testLoadUnExistFile() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The file ".+" does not exist./'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/ini')); - $r = new \ReflectionObject($loader); - $m = $r->getMethod('loadFile'); - $m->setAccessible(true); - - $m->invoke($loader, 'foo.yml'); - } - - public function testLoadInvalidYamlFile() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The file ".+" does not contain valid YAML./'); - $path = self::$fixturesPath.'/ini'; - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator($path)); - $r = new \ReflectionObject($loader); - $m = $r->getMethod('loadFile'); - $m->setAccessible(true); - - $m->invoke($loader, $path.'/parameters.ini'); - } - - /** - * @dataProvider provideInvalidFiles - */ - public function testLoadInvalidFile($file) - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - - $loader->load($file.'.yml'); - } - - public function provideInvalidFiles() - { - return [ - ['bad_parameters'], - ['bad_imports'], - ['bad_import'], - ['bad_services'], - ['bad_service'], - ['bad_calls'], - ['bad_format'], - ['nonvalid1'], - ['nonvalid2'], - ]; - } - - public function testLoadParameters() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services2.yml'); - $this->assertEquals(['foo' => 'bar', 'mixedcase' => ['MixedCaseKey' => 'value'], 'values' => [true, false, 0, 1000.3, \PHP_INT_MAX], 'bar' => 'foo', 'escape' => '@escapeme', 'foo_bar' => new Reference('foo_bar')], $container->getParameterBag()->all(), '->load() converts YAML keys to lowercase'); - } - - public function testLoadImports() - { - $container = new ContainerBuilder(); - $resolver = new LoaderResolver([ - new IniFileLoader($container, new FileLocator(self::$fixturesPath.'/ini')), - new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')), - new PhpFileLoader($container, new FileLocator(self::$fixturesPath.'/php')), - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')), - ]); - $loader->setResolver($resolver); - $loader->load('services4.yml'); - - $actual = $container->getParameterBag()->all(); - $expected = [ - 'foo' => 'bar', - 'values' => [true, false, \PHP_INT_MAX], - 'bar' => '%foo%', - 'escape' => '@escapeme', - 'foo_bar' => new Reference('foo_bar'), - 'mixedcase' => ['MixedCaseKey' => 'value'], - 'imported_from_ini' => true, - 'imported_from_xml' => true, - 'with_wrong_ext' => 'from yaml', - ]; - $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files'); - $this->assertTrue($actual['imported_from_ini']); - - // Bad import throws no exception due to ignore_errors value. - $loader->load('services4_bad_import.yml'); - } - - public function testLoadServices() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services6.yml'); - $services = $container->getDefinitions(); - $this->assertArrayHasKey('foo', $services, '->load() parses service elements'); - $this->assertFalse($services['not_shared']->isShared(), '->load() parses the shared flag'); - $this->assertInstanceOf('Symfony\\Component\\DependencyInjection\\Definition', $services['foo'], '->load() converts service element to Definition instances'); - $this->assertEquals('FooClass', $services['foo']->getClass(), '->load() parses the class attribute'); - $this->assertEquals('%path%/foo.php', $services['file']->getFile(), '->load() parses the file tag'); - $this->assertEquals(['foo', new Reference('foo'), [true, false]], $services['arguments']->getArguments(), '->load() parses the argument tags'); - $this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals([new Reference('baz'), 'configure'], $services['configurator2']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals(['BazClass', 'configureStatic'], $services['configurator3']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals([['setBar', []], ['setBar', []], ['setBar', [new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')]]], $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag'); - $this->assertEquals([['setBar', ['foo', new Reference('foo'), [true, false]]]], $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag'); - $this->assertEquals('factory', $services['new_factory1']->getFactory(), '->load() parses the factory tag'); - $this->assertEquals([new Reference('baz'), 'getClass'], $services['new_factory2']->getFactory(), '->load() parses the factory tag'); - $this->assertEquals(['BazClass', 'getInstance'], $services['new_factory3']->getFactory(), '->load() parses the factory tag'); - $this->assertSame([null, 'getInstance'], $services['new_factory4']->getFactory(), '->load() accepts factory tag without class'); - $this->assertEquals(['foo', new Reference('baz')], $services['Acme\WithShortCutArgs']->getArguments(), '->load() parses short service definition'); - - $aliases = $container->getAliases(); - $this->assertArrayHasKey('alias_for_foo', $aliases, '->load() parses aliases'); - $this->assertEquals('foo', (string) $aliases['alias_for_foo'], '->load() parses aliases'); - $this->assertTrue($aliases['alias_for_foo']->isPublic()); - $this->assertArrayHasKey('another_alias_for_foo', $aliases); - $this->assertEquals('foo', (string) $aliases['another_alias_for_foo']); - $this->assertFalse($aliases['another_alias_for_foo']->isPublic()); - $this->assertTrue(isset($aliases['another_third_alias_for_foo'])); - $this->assertEquals('foo', (string) $aliases['another_third_alias_for_foo']); - $this->assertTrue($aliases['another_third_alias_for_foo']->isPublic()); - - $this->assertEquals(['decorated', null, 0], $services['decorator_service']->getDecoratedService()); - $this->assertEquals(['decorated', 'decorated.pif-pouf', 0], $services['decorator_service_with_name']->getDecoratedService()); - $this->assertEquals(['decorated', 'decorated.pif-pouf', 5], $services['decorator_service_with_name_and_priority']->getDecoratedService()); - } - - public function testLoadFactoryShortSyntax() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services14.yml'); - $services = $container->getDefinitions(); - - $this->assertEquals([new Reference('baz'), 'getClass'], $services['factory']->getFactory(), '->load() parses the factory tag with service:method'); - $this->assertEquals(['FooBacFactory', 'createFooBar'], $services['factory_with_static_call']->getFactory(), '->load() parses the factory tag with Class::method'); - } - - public function testLoadConfiguratorShortSyntax() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_configurator_short_syntax.yml'); - $services = $container->getDefinitions(); - - $this->assertEquals([new Reference('foo_bar_configurator'), 'configure'], $services['foo_bar']->getConfigurator(), '->load() parses the configurator tag with service:method'); - $this->assertEquals(['FooBarConfigurator', 'configureFooBar'], $services['foo_bar_with_static_call']->getConfigurator(), '->load() parses the configurator tag with Class::method'); - } - - public function testExtensions() - { - $container = new ContainerBuilder(); - $container->registerExtension(new \ProjectExtension()); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services10.yml'); - $container->compile(); - $services = $container->getDefinitions(); - $parameters = $container->getParameterBag()->all(); - - $this->assertArrayHasKey('project.service.bar', $services, '->load() parses extension elements'); - $this->assertArrayHasKey('project.parameter.bar', $parameters, '->load() parses extension elements'); - - $this->assertEquals('BAR', $services['project.service.foo']->getClass(), '->load() parses extension elements'); - $this->assertEquals('BAR', $parameters['project.parameter.foo'], '->load() parses extension elements'); - - try { - $loader->load('services11.yml'); - $this->fail('->load() throws an InvalidArgumentException if the tag is not valid'); - } catch (\Exception $e) { - $this->assertInstanceOf('\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tag is not valid'); - $this->assertStringStartsWith('There is no extension able to load the configuration for "foobarfoobar" (in', $e->getMessage(), '->load() throws an InvalidArgumentException if the tag is not valid'); - } - } - - public function testExtensionWithNullConfig() - { - $container = new ContainerBuilder(); - $container->registerExtension(new \ProjectExtension()); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('null_config.yml'); - $container->compile(); - - $this->assertSame([null], $container->getParameter('project.configs')); - } - - public function testSupports() - { - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator()); - - $this->assertTrue($loader->supports('foo.yml'), '->supports() returns true if the resource is loadable'); - $this->assertTrue($loader->supports('foo.yaml'), '->supports() returns true if the resource is loadable'); - $this->assertFalse($loader->supports('foo.foo'), '->supports() returns false if the resource is not loadable'); - $this->assertTrue($loader->supports('with_wrong_ext.xml', 'yml'), '->supports() returns true if the resource with forced type is loadable'); - $this->assertTrue($loader->supports('with_wrong_ext.xml', 'yaml'), '->supports() returns true if the resource with forced type is loadable'); - } - - public function testNonArrayTagsThrowsException() - { - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - try { - $loader->load('badtag1.yml'); - $this->fail('->load() should throw an exception when the tags key of a service is not an array'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if the tags key is not an array'); - $this->assertStringStartsWith('Parameter "tags" must be an array for service', $e->getMessage(), '->load() throws an InvalidArgumentException if the tags key is not an array'); - } - } - - public function testTagWithoutNameThrowsException() - { - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - try { - $loader->load('badtag2.yml'); - $this->fail('->load() should throw an exception when a tag is missing the name key'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if a tag is missing the name key'); - $this->assertStringStartsWith('A "tags" entry is missing a "name" key for service ', $e->getMessage(), '->load() throws an InvalidArgumentException if a tag is missing the name key'); - } - } - - public function testNameOnlyTagsAreAllowedAsString() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('tag_name_only.yml'); - - $this->assertCount(1, $container->getDefinition('foo_service')->getTag('foo')); - } - - public function testTagWithAttributeArrayThrowsException() - { - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - try { - $loader->load('badtag3.yml'); - $this->fail('->load() should throw an exception when a tag-attribute is not a scalar'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException', $e, '->load() throws an InvalidArgumentException if a tag-attribute is not a scalar'); - $this->assertStringStartsWith('A "tags" attribute must be of a scalar-type for service "foo_service", tag "foo", attribute "bar"', $e->getMessage(), '->load() throws an InvalidArgumentException if a tag-attribute is not a scalar'); - } - } - - public function testLoadYamlOnlyWithKeys() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services21.yml'); - - $definition = $container->getDefinition('manager'); - $this->assertEquals([['setLogger', [new Reference('logger')]], ['setClass', ['User']]], $definition->getMethodCalls()); - $this->assertEquals([true], $definition->getArguments()); - $this->assertEquals(['manager' => [['alias' => 'user']]], $definition->getTags()); - } - - public function testTagWithEmptyNameThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The tag name for service ".+" in .+ must be a non-empty string/'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('tag_name_empty_string.yml'); - } - - public function testTagWithNonStringNameThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/The tag name for service ".+" in .+ must be a non-empty string/'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('tag_name_no_string.yml'); - } - - public function testTypesNotArray() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('bad_types1.yml'); - } - - public function testTypeNotString() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('bad_types2.yml'); - } - - /** - * @group legacy - */ - public function testTypes() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services22.yml'); - - $this->assertEquals(['Foo', 'Bar'], $container->getDefinition('foo_service')->getAutowiringTypes()); - $this->assertEquals(['Foo'], $container->getDefinition('baz_service')->getAutowiringTypes()); - } - - public function testParsesIteratorArgument() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services9.yml'); - - $lazyDefinition = $container->getDefinition('lazy_context'); - - $this->assertEquals([new IteratorArgument(['k1' => new Reference('foo.baz'), 'k2' => new Reference('service_container')]), new IteratorArgument([])], $lazyDefinition->getArguments(), '->load() parses lazy arguments'); - - $message = 'The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.'; - $this->assertSame($message, $container->getDefinition('deprecated_service')->getDeprecationMessage('deprecated_service')); - } - - public function testAutowire() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services23.yml'); - - $this->assertTrue($container->getDefinition('bar_service')->isAutowired()); - } - - public function testClassFromId() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('class_from_id.yml'); - $container->compile(); - - $this->assertEquals(CaseSensitiveClass::class, $container->getDefinition(CaseSensitiveClass::class)->getClass()); - } - - public function testPrototype() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_prototype.yml'); - - $ids = array_keys($container->getDefinitions()); - sort($ids); - $this->assertSame([Prototype\Foo::class, Prototype\Sub\Bar::class, 'service_container'], $ids); - - $resources = $container->getResources(); - - $fixturesDir = \dirname(__DIR__).\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR; - $resources = array_map('strval', $resources); - $this->assertContains((string) (new FileResource($fixturesDir.'yaml'.\DIRECTORY_SEPARATOR.'services_prototype.yml')), $resources); - $this->assertContains((string) (new GlobResource($fixturesDir.'Prototype', '', true)), $resources); - $this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo', $resources); - $this->assertContains('reflection.Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar', $resources); - } - - public function testPrototypeWithNamespace() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_prototype_namespace.yml'); - - $ids = array_keys($container->getDefinitions()); - sort($ids); - - $this->assertSame([ - Prototype\OtherDir\Component1\Dir1\Service1::class, - Prototype\OtherDir\Component1\Dir2\Service2::class, - Prototype\OtherDir\Component2\Dir1\Service4::class, - Prototype\OtherDir\Component2\Dir2\Service5::class, - 'service_container', - ], $ids); - - $this->assertTrue($container->getDefinition(Prototype\OtherDir\Component1\Dir1\Service1::class)->hasTag('foo')); - $this->assertTrue($container->getDefinition(Prototype\OtherDir\Component2\Dir1\Service4::class)->hasTag('foo')); - $this->assertFalse($container->getDefinition(Prototype\OtherDir\Component1\Dir1\Service1::class)->hasTag('bar')); - $this->assertFalse($container->getDefinition(Prototype\OtherDir\Component2\Dir1\Service4::class)->hasTag('bar')); - - $this->assertTrue($container->getDefinition(Prototype\OtherDir\Component1\Dir2\Service2::class)->hasTag('bar')); - $this->assertTrue($container->getDefinition(Prototype\OtherDir\Component2\Dir2\Service5::class)->hasTag('bar')); - $this->assertFalse($container->getDefinition(Prototype\OtherDir\Component1\Dir2\Service2::class)->hasTag('foo')); - $this->assertFalse($container->getDefinition(Prototype\OtherDir\Component2\Dir2\Service5::class)->hasTag('foo')); - } - - public function testPrototypeWithNamespaceAndNoResource() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/A "resource" attribute must be set when the "namespace" attribute is set for service ".+" in .+/'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_prototype_namespace_without_resource.yml'); - } - - public function testDefaults() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services28.yml'); - - $this->assertFalse($container->getDefinition('with_defaults')->isPublic()); - $this->assertSame(['foo' => [[]]], $container->getDefinition('with_defaults')->getTags()); - $this->assertTrue($container->getDefinition('with_defaults')->isAutowired()); - $this->assertArrayNotHasKey('public', $container->getDefinition('with_defaults')->getChanges()); - $this->assertArrayNotHasKey('autowire', $container->getDefinition('with_defaults')->getChanges()); - - $this->assertFalse($container->getAlias('with_defaults_aliased')->isPublic()); - $this->assertFalse($container->getAlias('with_defaults_aliased_short')->isPublic()); - - $this->assertFalse($container->getDefinition('Acme\WithShortCutArgs')->isPublic()); - $this->assertSame(['foo' => [[]]], $container->getDefinition('Acme\WithShortCutArgs')->getTags()); - $this->assertTrue($container->getDefinition('Acme\WithShortCutArgs')->isAutowired()); - - $container->compile(); - - $this->assertTrue($container->getDefinition('with_null')->isPublic()); - $this->assertTrue($container->getDefinition('no_defaults')->isPublic()); - - // foo tag is inherited from defaults - $this->assertSame(['foo' => [[]]], $container->getDefinition('with_null')->getTags()); - $this->assertSame(['foo' => [[]]], $container->getDefinition('no_defaults')->getTags()); - - $this->assertTrue($container->getDefinition('with_null')->isAutowired()); - $this->assertFalse($container->getDefinition('no_defaults')->isAutowired()); - - $this->assertTrue($container->getDefinition('child_def')->isPublic()); - $this->assertSame(['foo' => [[]]], $container->getDefinition('child_def')->getTags()); - $this->assertFalse($container->getDefinition('child_def')->isAutowired()); - } - - public function testNamedArguments() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_named_args.yml'); - - $this->assertEquals([null, '$apiKey' => 'ABCD'], $container->getDefinition(NamedArgumentsDummy::class)->getArguments()); - $this->assertEquals(['$apiKey' => 'ABCD', CaseSensitiveClass::class => null], $container->getDefinition('another_one')->getArguments()); - - $container->compile(); - - $this->assertEquals([null, 'ABCD'], $container->getDefinition(NamedArgumentsDummy::class)->getArguments()); - $this->assertEquals([null, 'ABCD'], $container->getDefinition('another_one')->getArguments()); - $this->assertEquals([['setApiKey', ['123']]], $container->getDefinition('another_one')->getMethodCalls()); - } - - public function testInstanceof() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_instanceof.yml'); - $container->compile(); - - $definition = $container->getDefinition(Bar::class); - $this->assertTrue($definition->isAutowired()); - $this->assertTrue($definition->isLazy()); - $this->assertSame(['foo' => [[]], 'bar' => [[]]], $definition->getTags()); - } - - public function testInstanceOfAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The service "child_service" cannot use the "parent" option in the same file where "_instanceof" configuration is defined as using both is not supported. Move your child definitions to a separate file.'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_instanceof_with_parent.yml'); - $container->compile(); - } - - public function testAutoConfigureAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The service "child_service" cannot have a "parent" and also have "autoconfigure". Try setting "autoconfigure: false" for the service.'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_autoconfigure_with_parent.yml'); - $container->compile(); - } - - public function testDefaultsAndChildDefinitionNotAllowed() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Attribute "autowire" on service "child_service" cannot be inherited from "_defaults" when a "parent" is set. Move your child definitions to a separate file or define this attribute explicitly.'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_defaults_with_parent.yml'); - $container->compile(); - } - - public function testDecoratedServicesWithWrongSyntaxThrowsException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('The value of the "decorates" option for the "bar" service must be the id of the service without the "@" prefix (replace "@foo" with "foo").'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('bad_decorates.yml'); - } - - public function testInvalidTagsWithDefaults() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Parameter "tags" must be an array for service "Foo\\\Bar" in ".+services31_invalid_tags\.yml"\. Check your YAML syntax./'); - $loader = new YamlFileLoader(new ContainerBuilder(), new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services31_invalid_tags.yml'); - } - - /** - * @group legacy - * @expectedDeprecation Service names that start with an underscore are deprecated since Symfony 3.3 and will be reserved in 4.0. Rename the "_foo" service or define it in XML instead. - */ - public function testUnderscoreServiceId() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_underscore.yml'); - } - - public function testAnonymousServices() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('anonymous_services.yml'); - - $definition = $container->getDefinition('Foo'); - $this->assertTrue($definition->isAutowired()); - - // Anonymous service in an argument - $args = $definition->getArguments(); - $this->assertCount(1, $args); - $this->assertInstanceOf(Reference::class, $args[0]); - $this->assertTrue($container->has((string) $args[0])); - $this->assertMatchesRegularExpression('/^\d+_Bar~[._A-Za-z0-9]{7}$/', (string) $args[0]); - - $anonymous = $container->getDefinition((string) $args[0]); - $this->assertEquals('Bar', $anonymous->getClass()); - $this->assertFalse($anonymous->isPublic()); - $this->assertTrue($anonymous->isAutowired()); - - // Anonymous service in a callable - $factory = $definition->getFactory(); - $this->assertIsArray($factory); - $this->assertInstanceOf(Reference::class, $factory[0]); - $this->assertTrue($container->has((string) $factory[0])); - $this->assertMatchesRegularExpression('/^\d+_Quz~[._A-Za-z0-9]{7}$/', (string) $factory[0]); - $this->assertEquals('constructFoo', $factory[1]); - - $anonymous = $container->getDefinition((string) $factory[0]); - $this->assertEquals('Quz', $anonymous->getClass()); - $this->assertFalse($anonymous->isPublic()); - $this->assertFalse($anonymous->isAutowired()); - } - - public function testAnonymousServicesInDifferentFilesWithSameNameDoNotConflict() - { - $container = new ContainerBuilder(); - - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml/foo')); - $loader->load('services.yml'); - - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml/bar')); - $loader->load('services.yml'); - - $this->assertCount(5, $container->getDefinitions()); - } - - public function testAnonymousServicesInInstanceof() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('anonymous_services_in_instanceof.yml'); - - $definition = $container->getDefinition('Dummy'); - - $instanceof = $definition->getInstanceofConditionals(); - $this->assertCount(3, $instanceof); - $this->assertArrayHasKey('DummyInterface', $instanceof); - - $args = $instanceof['DummyInterface']->getProperties(); - $this->assertCount(1, $args); - $this->assertInstanceOf(Reference::class, $args['foo']); - $this->assertTrue($container->has((string) $args['foo'])); - - $anonymous = $container->getDefinition((string) $args['foo']); - $this->assertEquals('Anonymous', $anonymous->getClass()); - $this->assertFalse($anonymous->isPublic()); - $this->assertEmpty($anonymous->getInstanceofConditionals()); - - $this->assertFalse($container->has('Bar')); - } - - public function testAnonymousServicesWithAliases() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Creating an alias using the tag "!service" is not allowed in ".+anonymous_services_alias\.yml"\./'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('anonymous_services_alias.yml'); - } - - public function testAnonymousServicesInParameters() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Using an anonymous service in a parameter is not allowed in ".+anonymous_services_in_parameters\.yml"\./'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('anonymous_services_in_parameters.yml'); - } - - public function testAutoConfigureInstanceof() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_autoconfigure.yml'); - - $this->assertTrue($container->getDefinition('use_defaults_settings')->isAutoconfigured()); - $this->assertFalse($container->getDefinition('override_defaults_settings_to_false')->isAutoconfigured()); - } - - public function testEmptyDefaultsThrowsClearException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Service "_defaults" key must be an array, "NULL" given in ".+bad_empty_defaults\.yml"\./'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('bad_empty_defaults.yml'); - } - - public function testEmptyInstanceofThrowsClearException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $this->expectExceptionMessageMatches('/Service "_instanceof" key must be an array, "NULL" given in ".+bad_empty_instanceof\.yml"\./'); - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('bad_empty_instanceof.yml'); - } - - public function testBindings() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('services_bindings.yml'); - $container->compile(); - - $definition = $container->getDefinition('bar'); - $this->assertEquals([ - 'NonExistent' => null, - BarInterface::class => new Reference(Bar::class), - '$foo' => [null], - '$quz' => 'quz', - '$factory' => 'factory', - ], array_map(function ($v) { return $v->getValues()[0]; }, $definition->getBindings())); - $this->assertEquals([ - 'quz', - null, - new Reference(Bar::class), - [null], - ], $definition->getArguments()); - - $definition = $container->getDefinition(Bar::class); - $this->assertEquals([ - null, - 'factory', - ], $definition->getArguments()); - $this->assertEquals([ - 'NonExistent' => null, - '$quz' => 'quz', - '$factory' => 'factory', - ], array_map(function ($v) { return $v->getValues()[0]; }, $definition->getBindings())); - } - - /** - * The pass may throw an exception, which will cause the test to fail. - */ - public function testOverriddenDefaultsBindings() - { - $container = new ContainerBuilder(); - - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('defaults_bindings.yml'); - $loader->load('defaults_bindings2.yml'); - - (new ResolveBindingsPass())->process($container); - - $this->assertSame('overridden', $container->get('bar')->quz); - } - - /** - * @group legacy - * @expectedDeprecation The configuration key "factory" is unsupported for the service "foo" which is defined as an alias in %s. - * @expectedDeprecation The configuration key "parent" is unsupported for the service "foo" which is defined as an alias in %s. - */ - public function testAliasDefinitionContainsUnsupportedElements() - { - $container = new ContainerBuilder(); - $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); - $loader->load('legacy_invalid_alias_definition.yml'); - $this->assertTrue($container->has('foo')); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php b/vendor/symfony/dependency-injection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php deleted file mode 100644 index 273072f9..00000000 --- a/vendor/symfony/dependency-injection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php +++ /dev/null @@ -1,159 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\ParameterBag; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag; - -class EnvPlaceholderParameterBagTest extends TestCase -{ - public function testGetThrowsInvalidArgumentExceptionIfEnvNameContainsNonWordCharacters() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException'); - $bag = new EnvPlaceholderParameterBag(); - $bag->get('env(%foo%)'); - } - - public function testMergeWillNotDuplicateIdenticalParameters() - { - $envVariableName = 'DB_HOST'; - $parameter = sprintf('env(%s)', $envVariableName); - $firstBag = new EnvPlaceholderParameterBag(); - - // initialize placeholders - $firstBag->get($parameter); - $secondBag = clone $firstBag; - - $firstBag->mergeEnvPlaceholders($secondBag); - $mergedPlaceholders = $firstBag->getEnvPlaceholders(); - - $placeholderForVariable = $mergedPlaceholders[$envVariableName]; - $placeholder = array_values($placeholderForVariable)[0]; - - $this->assertCount(1, $placeholderForVariable); - $this->assertIsString($placeholder); - $this->assertStringContainsString($envVariableName, $placeholder); - } - - public function testMergeWhereFirstBagIsEmptyWillWork() - { - $envVariableName = 'DB_HOST'; - $parameter = sprintf('env(%s)', $envVariableName); - $firstBag = new EnvPlaceholderParameterBag(); - $secondBag = new EnvPlaceholderParameterBag(); - - // initialize placeholder only in second bag - $secondBag->get($parameter); - - $this->assertEmpty($firstBag->getEnvPlaceholders()); - - $firstBag->mergeEnvPlaceholders($secondBag); - $mergedPlaceholders = $firstBag->getEnvPlaceholders(); - - $placeholderForVariable = $mergedPlaceholders[$envVariableName]; - $placeholder = array_values($placeholderForVariable)[0]; - - $this->assertCount(1, $placeholderForVariable); - $this->assertIsString($placeholder); - $this->assertStringContainsString($envVariableName, $placeholder); - } - - public function testMergeWherePlaceholderOnlyExistsInSecond() - { - $uniqueEnvName = 'DB_HOST'; - $commonEnvName = 'DB_USER'; - - $uniqueParamName = sprintf('env(%s)', $uniqueEnvName); - $commonParamName = sprintf('env(%s)', $commonEnvName); - - $firstBag = new EnvPlaceholderParameterBag(); - // initialize common placeholder - $firstBag->get($commonParamName); - $secondBag = clone $firstBag; - - // initialize unique placeholder - $secondBag->get($uniqueParamName); - - $firstBag->mergeEnvPlaceholders($secondBag); - $merged = $firstBag->getEnvPlaceholders(); - - $this->assertCount(1, $merged[$uniqueEnvName]); - // second bag has same placeholder for commonEnvName - $this->assertCount(1, $merged[$commonEnvName]); - } - - public function testMergeWithDifferentIdentifiersForPlaceholders() - { - $envName = 'DB_USER'; - $paramName = sprintf('env(%s)', $envName); - - $firstBag = new EnvPlaceholderParameterBag(); - $secondBag = new EnvPlaceholderParameterBag(); - // initialize placeholders - $firstPlaceholder = $firstBag->get($paramName); - $secondPlaceholder = $secondBag->get($paramName); - - $firstBag->mergeEnvPlaceholders($secondBag); - $merged = $firstBag->getEnvPlaceholders(); - - $this->assertNotEquals($firstPlaceholder, $secondPlaceholder); - $this->assertCount(2, $merged[$envName]); - } - - public function testResolveEnvCastsIntToString() - { - $bag = new EnvPlaceholderParameterBag(); - $bag->get('env(INT_VAR)'); - $bag->set('env(INT_VAR)', 2); - $bag->resolve(); - $this->assertSame('2', $bag->all()['env(INT_VAR)']); - } - - public function testResolveEnvAllowsNull() - { - $bag = new EnvPlaceholderParameterBag(); - $bag->get('env(NULL_VAR)'); - $bag->set('env(NULL_VAR)', null); - $bag->resolve(); - $this->assertNull($bag->all()['env(NULL_VAR)']); - } - - public function testResolveThrowsOnBadDefaultValue() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The default value of env parameter "ARRAY_VAR" must be scalar or null, "array" given.'); - $bag = new EnvPlaceholderParameterBag(); - $bag->get('env(ARRAY_VAR)'); - $bag->set('env(ARRAY_VAR)', []); - $bag->resolve(); - } - - public function testGetEnvAllowsNull() - { - $bag = new EnvPlaceholderParameterBag(); - $bag->set('env(NULL_VAR)', null); - $bag->get('env(NULL_VAR)'); - $bag->resolve(); - - $this->assertNull($bag->all()['env(NULL_VAR)']); - } - - public function testGetThrowsOnBadDefaultValue() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException'); - $this->expectExceptionMessage('The default value of an env() parameter must be scalar or null, but "array" given to "env(ARRAY_VAR)".'); - $bag = new EnvPlaceholderParameterBag(); - $bag->set('env(ARRAY_VAR)', []); - $bag->get('env(ARRAY_VAR)'); - $bag->resolve(); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ParameterBag/FrozenParameterBagTest.php b/vendor/symfony/dependency-injection/Tests/ParameterBag/FrozenParameterBagTest.php deleted file mode 100644 index ed89c8e4..00000000 --- a/vendor/symfony/dependency-injection/Tests/ParameterBag/FrozenParameterBagTest.php +++ /dev/null @@ -1,56 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\ParameterBag; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag; - -class FrozenParameterBagTest extends TestCase -{ - public function testConstructor() - { - $parameters = [ - 'foo' => 'foo', - 'bar' => 'bar', - ]; - $bag = new FrozenParameterBag($parameters); - $this->assertEquals($parameters, $bag->all(), '__construct() takes an array of parameters as its first argument'); - } - - public function testClear() - { - $this->expectException('LogicException'); - $bag = new FrozenParameterBag([]); - $bag->clear(); - } - - public function testSet() - { - $this->expectException('LogicException'); - $bag = new FrozenParameterBag([]); - $bag->set('foo', 'bar'); - } - - public function testAdd() - { - $this->expectException('LogicException'); - $bag = new FrozenParameterBag([]); - $bag->add([]); - } - - public function testRemove() - { - $this->expectException('LogicException'); - $bag = new FrozenParameterBag(['foo' => 'bar']); - $bag->remove('foo'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ParameterBag/ParameterBagTest.php b/vendor/symfony/dependency-injection/Tests/ParameterBag/ParameterBagTest.php deleted file mode 100644 index 9b39458c..00000000 --- a/vendor/symfony/dependency-injection/Tests/ParameterBag/ParameterBagTest.php +++ /dev/null @@ -1,264 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests\ParameterBag; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; -use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; -use Symfony\Component\DependencyInjection\Exception\RuntimeException; -use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; - -class ParameterBagTest extends TestCase -{ - public function testConstructor() - { - $bag = new ParameterBag($parameters = [ - 'foo' => 'foo', - 'bar' => 'bar', - ]); - $this->assertEquals($parameters, $bag->all(), '__construct() takes an array of parameters as its first argument'); - } - - public function testClear() - { - $bag = new ParameterBag($parameters = [ - 'foo' => 'foo', - 'bar' => 'bar', - ]); - $bag->clear(); - $this->assertEquals([], $bag->all(), '->clear() removes all parameters'); - } - - public function testRemove() - { - $bag = new ParameterBag([ - 'foo' => 'foo', - 'bar' => 'bar', - ]); - $bag->remove('foo'); - $this->assertEquals(['bar' => 'bar'], $bag->all(), '->remove() removes a parameter'); - } - - public function testGetSet() - { - $bag = new ParameterBag(['foo' => 'bar']); - $bag->set('bar', 'foo'); - $this->assertEquals('foo', $bag->get('bar'), '->set() sets the value of a new parameter'); - - $bag->set('foo', 'baz'); - $this->assertEquals('baz', $bag->get('foo'), '->set() overrides previously set parameter'); - - try { - $bag->get('baba'); - $this->fail('->get() throws an Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException if the key does not exist'); - } catch (\Exception $e) { - $this->assertInstanceOf('Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException', $e, '->get() throws an Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException if the key does not exist'); - $this->assertEquals('You have requested a non-existent parameter "baba".', $e->getMessage(), '->get() throws an Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException if the key does not exist'); - } - } - - /** - * @dataProvider provideGetThrowParameterNotFoundExceptionData - */ - public function testGetThrowParameterNotFoundException($parameterKey, $exceptionMessage) - { - $bag = new ParameterBag([ - 'foo' => 'foo', - 'bar' => 'bar', - 'baz' => 'baz', - 'fiz' => ['bar' => ['boo' => 12]], - ]); - - $this->expectException(ParameterNotFoundException::class); - $this->expectExceptionMessage($exceptionMessage); - - $bag->get($parameterKey); - } - - public function provideGetThrowParameterNotFoundExceptionData() - { - return [ - ['foo1', 'You have requested a non-existent parameter "foo1". Did you mean this: "foo"?'], - ['bag', 'You have requested a non-existent parameter "bag". Did you mean one of these: "bar", "baz"?'], - ['', 'You have requested a non-existent parameter "".'], - - ['fiz.bar.boo', 'You have requested a non-existent parameter "fiz.bar.boo". You cannot access nested array items, do you want to inject "fiz" instead?'], - ]; - } - - public function testHas() - { - $bag = new ParameterBag(['foo' => 'bar']); - $this->assertTrue($bag->has('foo'), '->has() returns true if a parameter is defined'); - $this->assertFalse($bag->has('bar'), '->has() returns false if a parameter is not defined'); - } - - /** - * @group legacy - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "BAR" instead of "bar" is deprecated since Symfony 3.4. - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since Symfony 3.4. - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "FOO" instead of "foo" is deprecated since Symfony 3.4. - * @expectedDeprecation Parameter names will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since Symfony 3.4. - */ - public function testMixedCase() - { - $bag = new ParameterBag([ - 'foo' => 'foo', - 'bar' => 'bar', - ]); - - $bag->remove('BAR'); - $this->assertEquals(['foo' => 'foo'], $bag->all(), '->remove() converts key to lowercase before removing'); - - $bag->set('Foo', 'baz1'); - $this->assertEquals('baz1', $bag->get('foo'), '->set() converts the key to lowercase'); - $this->assertEquals('baz1', $bag->get('FOO'), '->get() converts the key to lowercase'); - - $this->assertTrue($bag->has('Foo'), '->has() converts the key to lowercase'); - } - - public function testResolveValue() - { - $bag = new ParameterBag([]); - $this->assertEquals('foo', $bag->resolveValue('foo'), '->resolveValue() returns its argument unmodified if no placeholders are found'); - - $bag = new ParameterBag(['foo' => 'bar']); - $this->assertEquals('I\'m a bar', $bag->resolveValue('I\'m a %foo%'), '->resolveValue() replaces placeholders by their values'); - $this->assertEquals(['bar' => 'bar'], $bag->resolveValue(['%foo%' => '%foo%']), '->resolveValue() replaces placeholders in keys and values of arrays'); - $this->assertEquals(['bar' => ['bar' => ['bar' => 'bar']]], $bag->resolveValue(['%foo%' => ['%foo%' => ['%foo%' => '%foo%']]]), '->resolveValue() replaces placeholders in nested arrays'); - $this->assertEquals('I\'m a %%foo%%', $bag->resolveValue('I\'m a %%foo%%'), '->resolveValue() supports % escaping by doubling it'); - $this->assertEquals('I\'m a bar %%foo bar', $bag->resolveValue('I\'m a %foo% %%foo %foo%'), '->resolveValue() supports % escaping by doubling it'); - $this->assertEquals(['foo' => ['bar' => ['ding' => 'I\'m a bar %%foo %%bar']]], $bag->resolveValue(['foo' => ['bar' => ['ding' => 'I\'m a bar %%foo %%bar']]]), '->resolveValue() supports % escaping by doubling it'); - - $bag = new ParameterBag(['foo' => true]); - $this->assertTrue($bag->resolveValue('%foo%'), '->resolveValue() replaces arguments that are just a placeholder by their value without casting them to strings'); - $bag = new ParameterBag(['foo' => null]); - $this->assertNull($bag->resolveValue('%foo%'), '->resolveValue() replaces arguments that are just a placeholder by their value without casting them to strings'); - - $bag = new ParameterBag(['foo' => 'bar', 'baz' => '%%%foo% %foo%%% %%foo%% %%%foo%%%']); - $this->assertEquals('%%bar bar%% %%foo%% %%bar%%', $bag->resolveValue('%baz%'), '->resolveValue() replaces params placed besides escaped %'); - - $bag = new ParameterBag(['baz' => '%%s?%%s']); - $this->assertEquals('%%s?%%s', $bag->resolveValue('%baz%'), '->resolveValue() is not replacing greedily'); - - $bag = new ParameterBag([]); - try { - $bag->resolveValue('%foobar%'); - $this->fail('->resolveValue() throws an InvalidArgumentException if a placeholder references a non-existent parameter'); - } catch (ParameterNotFoundException $e) { - $this->assertEquals('You have requested a non-existent parameter "foobar".', $e->getMessage(), '->resolveValue() throws a ParameterNotFoundException if a placeholder references a non-existent parameter'); - } - - try { - $bag->resolveValue('foo %foobar% bar'); - $this->fail('->resolveValue() throws a ParameterNotFoundException if a placeholder references a non-existent parameter'); - } catch (ParameterNotFoundException $e) { - $this->assertEquals('You have requested a non-existent parameter "foobar".', $e->getMessage(), '->resolveValue() throws a ParameterNotFoundException if a placeholder references a non-existent parameter'); - } - - $bag = new ParameterBag(['foo' => 'a %bar%', 'bar' => []]); - try { - $bag->resolveValue('%foo%'); - $this->fail('->resolveValue() throws a RuntimeException when a parameter embeds another non-string parameter'); - } catch (RuntimeException $e) { - $this->assertEquals('A string value must be composed of strings and/or numbers, but found parameter "bar" of type "array" inside string value "a %bar%".', $e->getMessage(), '->resolveValue() throws a RuntimeException when a parameter embeds another non-string parameter'); - } - - $bag = new ParameterBag(['foo' => '%bar%', 'bar' => '%foobar%', 'foobar' => '%foo%']); - try { - $bag->resolveValue('%foo%'); - $this->fail('->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference'); - } catch (ParameterCircularReferenceException $e) { - $this->assertEquals('Circular reference detected for parameter "foo" ("foo" > "bar" > "foobar" > "foo").', $e->getMessage(), '->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference'); - } - - $bag = new ParameterBag(['foo' => 'a %bar%', 'bar' => 'a %foobar%', 'foobar' => 'a %foo%']); - try { - $bag->resolveValue('%foo%'); - $this->fail('->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference'); - } catch (ParameterCircularReferenceException $e) { - $this->assertEquals('Circular reference detected for parameter "foo" ("foo" > "bar" > "foobar" > "foo").', $e->getMessage(), '->resolveValue() throws a ParameterCircularReferenceException when a parameter has a circular reference'); - } - - $bag = new ParameterBag(['host' => 'foo.bar', 'port' => 1337]); - $this->assertEquals('foo.bar:1337', $bag->resolveValue('%host%:%port%')); - } - - public function testResolveIndicatesWhyAParameterIsNeeded() - { - $bag = new ParameterBag(['foo' => '%bar%']); - - try { - $bag->resolve(); - } catch (ParameterNotFoundException $e) { - $this->assertEquals('The parameter "foo" has a dependency on a non-existent parameter "bar".', $e->getMessage()); - } - - $bag = new ParameterBag(['foo' => '%bar%']); - - try { - $bag->resolve(); - } catch (ParameterNotFoundException $e) { - $this->assertEquals('The parameter "foo" has a dependency on a non-existent parameter "bar".', $e->getMessage()); - } - } - - public function testResolveUnescapesValue() - { - $bag = new ParameterBag([ - 'foo' => ['bar' => ['ding' => 'I\'m a bar %%foo %%bar']], - 'bar' => 'I\'m a %%foo%%', - ]); - - $bag->resolve(); - - $this->assertEquals('I\'m a %foo%', $bag->get('bar'), '->resolveValue() supports % escaping by doubling it'); - $this->assertEquals(['bar' => ['ding' => 'I\'m a bar %foo %bar']], $bag->get('foo'), '->resolveValue() supports % escaping by doubling it'); - } - - public function testEscapeValue() - { - $bag = new ParameterBag(); - - $bag->add([ - 'foo' => $bag->escapeValue(['bar' => ['ding' => 'I\'m a bar %foo %bar', 'zero' => null]]), - 'bar' => $bag->escapeValue('I\'m a %foo%'), - ]); - - $this->assertEquals('I\'m a %%foo%%', $bag->get('bar'), '->escapeValue() escapes % by doubling it'); - $this->assertEquals(['bar' => ['ding' => 'I\'m a bar %%foo %%bar', 'zero' => null]], $bag->get('foo'), '->escapeValue() escapes % by doubling it'); - } - - /** - * @dataProvider stringsWithSpacesProvider - */ - public function testResolveStringWithSpacesReturnsString($expected, $test, $description) - { - $bag = new ParameterBag(['foo' => 'bar']); - - try { - $this->assertEquals($expected, $bag->resolveString($test), $description); - } catch (ParameterNotFoundException $e) { - $this->fail(sprintf('%s - "%s"', $description, $expected)); - } - } - - public function stringsWithSpacesProvider() - { - return [ - ['bar', '%foo%', 'Parameters must be wrapped by %.'], - ['% foo %', '% foo %', 'Parameters should not have spaces.'], - ['{% set my_template = "foo" %}', '{% set my_template = "foo" %}', 'Twig-like strings are not parameters.'], - ['50% is less than 100%', '50% is less than 100%', 'Text between % signs is allowed, if there are spaces.'], - ]; - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ParameterTest.php b/vendor/symfony/dependency-injection/Tests/ParameterTest.php deleted file mode 100644 index 975e5582..00000000 --- a/vendor/symfony/dependency-injection/Tests/ParameterTest.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Parameter; - -class ParameterTest extends TestCase -{ - public function testConstructor() - { - $ref = new Parameter('foo'); - $this->assertEquals('foo', (string) $ref, '__construct() sets the id of the parameter, which is used for the __toString() method'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ReferenceTest.php b/vendor/symfony/dependency-injection/Tests/ReferenceTest.php deleted file mode 100644 index 1fc274a2..00000000 --- a/vendor/symfony/dependency-injection/Tests/ReferenceTest.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Reference; - -class ReferenceTest extends TestCase -{ - public function testConstructor() - { - $ref = new Reference('foo'); - $this->assertEquals('foo', (string) $ref, '__construct() sets the id of the reference, which is used for the __toString() method'); - } -} diff --git a/vendor/symfony/dependency-injection/Tests/ServiceLocatorTest.php b/vendor/symfony/dependency-injection/Tests/ServiceLocatorTest.php deleted file mode 100644 index 52466af9..00000000 --- a/vendor/symfony/dependency-injection/Tests/ServiceLocatorTest.php +++ /dev/null @@ -1,148 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\DependencyInjection\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Container; -use Symfony\Component\DependencyInjection\ServiceLocator; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; - -class ServiceLocatorTest extends TestCase -{ - public function testHas() - { - $locator = new ServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - function () { return 'dummy'; }, - ]); - - $this->assertTrue($locator->has('foo')); - $this->assertTrue($locator->has('bar')); - $this->assertFalse($locator->has('dummy')); - } - - public function testGet() - { - $locator = new ServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('baz', $locator->get('bar')); - } - - public function testGetDoesNotMemoize() - { - $i = 0; - $locator = new ServiceLocator([ - 'foo' => function () use (&$i) { - ++$i; - - return 'bar'; - }, - ]); - - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame('bar', $locator->get('foo')); - $this->assertSame(2, $i); - } - - public function testGetThrowsOnUndefinedService() - { - $this->expectException('Psr\Container\NotFoundExceptionInterface'); - $this->expectExceptionMessage('Service "dummy" not found: the container inside "Symfony\Component\DependencyInjection\Tests\ServiceLocatorTest" is a smaller service locator that only knows about the "foo" and "bar" services.'); - $locator = new ServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - ]); - - $locator->get('dummy'); - } - - public function testThrowsOnUndefinedInternalService() - { - $this->expectException('Psr\Container\NotFoundExceptionInterface'); - $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); - $locator = new ServiceLocator([ - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, - ]); - - $locator->get('foo'); - } - - public function testThrowsOnCircularReference() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException'); - $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); - $locator = new ServiceLocator([ - 'foo' => function () use (&$locator) { return $locator->get('bar'); }, - 'bar' => function () use (&$locator) { return $locator->get('baz'); }, - 'baz' => function () use (&$locator) { return $locator->get('bar'); }, - ]); - - $locator->get('foo'); - } - - public function testThrowsInServiceSubscriber() - { - $this->expectException('Psr\Container\NotFoundExceptionInterface'); - $this->expectExceptionMessage('Service "foo" not found: even though it exists in the app\'s container, the container inside "caller" is a smaller service locator that only knows about the "bar" service. Unless you need extra laziness, try using dependency injection instead. Otherwise, you need to declare it using "SomeServiceSubscriber::getSubscribedServices()".'); - $container = new Container(); - $container->set('foo', new \stdClass()); - $subscriber = new SomeServiceSubscriber(); - $subscriber->container = new ServiceLocator(['bar' => function () {}]); - $subscriber->container = $subscriber->container->withContext('caller', $container); - - $subscriber->getFoo(); - } - - public function testGetThrowsServiceNotFoundException() - { - $this->expectException('Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException'); - $this->expectExceptionMessage('Service "foo" not found: even though it exists in the app\'s container, the container inside "foo" is a smaller service locator that is empty... Try using dependency injection instead.'); - $container = new Container(); - $container->set('foo', new \stdClass()); - - $locator = new ServiceLocator([]); - $locator = $locator->withContext('foo', $container); - $locator->get('foo'); - } - - public function testInvoke() - { - $locator = new ServiceLocator([ - 'foo' => function () { return 'bar'; }, - 'bar' => function () { return 'baz'; }, - ]); - - $this->assertSame('bar', $locator('foo')); - $this->assertSame('baz', $locator('bar')); - $this->assertNull($locator('dummy'), '->__invoke() should return null on invalid service'); - } -} - -class SomeServiceSubscriber implements ServiceSubscriberinterface -{ - public $container; - - public function getFoo() - { - return $this->container->get('foo'); - } - - public static function getSubscribedServices() - { - return ['bar' => 'stdClass']; - } -} diff --git a/vendor/symfony/dependency-injection/TypedReference.php b/vendor/symfony/dependency-injection/TypedReference.php index aad78e80..3ec4035b 100644 --- a/vendor/symfony/dependency-injection/TypedReference.php +++ b/vendor/symfony/dependency-injection/TypedReference.php @@ -19,19 +19,27 @@ class TypedReference extends Reference { private $type; + private $name; private $requiringClass; /** - * @param string $id The service identifier - * @param string $type The PHP type of the identified service - * @param string $requiringClass The class of the service that requires the referenced type - * @param int $invalidBehavior The behavior when the service does not exist + * @param string $id The service identifier + * @param string $type The PHP type of the identified service + * @param int $invalidBehavior The behavior when the service does not exist + * @param string|null $name The name of the argument targeting the service */ - public function __construct($id, $type, $requiringClass = '', $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) + public function __construct(string $id, string $type, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $name = null) { + if (\is_string($invalidBehavior ?? '') || \is_int($name)) { + @trigger_error(sprintf('Passing the $requiringClass as 3rd argument for "%s()" is deprecated since Symfony 4.1. It should be removed, moving all following arguments 1 to the left.', __METHOD__), \E_USER_DEPRECATED); + + $this->requiringClass = $invalidBehavior; + $invalidBehavior = 3 < \func_num_args() ? func_get_arg(3) : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + } else { + $this->name = $type === $id ? $name : null; + } parent::__construct($id, $invalidBehavior); $this->type = $type; - $this->requiringClass = $requiringClass; } public function getType() @@ -39,13 +47,28 @@ public function getType() return $this->type; } + public function getName(): ?string + { + return $this->name; + } + + /** + * @deprecated since Symfony 4.1 + */ public function getRequiringClass() { - return $this->requiringClass; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), \E_USER_DEPRECATED); + + return $this->requiringClass ?? ''; } + /** + * @deprecated since Symfony 4.1 + */ public function canBeAutoregistered() { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), \E_USER_DEPRECATED); + return $this->requiringClass && (false !== $i = strpos($this->type, '\\')) && 0 === strncasecmp($this->type, $this->requiringClass, 1 + $i); } } diff --git a/vendor/symfony/dependency-injection/Variable.php b/vendor/symfony/dependency-injection/Variable.php index 9654ee4d..21d33ebb 100644 --- a/vendor/symfony/dependency-injection/Variable.php +++ b/vendor/symfony/dependency-injection/Variable.php @@ -28,14 +28,14 @@ class Variable { private $name; - /** - * @param string $name - */ - public function __construct($name) + public function __construct(string $name) { $this->name = $name; } + /** + * @return string + */ public function __toString() { return $this->name; diff --git a/vendor/symfony/dependency-injection/composer.json b/vendor/symfony/dependency-injection/composer.json index eee41ce0..15c01508 100644 --- a/vendor/symfony/dependency-injection/composer.json +++ b/vendor/symfony/dependency-injection/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/dependency-injection", "type": "library", - "description": "Symfony DependencyInjection Component", + "description": "Allows you to standardize and centralize the way objects are constructed in your application", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,13 +16,15 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "psr/container": "^1.0" + "php": ">=7.1.3", + "psr/container": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1.6|^2" }, "require-dev": { - "symfony/yaml": "~3.4|~4.0", - "symfony/config": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0" + "symfony/yaml": "^4.4|^5.0", + "symfony/config": "^4.3", + "symfony/expression-language": "^3.4|^4.0|^5.0" }, "suggest": { "symfony/yaml": "", @@ -32,13 +34,14 @@ "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them" }, "conflict": { - "symfony/config": "<3.3.7", - "symfony/finder": "<3.3", + "symfony/config": "<4.3|>=5.0", + "symfony/finder": "<3.4", "symfony/proxy-manager-bridge": "<3.4", "symfony/yaml": "<3.4" }, "provide": { - "psr/container-implementation": "1.0" + "psr/container-implementation": "1.0", + "symfony/service-implementation": "1.0|2.0" }, "autoload": { "psr-4": { "Symfony\\Component\\DependencyInjection\\": "" }, diff --git a/vendor/symfony/dependency-injection/phpunit.xml.dist b/vendor/symfony/dependency-injection/phpunit.xml.dist deleted file mode 100644 index 21dee2a8..00000000 --- a/vendor/symfony/dependency-injection/phpunit.xml.dist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/debug/.gitignore b/vendor/symfony/deprecation-contracts/.gitignore similarity index 100% rename from vendor/symfony/debug/.gitignore rename to vendor/symfony/deprecation-contracts/.gitignore diff --git a/vendor/symfony/deprecation-contracts/CHANGELOG.md b/vendor/symfony/deprecation-contracts/CHANGELOG.md new file mode 100644 index 00000000..7932e261 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/vendor/symfony/deprecation-contracts/LICENSE b/vendor/symfony/deprecation-contracts/LICENSE new file mode 100644 index 00000000..406242ff --- /dev/null +++ b/vendor/symfony/deprecation-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/deprecation-contracts/README.md b/vendor/symfony/deprecation-contracts/README.md new file mode 100644 index 00000000..4957933a --- /dev/null +++ b/vendor/symfony/deprecation-contracts/README.md @@ -0,0 +1,26 @@ +Symfony Deprecation Contracts +============================= + +A generic function and convention to trigger deprecation notices. + +This package provides a single global function named `trigger_deprecation()` that triggers silenced deprecation notices. + +By using a custom PHP error handler such as the one provided by the Symfony ErrorHandler component, +the triggered deprecations can be caught and logged for later discovery, both on dev and prod environments. + +The function requires at least 3 arguments: + - the name of the Composer package that is triggering the deprecation + - the version of the package that introduced the deprecation + - the message of the deprecation + - more arguments can be provided: they will be inserted in the message using `printf()` formatting + +Example: +```php +trigger_deprecation('symfony/blockchain', '8.9', 'Using "%s" is deprecated, use "%s" instead.', 'bitcoin', 'fabcoin'); +``` + +This will generate the following message: +`Since symfony/blockchain 8.9: Using "bitcoin" is deprecated, use "fabcoin" instead.` + +While not necessarily recommended, the deprecation notices can be completely ignored by declaring an empty +`function trigger_deprecation() {}` in your application. diff --git a/vendor/symfony/deprecation-contracts/composer.json b/vendor/symfony/deprecation-contracts/composer.json new file mode 100644 index 00000000..cc7cc123 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/deprecation-contracts", + "type": "library", + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/vendor/symfony/deprecation-contracts/function.php b/vendor/symfony/deprecation-contracts/function.php new file mode 100644 index 00000000..d4371504 --- /dev/null +++ b/vendor/symfony/deprecation-contracts/function.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!function_exists('trigger_deprecation')) { + /** + * Triggers a silenced deprecation notice. + * + * @param string $package The name of the Composer package that is triggering the deprecation + * @param string $version The version of the package that introduced the deprecation + * @param string $message The message of the deprecation + * @param mixed ...$args Values to insert in the message using printf() formatting + * + * @author Nicolas Grekas + */ + function trigger_deprecation(string $package, string $version, string $message, ...$args): void + { + @trigger_error(($package || $version ? "Since $package $version: " : '').($args ? vsprintf($message, $args) : $message), \E_USER_DEPRECATED); + } +} diff --git a/vendor/symfony/error-handler/BufferingLogger.php b/vendor/symfony/error-handler/BufferingLogger.php new file mode 100644 index 00000000..cfd55c61 --- /dev/null +++ b/vendor/symfony/error-handler/BufferingLogger.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler; + +use Psr\Log\AbstractLogger; + +/** + * A buffering logger that stacks logs for later. + * + * @author Nicolas Grekas + */ +class BufferingLogger extends AbstractLogger +{ + private $logs = []; + + public function log($level, $message, array $context = []): void + { + $this->logs[] = [$level, $message, $context]; + } + + public function cleanLogs(): array + { + $logs = $this->logs; + $this->logs = []; + + return $logs; + } + + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + foreach ($this->logs as [$level, $message, $context]) { + if (false !== strpos($message, '{')) { + foreach ($context as $key => $val) { + if (null === $val || \is_scalar($val) || (\is_object($val) && \is_callable([$val, '__toString']))) { + $message = str_replace("{{$key}}", $val, $message); + } elseif ($val instanceof \DateTimeInterface) { + $message = str_replace("{{$key}}", $val->format(\DateTime::RFC3339), $message); + } elseif (\is_object($val)) { + $message = str_replace("{{$key}}", '[object '.\get_class($val).']', $message); + } else { + $message = str_replace("{{$key}}", '['.\gettype($val).']', $message); + } + } + } + + error_log(sprintf('%s [%s] %s', date(\DateTime::RFC3339), $level, $message)); + } + } +} diff --git a/vendor/symfony/error-handler/CHANGELOG.md b/vendor/symfony/error-handler/CHANGELOG.md new file mode 100644 index 00000000..c7c245a4 --- /dev/null +++ b/vendor/symfony/error-handler/CHANGELOG.md @@ -0,0 +1,8 @@ +CHANGELOG +========= + +4.4.0 +----- + + * added the component + * added `ErrorHandler::call()` method utility to turn any PHP error into `\ErrorException` diff --git a/vendor/symfony/error-handler/Debug.php b/vendor/symfony/error-handler/Debug.php new file mode 100644 index 00000000..343a35a7 --- /dev/null +++ b/vendor/symfony/error-handler/Debug.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler; + +/** + * Registers all the debug tools. + * + * @author Fabien Potencier + */ +class Debug +{ + public static function enable(): ErrorHandler + { + error_reporting(-1); + + if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { + ini_set('display_errors', 0); + } elseif (!filter_var(\ini_get('log_errors'), \FILTER_VALIDATE_BOOLEAN) || \ini_get('error_log')) { + // CLI - display errors only if they're not already logged to STDERR + ini_set('display_errors', 1); + } + + @ini_set('zend.assertions', 1); + ini_set('assert.active', 1); + ini_set('assert.warning', 0); + ini_set('assert.exception', 1); + + DebugClassLoader::enable(); + + return ErrorHandler::register(new ErrorHandler(new BufferingLogger(), true)); + } +} diff --git a/vendor/symfony/error-handler/DebugClassLoader.php b/vendor/symfony/error-handler/DebugClassLoader.php new file mode 100644 index 00000000..ce05790b --- /dev/null +++ b/vendor/symfony/error-handler/DebugClassLoader.php @@ -0,0 +1,1097 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler; + +use Composer\InstalledVersions; +use Doctrine\Common\Persistence\Proxy as LegacyProxy; +use Doctrine\Persistence\Proxy; +use Mockery\MockInterface; +use Phake\IMock; +use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation; +use PHPUnit\Framework\MockObject\MockObject; +use Prophecy\Prophecy\ProphecySubjectInterface; +use ProxyManager\Proxy\ProxyInterface; + +/** + * Autoloader checking if the class is really defined in the file found. + * + * The ClassLoader will wrap all registered autoloaders + * and will throw an exception if a file is found but does + * not declare the class. + * + * It can also patch classes to turn docblocks into actual return types. + * This behavior is controlled by the SYMFONY_PATCH_TYPE_DECLARATIONS env var, + * which is a url-encoded array with the follow parameters: + * - "force": any value enables deprecation notices - can be any of: + * - "docblock" to patch only docblock annotations + * - "object" to turn union types to the "object" type when possible (not recommended) + * - "1" to add all possible return types including magic methods + * - "0" to add possible return types excluding magic methods + * - "php": the target version of PHP - e.g. "7.1" doesn't generate "object" types + * - "deprecations": "1" to trigger a deprecation notice when a child class misses a + * return type while the parent declares an "@return" annotation + * + * Note that patching doesn't care about any coding style so you'd better to run + * php-cs-fixer after, with rules "phpdoc_trim_consecutive_blank_line_separation" + * and "no_superfluous_phpdoc_tags" enabled typically. + * + * @author Fabien Potencier + * @author Christophe Coevoet + * @author Nicolas Grekas + * @author Guilhem Niot + */ +class DebugClassLoader +{ + private const SPECIAL_RETURN_TYPES = [ + 'void' => 'void', + 'null' => 'null', + 'resource' => 'resource', + 'boolean' => 'bool', + 'true' => 'bool', + 'false' => 'bool', + 'integer' => 'int', + 'array' => 'array', + 'bool' => 'bool', + 'callable' => 'callable', + 'float' => 'float', + 'int' => 'int', + 'iterable' => 'iterable', + 'object' => 'object', + 'string' => 'string', + 'self' => 'self', + 'parent' => 'parent', + 'mixed' => 'mixed', + 'list' => 'array', + 'class-string' => 'string', + ] + (\PHP_VERSION_ID >= 80000 ? [ + 'static' => 'static', + '$this' => 'static', + ] : [ + 'static' => 'object', + '$this' => 'object', + ]); + + private const BUILTIN_RETURN_TYPES = [ + 'void' => true, + 'array' => true, + 'bool' => true, + 'callable' => true, + 'float' => true, + 'int' => true, + 'iterable' => true, + 'object' => true, + 'string' => true, + 'self' => true, + 'parent' => true, + ] + (\PHP_VERSION_ID >= 80000 ? [ + 'mixed' => true, + 'static' => true, + ] : []); + + private const MAGIC_METHODS = [ + '__set' => 'void', + '__isset' => 'bool', + '__unset' => 'void', + '__sleep' => 'array', + '__wakeup' => 'void', + '__toString' => 'string', + '__clone' => 'void', + '__debugInfo' => 'array', + '__serialize' => 'array', + '__unserialize' => 'void', + ]; + + private const INTERNAL_TYPES = [ + 'ArrayAccess' => [ + 'offsetExists' => 'bool', + 'offsetSet' => 'void', + 'offsetUnset' => 'void', + ], + 'Countable' => [ + 'count' => 'int', + ], + 'Iterator' => [ + 'next' => 'void', + 'valid' => 'bool', + 'rewind' => 'void', + ], + 'IteratorAggregate' => [ + 'getIterator' => '\Traversable', + ], + 'OuterIterator' => [ + 'getInnerIterator' => '\Iterator', + ], + 'RecursiveIterator' => [ + 'hasChildren' => 'bool', + ], + 'SeekableIterator' => [ + 'seek' => 'void', + ], + 'Serializable' => [ + 'serialize' => 'string', + 'unserialize' => 'void', + ], + 'SessionHandlerInterface' => [ + 'open' => 'bool', + 'close' => 'bool', + 'read' => 'string', + 'write' => 'bool', + 'destroy' => 'bool', + 'gc' => 'bool', + ], + 'SessionIdInterface' => [ + 'create_sid' => 'string', + ], + 'SessionUpdateTimestampHandlerInterface' => [ + 'validateId' => 'bool', + 'updateTimestamp' => 'bool', + ], + 'Throwable' => [ + 'getMessage' => 'string', + 'getCode' => 'int', + 'getFile' => 'string', + 'getLine' => 'int', + 'getTrace' => 'array', + 'getPrevious' => '?\Throwable', + 'getTraceAsString' => 'string', + ], + ]; + + private $classLoader; + private $isFinder; + private $loaded = []; + private $patchTypes; + + private static $caseCheck; + private static $checkedClasses = []; + private static $final = []; + private static $finalMethods = []; + private static $deprecated = []; + private static $internal = []; + private static $internalMethods = []; + private static $annotatedParameters = []; + private static $darwinCache = ['/' => ['/', []]]; + private static $method = []; + private static $returnTypes = []; + private static $methodTraits = []; + private static $fileOffsets = []; + + public function __construct(callable $classLoader) + { + $this->classLoader = $classLoader; + $this->isFinder = \is_array($classLoader) && method_exists($classLoader[0], 'findFile'); + parse_str(getenv('SYMFONY_PATCH_TYPE_DECLARATIONS') ?: '', $this->patchTypes); + $this->patchTypes += [ + 'force' => null, + 'php' => null, + 'deprecations' => false, + ]; + + if (!isset(self::$caseCheck)) { + $file = file_exists(__FILE__) ? __FILE__ : rtrim(realpath('.'), \DIRECTORY_SEPARATOR); + $i = strrpos($file, \DIRECTORY_SEPARATOR); + $dir = substr($file, 0, 1 + $i); + $file = substr($file, 1 + $i); + $test = strtoupper($file) === $file ? strtolower($file) : strtoupper($file); + $test = realpath($dir.$test); + + if (false === $test || false === $i) { + // filesystem is case sensitive + self::$caseCheck = 0; + } elseif (substr($test, -\strlen($file)) === $file) { + // filesystem is case insensitive and realpath() normalizes the case of characters + self::$caseCheck = 1; + } elseif (false !== stripos(\PHP_OS, 'darwin')) { + // on MacOSX, HFS+ is case insensitive but realpath() doesn't normalize the case of characters + self::$caseCheck = 2; + } else { + // filesystem case checks failed, fallback to disabling them + self::$caseCheck = 0; + } + } + } + + /** + * Gets the wrapped class loader. + * + * @return callable The wrapped class loader + */ + public function getClassLoader(): callable + { + return $this->classLoader; + } + + /** + * Wraps all autoloaders. + */ + public static function enable(): void + { + // Ensures we don't hit https://bugs.php.net/42098 + class_exists(\Symfony\Component\ErrorHandler\ErrorHandler::class); + class_exists(\Psr\Log\LogLevel::class); + + if (!\is_array($functions = spl_autoload_functions())) { + return; + } + + foreach ($functions as $function) { + spl_autoload_unregister($function); + } + + foreach ($functions as $function) { + if (!\is_array($function) || !$function[0] instanceof self) { + $function = [new static($function), 'loadClass']; + } + + spl_autoload_register($function); + } + } + + /** + * Disables the wrapping. + */ + public static function disable(): void + { + if (!\is_array($functions = spl_autoload_functions())) { + return; + } + + foreach ($functions as $function) { + spl_autoload_unregister($function); + } + + foreach ($functions as $function) { + if (\is_array($function) && $function[0] instanceof self) { + $function = $function[0]->getClassLoader(); + } + + spl_autoload_register($function); + } + } + + public static function checkClasses(): bool + { + if (!\is_array($functions = spl_autoload_functions())) { + return false; + } + + $loader = null; + + foreach ($functions as $function) { + if (\is_array($function) && $function[0] instanceof self) { + $loader = $function[0]; + break; + } + } + + if (null === $loader) { + return false; + } + + static $offsets = [ + 'get_declared_interfaces' => 0, + 'get_declared_traits' => 0, + 'get_declared_classes' => 0, + ]; + + foreach ($offsets as $getSymbols => $i) { + $symbols = $getSymbols(); + + for (; $i < \count($symbols); ++$i) { + if (!is_subclass_of($symbols[$i], MockObject::class) + && !is_subclass_of($symbols[$i], ProphecySubjectInterface::class) + && !is_subclass_of($symbols[$i], Proxy::class) + && !is_subclass_of($symbols[$i], ProxyInterface::class) + && !is_subclass_of($symbols[$i], LegacyProxy::class) + && !is_subclass_of($symbols[$i], MockInterface::class) + && !is_subclass_of($symbols[$i], IMock::class) + ) { + $loader->checkClass($symbols[$i]); + } + } + + $offsets[$getSymbols] = $i; + } + + return true; + } + + public function findFile(string $class): ?string + { + return $this->isFinder ? ($this->classLoader[0]->findFile($class) ?: null) : null; + } + + /** + * Loads the given class or interface. + * + * @throws \RuntimeException + */ + public function loadClass(string $class): void + { + $e = error_reporting(error_reporting() | \E_PARSE | \E_ERROR | \E_CORE_ERROR | \E_COMPILE_ERROR); + + try { + if ($this->isFinder && !isset($this->loaded[$class])) { + $this->loaded[$class] = true; + if (!$file = $this->classLoader[0]->findFile($class) ?: '') { + // no-op + } elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) { + include $file; + + return; + } elseif (false === include $file) { + return; + } + } else { + ($this->classLoader)($class); + $file = ''; + } + } finally { + error_reporting($e); + } + + $this->checkClass($class, $file); + } + + private function checkClass(string $class, string $file = null): void + { + $exists = null === $file || class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); + + if (null !== $file && $class && '\\' === $class[0]) { + $class = substr($class, 1); + } + + if ($exists) { + if (isset(self::$checkedClasses[$class])) { + return; + } + self::$checkedClasses[$class] = true; + + $refl = new \ReflectionClass($class); + if (null === $file && $refl->isInternal()) { + return; + } + $name = $refl->getName(); + + if ($name !== $class && 0 === strcasecmp($name, $class)) { + throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: "%s" vs "%s".', $class, $name)); + } + + $deprecations = $this->checkAnnotations($refl, $name); + + foreach ($deprecations as $message) { + @trigger_error($message, \E_USER_DEPRECATED); + } + } + + if (!$file) { + return; + } + + if (!$exists) { + if (false !== strpos($class, '/')) { + throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class)); + } + + throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file)); + } + + if (self::$caseCheck && $message = $this->checkCase($refl, $file, $class)) { + throw new \RuntimeException(sprintf('Case mismatch between class and real file names: "%s" vs "%s" in "%s".', $message[0], $message[1], $message[2])); + } + } + + public function checkAnnotations(\ReflectionClass $refl, string $class): array + { + if ( + 'Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV7' === $class + || 'Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerForV6' === $class + || 'Test\Symfony\Component\Debug\Tests' === $refl->getNamespaceName() + ) { + return []; + } + $deprecations = []; + + $className = false !== strpos($class, "@anonymous\0") ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' : $class; + + // Don't trigger deprecations for classes in the same vendor + if ($class !== $className) { + $vendor = preg_match('/^namespace ([^;\\\\\s]++)[;\\\\]/m', @file_get_contents($refl->getFileName()), $vendor) ? $vendor[1].'\\' : ''; + $vendorLen = \strlen($vendor); + } elseif (2 > $vendorLen = 1 + (strpos($class, '\\') ?: strpos($class, '_'))) { + $vendorLen = 0; + $vendor = ''; + } else { + $vendor = str_replace('_', '\\', substr($class, 0, $vendorLen)); + } + + // Detect annotations on the class + if (false !== $doc = $refl->getDocComment()) { + foreach (['final', 'deprecated', 'internal'] as $annotation) { + if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) { + self::${$annotation}[$class] = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : ''; + } + } + + if ($refl->isInterface() && false !== strpos($doc, 'method') && preg_match_all('#\n \* @method\s+(static\s+)?+([\w\|&\[\]\\\]+\s+)?(\w+(?:\s*\([^\)]*\))?)+(.+?([[:punct:]]\s*)?)?(?=\r?\n \*(?: @|/$|\r?\n))#', $doc, $notice, \PREG_SET_ORDER)) { + foreach ($notice as $method) { + $static = '' !== $method[1] && !empty($method[2]); + $name = $method[3]; + $description = $method[4] ?? null; + if (false === strpos($name, '(')) { + $name .= '()'; + } + if (null !== $description) { + $description = trim($description); + if (!isset($method[5])) { + $description .= '.'; + } + } + self::$method[$class][] = [$class, $name, $static, $description]; + } + } + } + + $parent = get_parent_class($class) ?: null; + $parentAndOwnInterfaces = $this->getOwnInterfaces($class, $parent); + if ($parent) { + $parentAndOwnInterfaces[$parent] = $parent; + + if (!isset(self::$checkedClasses[$parent])) { + $this->checkClass($parent); + } + + if (isset(self::$final[$parent])) { + $deprecations[] = sprintf('The "%s" class is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $parent, self::$final[$parent], $className); + } + } + + // Detect if the parent is annotated + foreach ($parentAndOwnInterfaces + class_uses($class, false) as $use) { + if (!isset(self::$checkedClasses[$use])) { + $this->checkClass($use); + } + if (isset(self::$deprecated[$use]) && strncmp($vendor, str_replace('_', '\\', $use), $vendorLen) && !isset(self::$deprecated[$class])) { + $type = class_exists($class, false) ? 'class' : (interface_exists($class, false) ? 'interface' : 'trait'); + $verb = class_exists($use, false) || interface_exists($class, false) ? 'extends' : (interface_exists($use, false) ? 'implements' : 'uses'); + + $deprecations[] = sprintf('The "%s" %s %s "%s" that is deprecated%s.', $className, $type, $verb, $use, self::$deprecated[$use]); + } + if (isset(self::$internal[$use]) && strncmp($vendor, str_replace('_', '\\', $use), $vendorLen)) { + $deprecations[] = sprintf('The "%s" %s is considered internal%s. It may change without further notice. You should not use it from "%s".', $use, class_exists($use, false) ? 'class' : (interface_exists($use, false) ? 'interface' : 'trait'), self::$internal[$use], $className); + } + if (isset(self::$method[$use])) { + if ($refl->isAbstract()) { + if (isset(self::$method[$class])) { + self::$method[$class] = array_merge(self::$method[$class], self::$method[$use]); + } else { + self::$method[$class] = self::$method[$use]; + } + } elseif (!$refl->isInterface()) { + if (!strncmp($vendor, str_replace('_', '\\', $use), $vendorLen) + && 0 === strpos($className, 'Symfony\\') + && (!class_exists(InstalledVersions::class) + || 'symfony/symfony' !== InstalledVersions::getRootPackage()['name']) + ) { + // skip "same vendor" @method deprecations for Symfony\* classes unless symfony/symfony is being tested + continue; + } + $hasCall = $refl->hasMethod('__call'); + $hasStaticCall = $refl->hasMethod('__callStatic'); + foreach (self::$method[$use] as $method) { + [$interface, $name, $static, $description] = $method; + if ($static ? $hasStaticCall : $hasCall) { + continue; + } + $realName = substr($name, 0, strpos($name, '(')); + if (!$refl->hasMethod($realName) || !($methodRefl = $refl->getMethod($realName))->isPublic() || ($static && !$methodRefl->isStatic()) || (!$static && $methodRefl->isStatic())) { + $deprecations[] = sprintf('Class "%s" should implement method "%s::%s"%s', $className, ($static ? 'static ' : '').$interface, $name, null == $description ? '.' : ': '.$description); + } + } + } + } + } + + if (trait_exists($class)) { + $file = $refl->getFileName(); + + foreach ($refl->getMethods() as $method) { + if ($method->getFileName() === $file) { + self::$methodTraits[$file][$method->getStartLine()] = $class; + } + } + + return $deprecations; + } + + // Inherit @final, @internal, @param and @return annotations for methods + self::$finalMethods[$class] = []; + self::$internalMethods[$class] = []; + self::$annotatedParameters[$class] = []; + self::$returnTypes[$class] = []; + foreach ($parentAndOwnInterfaces as $use) { + foreach (['finalMethods', 'internalMethods', 'annotatedParameters', 'returnTypes'] as $property) { + if (isset(self::${$property}[$use])) { + self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use]; + } + } + + if (null !== (self::INTERNAL_TYPES[$use] ?? null)) { + foreach (self::INTERNAL_TYPES[$use] as $method => $returnType) { + if ('void' !== $returnType) { + self::$returnTypes[$class] += [$method => [$returnType, $returnType, $use, '']]; + } + } + } + } + + foreach ($refl->getMethods() as $method) { + if ($method->class !== $class) { + continue; + } + + if (null === $ns = self::$methodTraits[$method->getFileName()][$method->getStartLine()] ?? null) { + $ns = $vendor; + $len = $vendorLen; + } elseif (2 > $len = 1 + (strpos($ns, '\\') ?: strpos($ns, '_'))) { + $len = 0; + $ns = ''; + } else { + $ns = str_replace('_', '\\', substr($ns, 0, $len)); + } + + if ($parent && isset(self::$finalMethods[$parent][$method->name])) { + [$declaringClass, $message] = self::$finalMethods[$parent][$method->name]; + $deprecations[] = sprintf('The "%s::%s()" method is considered final%s. It may change without further notice as of its next major version. You should not extend it from "%s".', $declaringClass, $method->name, $message, $className); + } + + if (isset(self::$internalMethods[$class][$method->name])) { + [$declaringClass, $message] = self::$internalMethods[$class][$method->name]; + if (strncmp($ns, $declaringClass, $len)) { + $deprecations[] = sprintf('The "%s::%s()" method is considered internal%s. It may change without further notice. You should not extend it from "%s".', $declaringClass, $method->name, $message, $className); + } + } + + // To read method annotations + $doc = $method->getDocComment(); + + if (isset(self::$annotatedParameters[$class][$method->name])) { + $definedParameters = []; + foreach ($method->getParameters() as $parameter) { + $definedParameters[$parameter->name] = true; + } + + foreach (self::$annotatedParameters[$class][$method->name] as $parameterName => $deprecation) { + if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\\\${$parameterName}\\b/", $doc))) { + $deprecations[] = sprintf($deprecation, $className); + } + } + } + + $forcePatchTypes = $this->patchTypes['force']; + + if ($canAddReturnType = null !== $forcePatchTypes && false === strpos($method->getFileName(), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) { + if ('void' !== (self::MAGIC_METHODS[$method->name] ?? 'void')) { + $this->patchTypes['force'] = $forcePatchTypes ?: 'docblock'; + } + + $canAddReturnType = false !== strpos($refl->getFileName(), \DIRECTORY_SEPARATOR.'Tests'.\DIRECTORY_SEPARATOR) + || $refl->isFinal() + || $method->isFinal() + || $method->isPrivate() + || ('' === (self::$internal[$class] ?? null) && !$refl->isAbstract()) + || '' === (self::$final[$class] ?? null) + || preg_match('/@(final|internal)$/m', $doc) + ; + } + + if (null !== ($returnType = self::$returnTypes[$class][$method->name] ?? self::MAGIC_METHODS[$method->name] ?? null) && !$method->hasReturnType() && !($doc && preg_match('/\n\s+\* @return +([^\s<(]+)/', $doc))) { + [$normalizedType, $returnType, $declaringClass, $declaringFile] = \is_string($returnType) ? [$returnType, $returnType, '', ''] : $returnType; + + if ('void' === $normalizedType) { + $canAddReturnType = false; + } + + if ($canAddReturnType && 'docblock' !== $this->patchTypes['force']) { + $this->patchMethod($method, $returnType, $declaringFile, $normalizedType); + } + + if (false === strpos($doc, '* @deprecated') && strncmp($ns, $declaringClass, $len)) { + if ($canAddReturnType && 'docblock' === $this->patchTypes['force'] && false === strpos($method->getFileName(), \DIRECTORY_SEPARATOR.'vendor'.\DIRECTORY_SEPARATOR)) { + $this->patchMethod($method, $returnType, $declaringFile, $normalizedType); + } elseif ('' !== $declaringClass && $this->patchTypes['deprecations']) { + $deprecations[] = sprintf('Method "%s::%s()" will return "%s" as of its next major version. Doing the same in %s "%s" will be required when upgrading.', $declaringClass, $method->name, $normalizedType, interface_exists($declaringClass) ? 'implementation' : 'child class', $className); + } + } + } + + if (!$doc) { + $this->patchTypes['force'] = $forcePatchTypes; + + continue; + } + + $matches = []; + + if (!$method->hasReturnType() && ((false !== strpos($doc, '@return') && preg_match('/\n\s+\* @return +([^\s<(]+)/', $doc, $matches)) || 'void' !== (self::MAGIC_METHODS[$method->name] ?? 'void'))) { + $matches = $matches ?: [1 => self::MAGIC_METHODS[$method->name]]; + $this->setReturnType($matches[1], $method, $parent); + + if (isset(self::$returnTypes[$class][$method->name][0]) && $canAddReturnType) { + $this->fixReturnStatements($method, self::$returnTypes[$class][$method->name][0]); + } + + if ($method->isPrivate()) { + unset(self::$returnTypes[$class][$method->name]); + } + } + + $this->patchTypes['force'] = $forcePatchTypes; + + if ($method->isPrivate()) { + continue; + } + + $finalOrInternal = false; + + foreach (['final', 'internal'] as $annotation) { + if (false !== strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$|\r?\n)#s', $doc, $notice)) { + $message = isset($notice[1]) ? preg_replace('#\.?\r?\n( \*)? *(?= |\r?\n|$)#', '', $notice[1]) : ''; + self::${$annotation.'Methods'}[$class][$method->name] = [$class, $message]; + $finalOrInternal = true; + } + } + + if ($finalOrInternal || $method->isConstructor() || false === strpos($doc, '@param') || StatelessInvocation::class === $class) { + continue; + } + if (!preg_match_all('#\n\s+\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\$([a-zA-Z0-9_\x7f-\xff]++)#', $doc, $matches, \PREG_SET_ORDER)) { + continue; + } + if (!isset(self::$annotatedParameters[$class][$method->name])) { + $definedParameters = []; + foreach ($method->getParameters() as $parameter) { + $definedParameters[$parameter->name] = true; + } + } + foreach ($matches as [, $parameterType, $parameterName]) { + if (!isset($definedParameters[$parameterName])) { + $parameterType = trim($parameterType); + self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its %s "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, interface_exists($className) ? 'interface' : 'parent class', $className); + } + } + } + + return $deprecations; + } + + public function checkCase(\ReflectionClass $refl, string $file, string $class): ?array + { + $real = explode('\\', $class.strrchr($file, '.')); + $tail = explode(\DIRECTORY_SEPARATOR, str_replace('/', \DIRECTORY_SEPARATOR, $file)); + + $i = \count($tail) - 1; + $j = \count($real) - 1; + + while (isset($tail[$i], $real[$j]) && $tail[$i] === $real[$j]) { + --$i; + --$j; + } + + array_splice($tail, 0, $i + 1); + + if (!$tail) { + return null; + } + + $tail = \DIRECTORY_SEPARATOR.implode(\DIRECTORY_SEPARATOR, $tail); + $tailLen = \strlen($tail); + $real = $refl->getFileName(); + + if (2 === self::$caseCheck) { + $real = $this->darwinRealpath($real); + } + + if (0 === substr_compare($real, $tail, -$tailLen, $tailLen, true) + && 0 !== substr_compare($real, $tail, -$tailLen, $tailLen, false) + ) { + return [substr($tail, -$tailLen + 1), substr($real, -$tailLen + 1), substr($real, 0, -$tailLen + 1)]; + } + + return null; + } + + /** + * `realpath` on MacOSX doesn't normalize the case of characters. + */ + private function darwinRealpath(string $real): string + { + $i = 1 + strrpos($real, '/'); + $file = substr($real, $i); + $real = substr($real, 0, $i); + + if (isset(self::$darwinCache[$real])) { + $kDir = $real; + } else { + $kDir = strtolower($real); + + if (isset(self::$darwinCache[$kDir])) { + $real = self::$darwinCache[$kDir][0]; + } else { + $dir = getcwd(); + + if (!@chdir($real)) { + return $real.$file; + } + + $real = getcwd().'/'; + chdir($dir); + + $dir = $real; + $k = $kDir; + $i = \strlen($dir) - 1; + while (!isset(self::$darwinCache[$k])) { + self::$darwinCache[$k] = [$dir, []]; + self::$darwinCache[$dir] = &self::$darwinCache[$k]; + + while ('/' !== $dir[--$i]) { + } + $k = substr($k, 0, ++$i); + $dir = substr($dir, 0, $i--); + } + } + } + + $dirFiles = self::$darwinCache[$kDir][1]; + + if (!isset($dirFiles[$file]) && ') : eval()\'d code' === substr($file, -17)) { + // Get the file name from "file_name.php(123) : eval()'d code" + $file = substr($file, 0, strrpos($file, '(', -17)); + } + + if (isset($dirFiles[$file])) { + return $real .= $dirFiles[$file]; + } + + $kFile = strtolower($file); + + if (!isset($dirFiles[$kFile])) { + foreach (scandir($real, 2) as $f) { + if ('.' !== $f[0]) { + $dirFiles[$f] = $f; + if ($f === $file) { + $kFile = $k = $file; + } elseif ($f !== $k = strtolower($f)) { + $dirFiles[$k] = $f; + } + } + } + self::$darwinCache[$kDir][1] = $dirFiles; + } + + return $real .= $dirFiles[$kFile]; + } + + /** + * `class_implements` includes interfaces from the parents so we have to manually exclude them. + * + * @return string[] + */ + private function getOwnInterfaces(string $class, ?string $parent): array + { + $ownInterfaces = class_implements($class, false); + + if ($parent) { + foreach (class_implements($parent, false) as $interface) { + unset($ownInterfaces[$interface]); + } + } + + foreach ($ownInterfaces as $interface) { + foreach (class_implements($interface) as $interface) { + unset($ownInterfaces[$interface]); + } + } + + return $ownInterfaces; + } + + private function setReturnType(string $types, \ReflectionMethod $method, ?string $parent): void + { + $nullable = false; + $typesMap = []; + foreach (explode('|', $types) as $t) { + $typesMap[$this->normalizeType($t, $method->class, $parent)] = $t; + } + + if (isset($typesMap['array'])) { + if (isset($typesMap['Traversable']) || isset($typesMap['\Traversable'])) { + $typesMap['iterable'] = 'array' !== $typesMap['array'] ? $typesMap['array'] : 'iterable'; + unset($typesMap['array'], $typesMap['Traversable'], $typesMap['\Traversable']); + } elseif ('array' !== $typesMap['array'] && isset(self::$returnTypes[$method->class][$method->name])) { + return; + } + } + + if (isset($typesMap['array']) && isset($typesMap['iterable'])) { + if ('[]' === substr($typesMap['array'], -2)) { + $typesMap['iterable'] = $typesMap['array']; + } + unset($typesMap['array']); + } + + $iterable = $object = true; + foreach ($typesMap as $n => $t) { + if ('null' !== $n) { + $iterable = $iterable && (\in_array($n, ['array', 'iterable']) || false !== strpos($n, 'Iterator')); + $object = $object && (\in_array($n, ['callable', 'object', '$this', 'static']) || !isset(self::SPECIAL_RETURN_TYPES[$n])); + } + } + + $normalizedType = key($typesMap); + $returnType = current($typesMap); + + foreach ($typesMap as $n => $t) { + if ('null' === $n) { + $nullable = true; + } elseif ('null' === $normalizedType) { + $normalizedType = $t; + $returnType = $t; + } elseif ($n !== $normalizedType || !preg_match('/^\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)*+$/', $n)) { + if ($iterable) { + $normalizedType = $returnType = 'iterable'; + } elseif ($object && 'object' === $this->patchTypes['force']) { + $normalizedType = $returnType = 'object'; + } else { + // ignore multi-types return declarations + return; + } + } + } + + if ('void' === $normalizedType || (\PHP_VERSION_ID >= 80000 && 'mixed' === $normalizedType)) { + $nullable = false; + } elseif (!isset(self::BUILTIN_RETURN_TYPES[$normalizedType]) && isset(self::SPECIAL_RETURN_TYPES[$normalizedType])) { + // ignore other special return types + return; + } + + if ($nullable) { + $normalizedType = '?'.$normalizedType; + $returnType .= '|null'; + } + + self::$returnTypes[$method->class][$method->name] = [$normalizedType, $returnType, $method->class, $method->getFileName()]; + } + + private function normalizeType(string $type, string $class, ?string $parent): string + { + if (isset(self::SPECIAL_RETURN_TYPES[$lcType = strtolower($type)])) { + if ('parent' === $lcType = self::SPECIAL_RETURN_TYPES[$lcType]) { + $lcType = null !== $parent ? '\\'.$parent : 'parent'; + } elseif ('self' === $lcType) { + $lcType = '\\'.$class; + } + + return $lcType; + } + + if ('[]' === substr($type, -2)) { + return 'array'; + } + + if (preg_match('/^(array|iterable|callable) *[<(]/', $lcType, $m)) { + return $m[1]; + } + + // We could resolve "use" statements to return the FQDN + // but this would be too expensive for a runtime checker + + return $type; + } + + /** + * Utility method to add @return annotations to the Symfony code-base where it triggers a self-deprecations. + */ + private function patchMethod(\ReflectionMethod $method, string $returnType, string $declaringFile, string $normalizedType) + { + static $patchedMethods = []; + static $useStatements = []; + + if (!file_exists($file = $method->getFileName()) || isset($patchedMethods[$file][$startLine = $method->getStartLine()])) { + return; + } + + $patchedMethods[$file][$startLine] = true; + $fileOffset = self::$fileOffsets[$file] ?? 0; + $startLine += $fileOffset - 2; + $nullable = '?' === $normalizedType[0] ? '?' : ''; + $normalizedType = ltrim($normalizedType, '?'); + $returnType = explode('|', $returnType); + $code = file($file); + + foreach ($returnType as $i => $type) { + if (preg_match('/((?:\[\])+)$/', $type, $m)) { + $type = substr($type, 0, -\strlen($m[1])); + $format = '%s'.$m[1]; + } elseif (preg_match('/^(array|iterable)<([^,>]++)>$/', $type, $m)) { + $type = $m[2]; + $format = $m[1].'<%s>'; + } else { + $format = null; + } + + if (isset(self::SPECIAL_RETURN_TYPES[$type]) || ('\\' === $type[0] && !$p = strrpos($type, '\\', 1))) { + continue; + } + + [$namespace, $useOffset, $useMap] = $useStatements[$file] ?? $useStatements[$file] = self::getUseStatements($file); + + if ('\\' !== $type[0]) { + [$declaringNamespace, , $declaringUseMap] = $useStatements[$declaringFile] ?? $useStatements[$declaringFile] = self::getUseStatements($declaringFile); + + $p = strpos($type, '\\', 1); + $alias = $p ? substr($type, 0, $p) : $type; + + if (isset($declaringUseMap[$alias])) { + $type = '\\'.$declaringUseMap[$alias].($p ? substr($type, $p) : ''); + } else { + $type = '\\'.$declaringNamespace.$type; + } + + $p = strrpos($type, '\\', 1); + } + + $alias = substr($type, 1 + $p); + $type = substr($type, 1); + + if (!isset($useMap[$alias]) && (class_exists($c = $namespace.$alias) || interface_exists($c) || trait_exists($c))) { + $useMap[$alias] = $c; + } + + if (!isset($useMap[$alias])) { + $useStatements[$file][2][$alias] = $type; + $code[$useOffset] = "use $type;\n".$code[$useOffset]; + ++$fileOffset; + } elseif ($useMap[$alias] !== $type) { + $alias .= 'FIXME'; + $useStatements[$file][2][$alias] = $type; + $code[$useOffset] = "use $type as $alias;\n".$code[$useOffset]; + ++$fileOffset; + } + + $returnType[$i] = null !== $format ? sprintf($format, $alias) : $alias; + + if (!isset(self::SPECIAL_RETURN_TYPES[$normalizedType]) && !isset(self::SPECIAL_RETURN_TYPES[$returnType[$i]])) { + $normalizedType = $returnType[$i]; + } + } + + if ('docblock' === $this->patchTypes['force'] || ('object' === $normalizedType && '7.1' === $this->patchTypes['php'])) { + $returnType = implode('|', $returnType); + + if ($method->getDocComment()) { + $code[$startLine] = " * @return $returnType\n".$code[$startLine]; + } else { + $code[$startLine] .= <<fixReturnStatements($method, $nullable.$normalizedType); + } + + private static function getUseStatements(string $file): array + { + $namespace = ''; + $useMap = []; + $useOffset = 0; + + if (!file_exists($file)) { + return [$namespace, $useOffset, $useMap]; + } + + $file = file($file); + + for ($i = 0; $i < \count($file); ++$i) { + if (preg_match('/^(class|interface|trait|abstract) /', $file[$i])) { + break; + } + + if (0 === strpos($file[$i], 'namespace ')) { + $namespace = substr($file[$i], \strlen('namespace '), -2).'\\'; + $useOffset = $i + 2; + } + + if (0 === strpos($file[$i], 'use ')) { + $useOffset = $i; + + for (; 0 === strpos($file[$i], 'use '); ++$i) { + $u = explode(' as ', substr($file[$i], 4, -2), 2); + + if (1 === \count($u)) { + $p = strrpos($u[0], '\\'); + $useMap[substr($u[0], false !== $p ? 1 + $p : 0)] = $u[0]; + } else { + $useMap[$u[1]] = $u[0]; + } + } + + break; + } + } + + return [$namespace, $useOffset, $useMap]; + } + + private function fixReturnStatements(\ReflectionMethod $method, string $returnType) + { + if ('7.1' === $this->patchTypes['php'] && 'object' === ltrim($returnType, '?') && 'docblock' !== $this->patchTypes['force']) { + return; + } + + if (!file_exists($file = $method->getFileName())) { + return; + } + + $fixedCode = $code = file($file); + $i = (self::$fileOffsets[$file] ?? 0) + $method->getStartLine(); + + if ('?' !== $returnType && 'docblock' !== $this->patchTypes['force']) { + $fixedCode[$i - 1] = preg_replace('/\)(;?\n)/', "): $returnType\\1", $code[$i - 1]); + } + + $end = $method->isGenerator() ? $i : $method->getEndLine(); + for (; $i < $end; ++$i) { + if ('void' === $returnType) { + $fixedCode[$i] = str_replace(' return null;', ' return;', $code[$i]); + } elseif ('mixed' === $returnType || '?' === $returnType[0]) { + $fixedCode[$i] = str_replace(' return;', ' return null;', $code[$i]); + } else { + $fixedCode[$i] = str_replace(' return;', " return $returnType!?;", $code[$i]); + } + } + + if ($fixedCode !== $code) { + file_put_contents($file, $fixedCode); + } + } +} diff --git a/vendor/symfony/error-handler/Error/ClassNotFoundError.php b/vendor/symfony/error-handler/Error/ClassNotFoundError.php new file mode 100644 index 00000000..443fba2c --- /dev/null +++ b/vendor/symfony/error-handler/Error/ClassNotFoundError.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class ClassNotFoundError extends \Error +{ + /** + * {@inheritdoc} + */ + public function __construct(string $message, \Throwable $previous) + { + parent::__construct($message, $previous->getCode(), $previous->getPrevious()); + + foreach ([ + 'file' => $previous->getFile(), + 'line' => $previous->getLine(), + 'trace' => $previous->getTrace(), + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } +} diff --git a/vendor/symfony/error-handler/Error/FatalError.php b/vendor/symfony/error-handler/Error/FatalError.php new file mode 100644 index 00000000..57fc690e --- /dev/null +++ b/vendor/symfony/error-handler/Error/FatalError.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class FatalError extends \Error +{ + private $error; + + /** + * {@inheritdoc} + * + * @param array $error An array as returned by error_get_last() + */ + public function __construct(string $message, int $code, array $error, int $traceOffset = null, bool $traceArgs = true, array $trace = null) + { + parent::__construct($message, $code); + + $this->error = $error; + + if (null !== $trace) { + if (!$traceArgs) { + foreach ($trace as &$frame) { + unset($frame['args'], $frame['this'], $frame); + } + } + } elseif (null !== $traceOffset) { + if (\function_exists('xdebug_get_function_stack') && $trace = @xdebug_get_function_stack()) { + if (0 < $traceOffset) { + array_splice($trace, -$traceOffset); + } + + foreach ($trace as &$frame) { + if (!isset($frame['type'])) { + // XDebug pre 2.1.1 doesn't currently set the call type key http://bugs.xdebug.org/view.php?id=695 + if (isset($frame['class'])) { + $frame['type'] = '::'; + } + } elseif ('dynamic' === $frame['type']) { + $frame['type'] = '->'; + } elseif ('static' === $frame['type']) { + $frame['type'] = '::'; + } + + // XDebug also has a different name for the parameters array + if (!$traceArgs) { + unset($frame['params'], $frame['args']); + } elseif (isset($frame['params']) && !isset($frame['args'])) { + $frame['args'] = $frame['params']; + unset($frame['params']); + } + } + + unset($frame); + $trace = array_reverse($trace); + } else { + $trace = []; + } + } + + foreach ([ + 'file' => $error['file'], + 'line' => $error['line'], + 'trace' => $trace, + ] as $property => $value) { + if (null !== $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } + } + + /** + * {@inheritdoc} + */ + public function getError(): array + { + return $this->error; + } +} diff --git a/vendor/symfony/error-handler/Error/OutOfMemoryError.php b/vendor/symfony/error-handler/Error/OutOfMemoryError.php new file mode 100644 index 00000000..d685c3d3 --- /dev/null +++ b/vendor/symfony/error-handler/Error/OutOfMemoryError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class OutOfMemoryError extends FatalError +{ +} diff --git a/vendor/symfony/error-handler/Error/UndefinedFunctionError.php b/vendor/symfony/error-handler/Error/UndefinedFunctionError.php new file mode 100644 index 00000000..b57dd157 --- /dev/null +++ b/vendor/symfony/error-handler/Error/UndefinedFunctionError.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class UndefinedFunctionError extends \Error +{ + /** + * {@inheritdoc} + */ + public function __construct(string $message, \Throwable $previous) + { + parent::__construct($message, $previous->getCode(), $previous->getPrevious()); + + foreach ([ + 'file' => $previous->getFile(), + 'line' => $previous->getLine(), + 'trace' => $previous->getTrace(), + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } +} diff --git a/vendor/symfony/error-handler/Error/UndefinedMethodError.php b/vendor/symfony/error-handler/Error/UndefinedMethodError.php new file mode 100644 index 00000000..adc8731f --- /dev/null +++ b/vendor/symfony/error-handler/Error/UndefinedMethodError.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Error; + +class UndefinedMethodError extends \Error +{ + /** + * {@inheritdoc} + */ + public function __construct(string $message, \Throwable $previous) + { + parent::__construct($message, $previous->getCode(), $previous->getPrevious()); + + foreach ([ + 'file' => $previous->getFile(), + 'line' => $previous->getLine(), + 'trace' => $previous->getTrace(), + ] as $property => $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } + } +} diff --git a/vendor/symfony/error-handler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php b/vendor/symfony/error-handler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php new file mode 100644 index 00000000..96a58be8 --- /dev/null +++ b/vendor/symfony/error-handler/ErrorEnhancer/ClassNotFoundErrorEnhancer.php @@ -0,0 +1,179 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; + +use Composer\Autoload\ClassLoader as ComposerClassLoader; +use Symfony\Component\ClassLoader\ClassLoader as SymfonyClassLoader; +use Symfony\Component\ErrorHandler\DebugClassLoader; +use Symfony\Component\ErrorHandler\Error\ClassNotFoundError; +use Symfony\Component\ErrorHandler\Error\FatalError; + +/** + * @author Fabien Potencier + */ +class ClassNotFoundErrorEnhancer implements ErrorEnhancerInterface +{ + /** + * {@inheritdoc} + */ + public function enhance(\Throwable $error): ?\Throwable + { + // Some specific versions of PHP produce a fatal error when extending a not found class. + $message = !$error instanceof FatalError ? $error->getMessage() : $error->getError()['message']; + if (!preg_match('/^(Class|Interface|Trait) [\'"]([^\'"]+)[\'"] not found$/', $message, $matches)) { + return null; + } + $typeName = strtolower($matches[1]); + $fullyQualifiedClassName = $matches[2]; + + if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedClassName, '\\')) { + $className = substr($fullyQualifiedClassName, $namespaceSeparatorIndex + 1); + $namespacePrefix = substr($fullyQualifiedClassName, 0, $namespaceSeparatorIndex); + $message = sprintf('Attempted to load %s "%s" from namespace "%s".', $typeName, $className, $namespacePrefix); + $tail = ' for another namespace?'; + } else { + $className = $fullyQualifiedClassName; + $message = sprintf('Attempted to load %s "%s" from the global namespace.', $typeName, $className); + $tail = '?'; + } + + if ($candidates = $this->getClassCandidates($className)) { + $tail = array_pop($candidates).'"?'; + if ($candidates) { + $tail = ' for e.g. "'.implode('", "', $candidates).'" or "'.$tail; + } else { + $tail = ' for "'.$tail; + } + } + $message .= "\nDid you forget a \"use\" statement".$tail; + + return new ClassNotFoundError($message, $error); + } + + /** + * Tries to guess the full namespace for a given class name. + * + * By default, it looks for PSR-0 and PSR-4 classes registered via a Symfony or a Composer + * autoloader (that should cover all common cases). + * + * @param string $class A class name (without its namespace) + * + * Returns an array of possible fully qualified class names + */ + private function getClassCandidates(string $class): array + { + if (!\is_array($functions = spl_autoload_functions())) { + return []; + } + + // find Symfony and Composer autoloaders + $classes = []; + + foreach ($functions as $function) { + if (!\is_array($function)) { + continue; + } + // get class loaders wrapped by DebugClassLoader + if ($function[0] instanceof DebugClassLoader) { + $function = $function[0]->getClassLoader(); + + if (!\is_array($function)) { + continue; + } + } + + if ($function[0] instanceof ComposerClassLoader || $function[0] instanceof SymfonyClassLoader) { + foreach ($function[0]->getPrefixes() as $prefix => $paths) { + foreach ($paths as $path) { + $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix)); + } + } + } + if ($function[0] instanceof ComposerClassLoader) { + foreach ($function[0]->getPrefixesPsr4() as $prefix => $paths) { + foreach ($paths as $path) { + $classes = array_merge($classes, $this->findClassInPath($path, $class, $prefix)); + } + } + } + } + + return array_unique($classes); + } + + private function findClassInPath(string $path, string $class, string $prefix): array + { + if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) { + return []; + } + + $classes = []; + $filename = $class.'.php'; + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { + if ($filename == $file->getFileName() && $class = $this->convertFileToClass($path, $file->getPathName(), $prefix)) { + $classes[] = $class; + } + } + + return $classes; + } + + private function convertFileToClass(string $path, string $file, string $prefix): ?string + { + $candidates = [ + // namespaced class + $namespacedClass = str_replace([$path.\DIRECTORY_SEPARATOR, '.php', '/'], ['', '', '\\'], $file), + // namespaced class (with target dir) + $prefix.$namespacedClass, + // namespaced class (with target dir and separator) + $prefix.'\\'.$namespacedClass, + // PEAR class + str_replace('\\', '_', $namespacedClass), + // PEAR class (with target dir) + str_replace('\\', '_', $prefix.$namespacedClass), + // PEAR class (with target dir and separator) + str_replace('\\', '_', $prefix.'\\'.$namespacedClass), + ]; + + if ($prefix) { + $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); }); + } + + // We cannot use the autoloader here as most of them use require; but if the class + // is not found, the new autoloader call will require the file again leading to a + // "cannot redeclare class" error. + foreach ($candidates as $candidate) { + if ($this->classExists($candidate)) { + return $candidate; + } + } + + try { + require_once $file; + } catch (\Throwable $e) { + return null; + } + + foreach ($candidates as $candidate) { + if ($this->classExists($candidate)) { + return $candidate; + } + } + + return null; + } + + private function classExists(string $class): bool + { + return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); + } +} diff --git a/vendor/symfony/error-handler/ErrorEnhancer/ErrorEnhancerInterface.php b/vendor/symfony/error-handler/ErrorEnhancer/ErrorEnhancerInterface.php new file mode 100644 index 00000000..7c3f4ef9 --- /dev/null +++ b/vendor/symfony/error-handler/ErrorEnhancer/ErrorEnhancerInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; + +interface ErrorEnhancerInterface +{ + /** + * Returns an \Throwable instance if the class is able to improve the error, null otherwise. + */ + public function enhance(\Throwable $error): ?\Throwable; +} diff --git a/vendor/symfony/error-handler/ErrorEnhancer/UndefinedFunctionErrorEnhancer.php b/vendor/symfony/error-handler/ErrorEnhancer/UndefinedFunctionErrorEnhancer.php new file mode 100644 index 00000000..f4c49c28 --- /dev/null +++ b/vendor/symfony/error-handler/ErrorEnhancer/UndefinedFunctionErrorEnhancer.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; + +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\Error\UndefinedFunctionError; + +/** + * @author Fabien Potencier + */ +class UndefinedFunctionErrorEnhancer implements ErrorEnhancerInterface +{ + /** + * {@inheritdoc} + */ + public function enhance(\Throwable $error): ?\Throwable + { + if ($error instanceof FatalError) { + return null; + } + + $message = $error->getMessage(); + $messageLen = \strlen($message); + $notFoundSuffix = '()'; + $notFoundSuffixLen = \strlen($notFoundSuffix); + if ($notFoundSuffixLen > $messageLen) { + return null; + } + + if (0 !== substr_compare($message, $notFoundSuffix, -$notFoundSuffixLen)) { + return null; + } + + $prefix = 'Call to undefined function '; + $prefixLen = \strlen($prefix); + if (0 !== strpos($message, $prefix)) { + return null; + } + + $fullyQualifiedFunctionName = substr($message, $prefixLen, -$notFoundSuffixLen); + if (false !== $namespaceSeparatorIndex = strrpos($fullyQualifiedFunctionName, '\\')) { + $functionName = substr($fullyQualifiedFunctionName, $namespaceSeparatorIndex + 1); + $namespacePrefix = substr($fullyQualifiedFunctionName, 0, $namespaceSeparatorIndex); + $message = sprintf('Attempted to call function "%s" from namespace "%s".', $functionName, $namespacePrefix); + } else { + $functionName = $fullyQualifiedFunctionName; + $message = sprintf('Attempted to call function "%s" from the global namespace.', $functionName); + } + + $candidates = []; + foreach (get_defined_functions() as $type => $definedFunctionNames) { + foreach ($definedFunctionNames as $definedFunctionName) { + if (false !== $namespaceSeparatorIndex = strrpos($definedFunctionName, '\\')) { + $definedFunctionNameBasename = substr($definedFunctionName, $namespaceSeparatorIndex + 1); + } else { + $definedFunctionNameBasename = $definedFunctionName; + } + + if ($definedFunctionNameBasename === $functionName) { + $candidates[] = '\\'.$definedFunctionName; + } + } + } + + if ($candidates) { + sort($candidates); + $last = array_pop($candidates).'"?'; + if ($candidates) { + $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last; + } else { + $candidates = '"'.$last; + } + $message .= "\nDid you mean to call ".$candidates; + } + + return new UndefinedFunctionError($message, $error); + } +} diff --git a/vendor/symfony/error-handler/ErrorEnhancer/UndefinedMethodErrorEnhancer.php b/vendor/symfony/error-handler/ErrorEnhancer/UndefinedMethodErrorEnhancer.php new file mode 100644 index 00000000..c4355f92 --- /dev/null +++ b/vendor/symfony/error-handler/ErrorEnhancer/UndefinedMethodErrorEnhancer.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorEnhancer; + +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\Error\UndefinedMethodError; + +/** + * @author Grégoire Pineau + */ +class UndefinedMethodErrorEnhancer implements ErrorEnhancerInterface +{ + /** + * {@inheritdoc} + */ + public function enhance(\Throwable $error): ?\Throwable + { + if ($error instanceof FatalError) { + return null; + } + + $message = $error->getMessage(); + preg_match('/^Call to undefined method (.*)::(.*)\(\)$/', $message, $matches); + if (!$matches) { + return null; + } + + $className = $matches[1]; + $methodName = $matches[2]; + + $message = sprintf('Attempted to call an undefined method named "%s" of class "%s".', $methodName, $className); + + if ('' === $methodName || !class_exists($className) || null === $methods = get_class_methods($className)) { + // failed to get the class or its methods on which an unknown method was called (for example on an anonymous class) + return new UndefinedMethodError($message, $error); + } + + $candidates = []; + foreach ($methods as $definedMethodName) { + $lev = levenshtein($methodName, $definedMethodName); + if ($lev <= \strlen($methodName) / 3 || false !== strpos($definedMethodName, $methodName)) { + $candidates[] = $definedMethodName; + } + } + + if ($candidates) { + sort($candidates); + $last = array_pop($candidates).'"?'; + if ($candidates) { + $candidates = 'e.g. "'.implode('", "', $candidates).'" or "'.$last; + } else { + $candidates = '"'.$last; + } + + $message .= "\nDid you mean to call ".$candidates; + } + + return new UndefinedMethodError($message, $error); + } +} diff --git a/vendor/symfony/error-handler/ErrorHandler.php b/vendor/symfony/error-handler/ErrorHandler.php new file mode 100644 index 00000000..fba6f8cf --- /dev/null +++ b/vendor/symfony/error-handler/ErrorHandler.php @@ -0,0 +1,779 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler; + +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Symfony\Component\ErrorHandler\Error\FatalError; +use Symfony\Component\ErrorHandler\Error\OutOfMemoryError; +use Symfony\Component\ErrorHandler\ErrorEnhancer\ClassNotFoundErrorEnhancer; +use Symfony\Component\ErrorHandler\ErrorEnhancer\ErrorEnhancerInterface; +use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedFunctionErrorEnhancer; +use Symfony\Component\ErrorHandler\ErrorEnhancer\UndefinedMethodErrorEnhancer; +use Symfony\Component\ErrorHandler\ErrorRenderer\CliErrorRenderer; +use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer; +use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; + +/** + * A generic ErrorHandler for the PHP engine. + * + * Provides five bit fields that control how errors are handled: + * - thrownErrors: errors thrown as \ErrorException + * - loggedErrors: logged errors, when not @-silenced + * - scopedErrors: errors thrown or logged with their local context + * - tracedErrors: errors logged with their stack trace + * - screamedErrors: never @-silenced errors + * + * Each error level can be logged by a dedicated PSR-3 logger object. + * Screaming only applies to logging. + * Throwing takes precedence over logging. + * Uncaught exceptions are logged as E_ERROR. + * E_DEPRECATED and E_USER_DEPRECATED levels never throw. + * E_RECOVERABLE_ERROR and E_USER_ERROR levels always throw. + * Non catchable errors that can be detected at shutdown time are logged when the scream bit field allows so. + * As errors have a performance cost, repeated errors are all logged, so that the developer + * can see them and weight them as more important to fix than others of the same level. + * + * @author Nicolas Grekas + * @author Grégoire Pineau + * + * @final + */ +class ErrorHandler +{ + private $levels = [ + \E_DEPRECATED => 'Deprecated', + \E_USER_DEPRECATED => 'User Deprecated', + \E_NOTICE => 'Notice', + \E_USER_NOTICE => 'User Notice', + \E_STRICT => 'Runtime Notice', + \E_WARNING => 'Warning', + \E_USER_WARNING => 'User Warning', + \E_COMPILE_WARNING => 'Compile Warning', + \E_CORE_WARNING => 'Core Warning', + \E_USER_ERROR => 'User Error', + \E_RECOVERABLE_ERROR => 'Catchable Fatal Error', + \E_COMPILE_ERROR => 'Compile Error', + \E_PARSE => 'Parse Error', + \E_ERROR => 'Error', + \E_CORE_ERROR => 'Core Error', + ]; + + private $loggers = [ + \E_DEPRECATED => [null, LogLevel::INFO], + \E_USER_DEPRECATED => [null, LogLevel::INFO], + \E_NOTICE => [null, LogLevel::WARNING], + \E_USER_NOTICE => [null, LogLevel::WARNING], + \E_STRICT => [null, LogLevel::WARNING], + \E_WARNING => [null, LogLevel::WARNING], + \E_USER_WARNING => [null, LogLevel::WARNING], + \E_COMPILE_WARNING => [null, LogLevel::WARNING], + \E_CORE_WARNING => [null, LogLevel::WARNING], + \E_USER_ERROR => [null, LogLevel::CRITICAL], + \E_RECOVERABLE_ERROR => [null, LogLevel::CRITICAL], + \E_COMPILE_ERROR => [null, LogLevel::CRITICAL], + \E_PARSE => [null, LogLevel::CRITICAL], + \E_ERROR => [null, LogLevel::CRITICAL], + \E_CORE_ERROR => [null, LogLevel::CRITICAL], + ]; + + private $thrownErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED + private $scopedErrors = 0x1FFF; // E_ALL - E_DEPRECATED - E_USER_DEPRECATED + private $tracedErrors = 0x77FB; // E_ALL - E_STRICT - E_PARSE + private $screamedErrors = 0x55; // E_ERROR + E_CORE_ERROR + E_COMPILE_ERROR + E_PARSE + private $loggedErrors = 0; + private $traceReflector; + private $debug; + + private $isRecursive = 0; + private $isRoot = false; + private $exceptionHandler; + private $bootstrappingLogger; + + private static $reservedMemory; + private static $toStringException; + private static $silencedErrorCache = []; + private static $silencedErrorCount = 0; + private static $exitCode = 0; + + /** + * Registers the error handler. + */ + public static function register(self $handler = null, bool $replace = true): self + { + if (null === self::$reservedMemory) { + self::$reservedMemory = str_repeat('x', 32768); + register_shutdown_function(__CLASS__.'::handleFatalError'); + } + + if ($handlerIsNew = null === $handler) { + $handler = new static(); + } + + if (null === $prev = set_error_handler([$handler, 'handleError'])) { + restore_error_handler(); + // Specifying the error types earlier would expose us to https://bugs.php.net/63206 + set_error_handler([$handler, 'handleError'], $handler->thrownErrors | $handler->loggedErrors); + $handler->isRoot = true; + } + + if ($handlerIsNew && \is_array($prev) && $prev[0] instanceof self) { + $handler = $prev[0]; + $replace = false; + } + if (!$replace && $prev) { + restore_error_handler(); + $handlerIsRegistered = \is_array($prev) && $handler === $prev[0]; + } else { + $handlerIsRegistered = true; + } + if (\is_array($prev = set_exception_handler([$handler, 'handleException'])) && $prev[0] instanceof self) { + restore_exception_handler(); + if (!$handlerIsRegistered) { + $handler = $prev[0]; + } elseif ($handler !== $prev[0] && $replace) { + set_exception_handler([$handler, 'handleException']); + $p = $prev[0]->setExceptionHandler(null); + $handler->setExceptionHandler($p); + $prev[0]->setExceptionHandler($p); + } + } else { + $handler->setExceptionHandler($prev ?? [$handler, 'renderException']); + } + + $handler->throwAt(\E_ALL & $handler->thrownErrors, true); + + return $handler; + } + + /** + * Calls a function and turns any PHP error into \ErrorException. + * + * @return mixed What $function(...$arguments) returns + * + * @throws \ErrorException When $function(...$arguments) triggers a PHP error + */ + public static function call(callable $function, ...$arguments) + { + set_error_handler(static function (int $type, string $message, string $file, int $line) { + if (__FILE__ === $file) { + $trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3); + $file = $trace[2]['file'] ?? $file; + $line = $trace[2]['line'] ?? $line; + } + + throw new \ErrorException($message, 0, $type, $file, $line); + }); + + try { + return $function(...$arguments); + } finally { + restore_error_handler(); + } + } + + public function __construct(BufferingLogger $bootstrappingLogger = null, bool $debug = false) + { + if ($bootstrappingLogger) { + $this->bootstrappingLogger = $bootstrappingLogger; + $this->setDefaultLogger($bootstrappingLogger); + } + $this->traceReflector = new \ReflectionProperty(\Exception::class, 'trace'); + $this->traceReflector->setAccessible(true); + $this->debug = $debug; + } + + /** + * Sets a logger to non assigned errors levels. + * + * @param LoggerInterface $logger A PSR-3 logger to put as default for the given levels + * @param array|int|null $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants + * @param bool $replace Whether to replace or not any existing logger + */ + public function setDefaultLogger(LoggerInterface $logger, $levels = \E_ALL, bool $replace = false): void + { + $loggers = []; + + if (\is_array($levels)) { + foreach ($levels as $type => $logLevel) { + if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) { + $loggers[$type] = [$logger, $logLevel]; + } + } + } else { + if (null === $levels) { + $levels = \E_ALL; + } + foreach ($this->loggers as $type => $log) { + if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) { + $log[0] = $logger; + $loggers[$type] = $log; + } + } + } + + $this->setLoggers($loggers); + } + + /** + * Sets a logger for each error level. + * + * @param array $loggers Error levels to [LoggerInterface|null, LogLevel::*] map + * + * @return array The previous map + * + * @throws \InvalidArgumentException + */ + public function setLoggers(array $loggers): array + { + $prevLogged = $this->loggedErrors; + $prev = $this->loggers; + $flush = []; + + foreach ($loggers as $type => $log) { + if (!isset($prev[$type])) { + throw new \InvalidArgumentException('Unknown error type: '.$type); + } + if (!\is_array($log)) { + $log = [$log]; + } elseif (!\array_key_exists(0, $log)) { + throw new \InvalidArgumentException('No logger provided.'); + } + if (null === $log[0]) { + $this->loggedErrors &= ~$type; + } elseif ($log[0] instanceof LoggerInterface) { + $this->loggedErrors |= $type; + } else { + throw new \InvalidArgumentException('Invalid logger provided.'); + } + $this->loggers[$type] = $log + $prev[$type]; + + if ($this->bootstrappingLogger && $prev[$type][0] === $this->bootstrappingLogger) { + $flush[$type] = $type; + } + } + $this->reRegister($prevLogged | $this->thrownErrors); + + if ($flush) { + foreach ($this->bootstrappingLogger->cleanLogs() as $log) { + $type = ThrowableUtils::getSeverity($log[2]['exception']); + if (!isset($flush[$type])) { + $this->bootstrappingLogger->log($log[0], $log[1], $log[2]); + } elseif ($this->loggers[$type][0]) { + $this->loggers[$type][0]->log($this->loggers[$type][1], $log[1], $log[2]); + } + } + } + + return $prev; + } + + /** + * Sets a user exception handler. + * + * @param callable(\Throwable $e)|null $handler + * + * @return callable|null The previous exception handler + */ + public function setExceptionHandler(?callable $handler): ?callable + { + $prev = $this->exceptionHandler; + $this->exceptionHandler = $handler; + + return $prev; + } + + /** + * Sets the PHP error levels that throw an exception when a PHP error occurs. + * + * @param int $levels A bit field of E_* constants for thrown errors + * @param bool $replace Replace or amend the previous value + * + * @return int The previous value + */ + public function throwAt(int $levels, bool $replace = false): int + { + $prev = $this->thrownErrors; + $this->thrownErrors = ($levels | \E_RECOVERABLE_ERROR | \E_USER_ERROR) & ~\E_USER_DEPRECATED & ~\E_DEPRECATED; + if (!$replace) { + $this->thrownErrors |= $prev; + } + $this->reRegister($prev | $this->loggedErrors); + + return $prev; + } + + /** + * Sets the PHP error levels for which local variables are preserved. + * + * @param int $levels A bit field of E_* constants for scoped errors + * @param bool $replace Replace or amend the previous value + * + * @return int The previous value + */ + public function scopeAt(int $levels, bool $replace = false): int + { + $prev = $this->scopedErrors; + $this->scopedErrors = $levels; + if (!$replace) { + $this->scopedErrors |= $prev; + } + + return $prev; + } + + /** + * Sets the PHP error levels for which the stack trace is preserved. + * + * @param int $levels A bit field of E_* constants for traced errors + * @param bool $replace Replace or amend the previous value + * + * @return int The previous value + */ + public function traceAt(int $levels, bool $replace = false): int + { + $prev = $this->tracedErrors; + $this->tracedErrors = $levels; + if (!$replace) { + $this->tracedErrors |= $prev; + } + + return $prev; + } + + /** + * Sets the error levels where the @-operator is ignored. + * + * @param int $levels A bit field of E_* constants for screamed errors + * @param bool $replace Replace or amend the previous value + * + * @return int The previous value + */ + public function screamAt(int $levels, bool $replace = false): int + { + $prev = $this->screamedErrors; + $this->screamedErrors = $levels; + if (!$replace) { + $this->screamedErrors |= $prev; + } + + return $prev; + } + + /** + * Re-registers as a PHP error handler if levels changed. + */ + private function reRegister(int $prev): void + { + if ($prev !== ($this->thrownErrors | $this->loggedErrors)) { + $handler = set_error_handler('is_int'); + $handler = \is_array($handler) ? $handler[0] : null; + restore_error_handler(); + if ($handler === $this) { + restore_error_handler(); + if ($this->isRoot) { + set_error_handler([$this, 'handleError'], $this->thrownErrors | $this->loggedErrors); + } else { + set_error_handler([$this, 'handleError']); + } + } + } + } + + /** + * Handles errors by filtering then logging them according to the configured bit fields. + * + * @return bool Returns false when no handling happens so that the PHP engine can handle the error itself + * + * @throws \ErrorException When $this->thrownErrors requests so + * + * @internal + */ + public function handleError(int $type, string $message, string $file, int $line): bool + { + if (\PHP_VERSION_ID >= 70300 && \E_WARNING === $type && '"' === $message[0] && false !== strpos($message, '" targeting switch is equivalent to "break')) { + $type = \E_DEPRECATED; + } + + // Level is the current error reporting level to manage silent error. + $level = error_reporting(); + $silenced = 0 === ($level & $type); + // Strong errors are not authorized to be silenced. + $level |= \E_RECOVERABLE_ERROR | \E_USER_ERROR | \E_DEPRECATED | \E_USER_DEPRECATED; + $log = $this->loggedErrors & $type; + $throw = $this->thrownErrors & $type & $level; + $type &= $level | $this->screamedErrors; + + // Never throw on warnings triggered by assert() + if (\E_WARNING === $type && 'a' === $message[0] && 0 === strncmp($message, 'assert(): ', 10)) { + $throw = 0; + } + + if (!$type || (!$log && !$throw)) { + return false; + } + + $logMessage = $this->levels[$type].': '.$message; + + if (null !== self::$toStringException) { + $errorAsException = self::$toStringException; + self::$toStringException = null; + } elseif (!$throw && !($type & $level)) { + if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) { + $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 5), $type, $file, $line, false) : []; + $errorAsException = new SilencedErrorContext($type, $file, $line, isset($lightTrace[1]) ? [$lightTrace[0]] : $lightTrace); + } elseif (isset(self::$silencedErrorCache[$id][$message])) { + $lightTrace = null; + $errorAsException = self::$silencedErrorCache[$id][$message]; + ++$errorAsException->count; + } else { + $lightTrace = []; + $errorAsException = null; + } + + if (100 < ++self::$silencedErrorCount) { + self::$silencedErrorCache = $lightTrace = []; + self::$silencedErrorCount = 1; + } + if ($errorAsException) { + self::$silencedErrorCache[$id][$message] = $errorAsException; + } + if (null === $lightTrace) { + return true; + } + } else { + if (false !== strpos($message, '@anonymous')) { + $backtrace = debug_backtrace(false, 5); + + for ($i = 1; isset($backtrace[$i]); ++$i) { + if (isset($backtrace[$i]['function'], $backtrace[$i]['args'][0]) + && ('trigger_error' === $backtrace[$i]['function'] || 'user_error' === $backtrace[$i]['function']) + ) { + if ($backtrace[$i]['args'][0] !== $message) { + $message = $this->parseAnonymousClass($backtrace[$i]['args'][0]); + $logMessage = $this->levels[$type].': '.$message; + } + + break; + } + } + } + + $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); + + if ($throw || $this->tracedErrors & $type) { + $backtrace = $errorAsException->getTrace(); + $lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw); + $this->traceReflector->setValue($errorAsException, $lightTrace); + } else { + $this->traceReflector->setValue($errorAsException, []); + $backtrace = []; + } + } + + if ($throw) { + if (\PHP_VERSION_ID < 70400 && \E_USER_ERROR & $type) { + for ($i = 1; isset($backtrace[$i]); ++$i) { + if (isset($backtrace[$i]['function'], $backtrace[$i]['type'], $backtrace[$i - 1]['function']) + && '__toString' === $backtrace[$i]['function'] + && '->' === $backtrace[$i]['type'] + && !isset($backtrace[$i - 1]['class']) + && ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function']) + ) { + // Here, we know trigger_error() has been called from __toString(). + // PHP triggers a fatal error when throwing from __toString(). + // A small convention allows working around the limitation: + // given a caught $e exception in __toString(), quitting the method with + // `return trigger_error($e, E_USER_ERROR);` allows this error handler + // to make $e get through the __toString() barrier. + + $context = 4 < \func_num_args() ? (func_get_arg(4) ?: []) : []; + + foreach ($context as $e) { + if ($e instanceof \Throwable && $e->__toString() === $message) { + self::$toStringException = $e; + + return true; + } + } + + // Display the original error message instead of the default one. + $this->handleException($errorAsException); + + // Stop the process by giving back the error to the native handler. + return false; + } + } + } + + throw $errorAsException; + } + + if ($this->isRecursive) { + $log = 0; + } else { + if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) { + $currentErrorHandler = set_error_handler('is_int'); + restore_error_handler(); + } + + try { + $this->isRecursive = true; + $level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG; + $this->loggers[$type][0]->log($level, $logMessage, $errorAsException ? ['exception' => $errorAsException] : []); + } finally { + $this->isRecursive = false; + + if (\PHP_VERSION_ID < (\PHP_VERSION_ID < 70400 ? 70316 : 70404)) { + set_error_handler($currentErrorHandler); + } + } + } + + return !$silenced && $type && $log; + } + + /** + * Handles an exception by logging then forwarding it to another handler. + * + * @internal + */ + public function handleException(\Throwable $exception) + { + $handlerException = null; + + if (!$exception instanceof FatalError) { + self::$exitCode = 255; + + $type = ThrowableUtils::getSeverity($exception); + } else { + $type = $exception->getError()['type']; + } + + if ($this->loggedErrors & $type) { + if (false !== strpos($message = $exception->getMessage(), "@anonymous\0")) { + $message = $this->parseAnonymousClass($message); + } + + if ($exception instanceof FatalError) { + $message = 'Fatal '.$message; + } elseif ($exception instanceof \Error) { + $message = 'Uncaught Error: '.$message; + } elseif ($exception instanceof \ErrorException) { + $message = 'Uncaught '.$message; + } else { + $message = 'Uncaught Exception: '.$message; + } + + try { + $this->loggers[$type][0]->log($this->loggers[$type][1], $message, ['exception' => $exception]); + } catch (\Throwable $handlerException) { + } + } + + if (!$exception instanceof OutOfMemoryError) { + foreach ($this->getErrorEnhancers() as $errorEnhancer) { + if ($e = $errorEnhancer->enhance($exception)) { + $exception = $e; + break; + } + } + } + + $exceptionHandler = $this->exceptionHandler; + $this->exceptionHandler = [$this, 'renderException']; + + if (null === $exceptionHandler || $exceptionHandler === $this->exceptionHandler) { + $this->exceptionHandler = null; + } + + try { + if (null !== $exceptionHandler) { + return $exceptionHandler($exception); + } + $handlerException = $handlerException ?: $exception; + } catch (\Throwable $handlerException) { + } + if ($exception === $handlerException && null === $this->exceptionHandler) { + self::$reservedMemory = null; // Disable the fatal error handler + throw $exception; // Give back $exception to the native handler + } + + $loggedErrors = $this->loggedErrors; + if ($exception === $handlerException) { + $this->loggedErrors &= ~$type; + } + + try { + $this->handleException($handlerException); + } finally { + $this->loggedErrors = $loggedErrors; + } + } + + /** + * Shutdown registered function for handling PHP fatal errors. + * + * @param array|null $error An array as returned by error_get_last() + * + * @internal + */ + public static function handleFatalError(array $error = null): void + { + if (null === self::$reservedMemory) { + return; + } + + $handler = self::$reservedMemory = null; + $handlers = []; + $previousHandler = null; + $sameHandlerLimit = 10; + + while (!\is_array($handler) || !$handler[0] instanceof self) { + $handler = set_exception_handler('is_int'); + restore_exception_handler(); + + if (!$handler) { + break; + } + restore_exception_handler(); + + if ($handler !== $previousHandler) { + array_unshift($handlers, $handler); + $previousHandler = $handler; + } elseif (0 === --$sameHandlerLimit) { + $handler = null; + break; + } + } + foreach ($handlers as $h) { + set_exception_handler($h); + } + if (!$handler) { + return; + } + if ($handler !== $h) { + $handler[0]->setExceptionHandler($h); + } + $handler = $handler[0]; + $handlers = []; + + if ($exit = null === $error) { + $error = error_get_last(); + } + + if ($error && $error['type'] &= \E_PARSE | \E_ERROR | \E_CORE_ERROR | \E_COMPILE_ERROR) { + // Let's not throw anymore but keep logging + $handler->throwAt(0, true); + $trace = $error['backtrace'] ?? null; + + if (0 === strpos($error['message'], 'Allowed memory') || 0 === strpos($error['message'], 'Out of memory')) { + $fatalError = new OutOfMemoryError($handler->levels[$error['type']].': '.$error['message'], 0, $error, 2, false, $trace); + } else { + $fatalError = new FatalError($handler->levels[$error['type']].': '.$error['message'], 0, $error, 2, true, $trace); + } + } else { + $fatalError = null; + } + + try { + if (null !== $fatalError) { + self::$exitCode = 255; + $handler->handleException($fatalError); + } + } catch (FatalError $e) { + // Ignore this re-throw + } + + if ($exit && self::$exitCode) { + $exitCode = self::$exitCode; + register_shutdown_function('register_shutdown_function', function () use ($exitCode) { exit($exitCode); }); + } + } + + /** + * Renders the given exception. + * + * As this method is mainly called during boot where nothing is yet available, + * the output is always either HTML or CLI depending where PHP runs. + */ + private function renderException(\Throwable $exception): void + { + $renderer = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliErrorRenderer() : new HtmlErrorRenderer($this->debug); + + $exception = $renderer->render($exception); + + if (!headers_sent()) { + http_response_code($exception->getStatusCode()); + + foreach ($exception->getHeaders() as $name => $value) { + header($name.': '.$value, false); + } + } + + echo $exception->getAsString(); + } + + /** + * Override this method if you want to define more error enhancers. + * + * @return ErrorEnhancerInterface[] + */ + protected function getErrorEnhancers(): iterable + { + return [ + new UndefinedFunctionErrorEnhancer(), + new UndefinedMethodErrorEnhancer(), + new ClassNotFoundErrorEnhancer(), + ]; + } + + /** + * Cleans the trace by removing function arguments and the frames added by the error handler and DebugClassLoader. + */ + private function cleanTrace(array $backtrace, int $type, string $file, int $line, bool $throw): array + { + $lightTrace = $backtrace; + + for ($i = 0; isset($backtrace[$i]); ++$i) { + if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { + $lightTrace = \array_slice($lightTrace, 1 + $i); + break; + } + } + if (class_exists(DebugClassLoader::class, false)) { + for ($i = \count($lightTrace) - 2; 0 < $i; --$i) { + if (DebugClassLoader::class === ($lightTrace[$i]['class'] ?? null)) { + array_splice($lightTrace, --$i, 2); + } + } + } + if (!($throw || $this->scopedErrors & $type)) { + for ($i = 0; isset($lightTrace[$i]); ++$i) { + unset($lightTrace[$i]['args'], $lightTrace[$i]['object']); + } + } + + return $lightTrace; + } + + /** + * Parse the error message by removing the anonymous class notation + * and using the parent class instead if possible. + */ + private function parseAnonymousClass(string $message): string + { + return preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', static function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $message); + } +} diff --git a/vendor/symfony/error-handler/ErrorRenderer/CliErrorRenderer.php b/vendor/symfony/error-handler/ErrorRenderer/CliErrorRenderer.php new file mode 100644 index 00000000..5c0f6a7d --- /dev/null +++ b/vendor/symfony/error-handler/ErrorRenderer/CliErrorRenderer.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +// Help opcache.preload discover always-needed symbols +class_exists(CliDumper::class); + +/** + * @author Nicolas Grekas + */ +class CliErrorRenderer implements ErrorRendererInterface +{ + /** + * {@inheritdoc} + */ + public function render(\Throwable $exception): FlattenException + { + $cloner = new VarCloner(); + $dumper = new class() extends CliDumper { + protected function supportsColors(): bool + { + $outputStream = $this->outputStream; + $this->outputStream = fopen('php://stdout', 'w'); + + try { + return parent::supportsColors(); + } finally { + $this->outputStream = $outputStream; + } + } + }; + + return FlattenException::createFromThrowable($exception) + ->setAsString($dumper->dump($cloner->cloneVar($exception), true)); + } +} diff --git a/vendor/symfony/error-handler/ErrorRenderer/ErrorRendererInterface.php b/vendor/symfony/error-handler/ErrorRenderer/ErrorRendererInterface.php new file mode 100644 index 00000000..aba19660 --- /dev/null +++ b/vendor/symfony/error-handler/ErrorRenderer/ErrorRendererInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; + +/** + * Formats an exception to be used as response content. + * + * @author Yonel Ceruto + */ +interface ErrorRendererInterface +{ + /** + * Renders a Throwable as a FlattenException. + */ + public function render(\Throwable $exception): FlattenException; +} diff --git a/vendor/symfony/error-handler/ErrorRenderer/HtmlErrorRenderer.php b/vendor/symfony/error-handler/ErrorRenderer/HtmlErrorRenderer.php new file mode 100644 index 00000000..4c0fb9cc --- /dev/null +++ b/vendor/symfony/error-handler/ErrorRenderer/HtmlErrorRenderer.php @@ -0,0 +1,352 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Psr\Log\LoggerInterface; +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; + +/** + * @author Yonel Ceruto + */ +class HtmlErrorRenderer implements ErrorRendererInterface +{ + private const GHOST_ADDONS = [ + '02-14' => self::GHOST_HEART, + '02-29' => self::GHOST_PLUS, + '10-18' => self::GHOST_GIFT, + ]; + + private const GHOST_GIFT = 'M124.00534057617188,5.3606138080358505 C124.40059661865234,4.644828304648399 125.1237564086914,3.712414965033531 123.88127899169922,3.487462028861046 C123.53517150878906,3.3097832053899765 123.18894958496094,2.9953975528478622 122.8432846069336,3.345616325736046 C122.07421112060547,3.649444565176964 121.40750122070312,4.074306473135948 122.2164306640625,4.869479164481163 C122.57514953613281,5.3830065578222275 122.90142822265625,6.503447040915489 123.3077621459961,6.626829609274864 C123.55027770996094,6.210384353995323 123.7774658203125,5.785196766257286 124.00534057617188,5.3606138080358505 zM122.30630493164062,7.336987480521202 C121.60028076171875,6.076864704489708 121.03211975097656,4.72498320043087 120.16796875,3.562500938773155 C119.11695098876953,2.44033907353878 117.04605865478516,2.940566048026085 116.57544708251953,4.387995228171349 C115.95028686523438,5.819030746817589 117.2991714477539,7.527640804648399 118.826171875,7.348545059561729 C119.98493194580078,7.367936596274376 121.15027618408203,7.420116886496544 122.30630493164062,7.336987480521202 zM128.1732177734375,7.379541382193565 C129.67486572265625,7.17823551595211 130.53842163085938,5.287807449698448 129.68344116210938,4.032590612769127 C128.92578125,2.693056806921959 126.74605560302734,2.6463639587163925 125.98509216308594,4.007616028189659 C125.32617950439453,5.108129009604454 124.75428009033203,6.258124336600304 124.14962768554688,7.388818249106407 C125.48638916015625,7.465229496359825 126.8357162475586,7.447416767477989 128.1732177734375,7.379541382193565 zM130.6601104736328,8.991325363516808 C131.17202758789062,8.540884003043175 133.1543731689453,8.009847149252892 131.65304565429688,7.582054600119591 C131.2811279296875,7.476506695151329 130.84751892089844,6.99234913289547 130.5132598876953,7.124847874045372 C129.78744506835938,8.02728746831417 128.67140197753906,8.55669592320919 127.50616455078125,8.501235947012901 C127.27806091308594,8.576229080557823 126.11459350585938,8.38720129430294 126.428955078125,8.601900085806847 C127.25099182128906,9.070617660880089 128.0523223876953,9.579657539725304 128.902587890625,9.995706543326378 C129.49813842773438,9.678531631827354 130.0761260986328,9.329126343131065 130.6601104736328,8.991325363516808 zM118.96446990966797,9.246344551444054 C119.4022445678711,8.991325363516808 119.84001922607422,8.736305221915245 120.27779388427734,8.481284126639366 C118.93965911865234,8.414779648184776 117.40827941894531,8.607666000723839 116.39698791503906,7.531384453177452 C116.11186981201172,7.212117180228233 115.83845520019531,6.846597656607628 115.44329071044922,7.248530372977257 C114.96995544433594,7.574637398123741 113.5140609741211,7.908811077475548 114.63501739501953,8.306883797049522 C115.61112976074219,8.883499130606651 116.58037567138672,9.474181160330772 117.58061218261719,10.008124336600304 C118.05723571777344,9.784612640738487 118.50651550292969,9.5052699893713 118.96446990966797,9.246344551444054 zM125.38018035888672,12.091858848929405 C125.9474868774414,11.636047348380089 127.32159423828125,11.201767906546593 127.36749267578125,10.712632164359093 C126.08487701416016,9.974547371268272 124.83960723876953,9.152772888541222 123.49772644042969,8.528907760977745 C123.03594207763672,8.353693947196007 122.66152954101562,8.623294815421104 122.28982543945312,8.857431396842003 C121.19065856933594,9.51122473180294 120.06505584716797,10.12446115911007 119.00167083740234,10.835315689444542 C120.39238739013672,11.69529627263546 121.79983520507812,12.529837593436241 123.22095489501953,13.338589653372765 C123.94580841064453,12.932025894522667 124.66128540039062,12.508862480521202 125.38018035888672,12.091858848929405 zM131.07164001464844,13.514615997672081 C131.66018676757812,13.143282875418663 132.2487335205078,12.771927818655968 132.8372802734375,12.400571808218956 C132.8324737548828,11.156818374991417 132.8523406982422,9.912529930472374 132.81829833984375,8.669195160269737 C131.63046264648438,9.332009300589561 130.45948791503906,10.027913078665733 129.30828857421875,10.752535805106163 C129.182373046875,12.035354599356651 129.24623107910156,13.33940313756466 129.27359008789062,14.628684982657433 C129.88104248046875,14.27079389989376 130.4737548828125,13.888019546866417 131.07164001464844,13.514640793204308 zM117.26847839355469,12.731024727225304 C117.32825469970703,11.67083452641964 117.45709991455078,10.46224020421505 116.17853546142578,10.148179039359093 C115.37110900878906,9.77159021794796 114.25194549560547,8.806716904044151 113.62991333007812,8.81639002263546 C113.61052703857422,10.0110072940588 113.62078857421875,11.20585821568966 113.61869049072266,12.400571808218956 C114.81139373779297,13.144886955618858 115.98292541503906,13.925040230154991 117.20137023925781,14.626662239432335 C117.31951141357422,14.010867103934288 117.24227905273438,13.35805033147335 117.26847839355469,12.731024727225304 zM125.80937957763672,16.836034759879112 C126.51483917236328,16.390663132071495 127.22030639648438,15.945291504263878 127.92576599121094,15.49991987645626 C127.92250061035156,14.215868934988976 127.97560119628906,12.929980263113976 127.91757202148438,11.647302612662315 C127.14225769042969,11.869626984000206 126.25550079345703,12.556857094168663 125.43866729736328,12.983742699027061 C124.82704162597656,13.342005714774132 124.21542358398438,13.700271591544151 123.60379028320312,14.05853746831417 C123.61585235595703,15.429577812552452 123.57081604003906,16.803131088614464 123.64839172363281,18.172149643301964 C124.37957000732422,17.744937881827354 125.09130859375,17.284801468253136 125.80937957763672,16.836034759879112 zM122.8521499633789,16.115344032645226 C122.8521499633789,15.429741844534874 122.8521499633789,14.744139656424522 122.8521499633789,14.05853746831417 C121.43595123291016,13.230924591422081 120.02428436279297,12.395455345511436 118.60256958007812,11.577354416251183 C118.52394104003906,12.888403877615929 118.56887817382812,14.204405769705772 118.55702209472656,15.517732605338097 C119.97289276123047,16.4041957706213 121.37410736083984,17.314891800284386 122.80789947509766,18.172149643301964 C122.86368560791016,17.488990768790245 122.84332275390625,16.800363525748253 122.8521499633789,16.115344032645226 zM131.10684204101562,18.871450409293175 C131.68399047851562,18.48711584508419 132.2611541748047,18.10278509557247 132.8383026123047,17.718475326895714 C132.81423950195312,16.499977096915245 132.89776611328125,15.264989838004112 132.77627563476562,14.05993078649044 C131.5760040283203,14.744719490408897 130.41763305664062,15.524359688162804 129.23875427246094,16.255397781729698 C129.26707458496094,17.516149505972862 129.18060302734375,18.791316971182823 129.3108367919922,20.041303619742393 C129.91973876953125,19.667551025748253 130.51010131835938,19.264152511954308 131.10684204101562,18.871450409293175 zM117.2557373046875,18.188333496451378 C117.25104522705078,17.549470886588097 117.24633026123047,16.91058538854122 117.24163055419922,16.271720871329308 C116.04924774169922,15.525708183646202 114.87187957763672,14.75476549565792 113.66158294677734,14.038097366690636 C113.5858383178711,15.262084946036339 113.62901306152344,16.49083898961544 113.61761474609375,17.717010483145714 C114.82051086425781,18.513254150748253 116.00987243652344,19.330610260367393 117.22888946533203,20.101993545889854 C117.27559661865234,19.466014847159386 117.25241088867188,18.825733169913292 117.2557373046875,18.188333496451378 zM125.8398666381836,22.38675306737423 C126.54049682617188,21.921453461050987 127.24110412597656,21.456151947379112 127.94172668457031,20.99083136022091 C127.94009399414062,19.693386062979698 127.96646118164062,18.395381912589073 127.93160247802734,17.098379120230675 C126.50540924072266,17.97775076329708 125.08877563476562,18.873308166861534 123.68258666992188,19.78428266942501 C123.52366638183594,21.03710363805294 123.626708984375,22.32878302037716 123.62647247314453,23.595300659537315 C124.06291198730469,23.86113165318966 125.1788101196289,22.68297766149044 125.8398666381836,22.38675306737423 zM122.8521499633789,21.83134649693966 C122.76741790771484,20.936696991324425 123.21651458740234,19.67745779454708 122.0794677734375,19.330633148550987 C120.93280029296875,18.604360565543175 119.7907485961914,17.870157226920128 118.62899780273438,17.16818617284298 C118.45966339111328,18.396427139639854 118.63676452636719,19.675991043448448 118.50668334960938,20.919256195425987 C119.89984130859375,21.92635916173458 121.32942199707031,22.88914106786251 122.78502655029297,23.803510650992393 C122.90177917480469,23.1627406924963 122.82917022705078,22.48402212560177 122.8521499633789,21.83134649693966 zM117.9798355102539,21.59483526647091 C116.28416442871094,20.46288488805294 114.58848571777344,19.330957397818565 112.892822265625,18.199007019400597 C112.89473724365234,14.705654129385948 112.84647369384766,11.211485847830772 112.90847778320312,7.718807205557823 C113.7575912475586,7.194885239005089 114.66117858886719,6.765397056937218 115.5350341796875,6.284702762961388 C114.97061157226562,4.668964847922325 115.78496551513672,2.7054970115423203 117.42159271240234,2.1007001250982285 C118.79354095458984,1.537783369421959 120.44731903076172,2.0457767099142075 121.32200622558594,3.23083733022213 C121.95732116699219,2.9050118774175644 122.59264373779297,2.5791852325201035 123.22796630859375,2.253336176276207 C123.86669921875,2.5821153968572617 124.50543975830078,2.9108948558568954 125.1441650390625,3.23967407643795 C126.05941009521484,2.154020771384239 127.62747192382812,1.5344576686620712 128.986328125,2.1429056972265244 C130.61741638183594,2.716217741370201 131.50650024414062,4.675290569663048 130.9215545654297,6.2884936183691025 C131.8018341064453,6.78548763692379 132.7589111328125,7.1738648265600204 133.5660400390625,7.780336365103722 C133.60182189941406,11.252970680594444 133.56637573242188,14.726140961050987 133.5631103515625,18.199007019400597 C130.18914794921875,20.431867584586143 126.86984252929688,22.74994657933712 123.44108581542969,24.897907242178917 C122.44406127929688,24.897628769278526 121.5834732055664,23.815067276358604 120.65831756591797,23.37616156041622 C119.76387023925781,22.784828171133995 118.87168884277344,22.19007681310177 117.9798355102539,21.59483526647091 z'; + private const GHOST_HEART = 'M125.91386369681868,8.305165958366445 C128.95033202169043,-0.40540639102854037 140.8469835342744,8.305165958366445 125.91386369681868,19.504526138305664 C110.98208663272044,8.305165958366445 122.87795231771452,-0.40540639102854037 125.91386369681868,8.305165958366445 z'; + private const GHOST_PLUS = 'M111.36824226379395,8.969108581542969 L118.69175148010254,8.969108581542969 L118.69175148010254,1.6455793380737305 L126.20429420471191,1.6455793380737305 L126.20429420471191,8.969108581542969 L133.52781105041504,8.969108581542969 L133.52781105041504,16.481630325317383 L126.20429420471191,16.481630325317383 L126.20429420471191,23.805158615112305 L118.69175148010254,23.805158615112305 L118.69175148010254,16.481630325317383 L111.36824226379395,16.481630325317383 z'; + + private $debug; + private $charset; + private $fileLinkFormat; + private $projectDir; + private $outputBuffer; + private $logger; + + /** + * @param bool|callable $debug The debugging mode as a boolean or a callable that should return it + * @param string|FileLinkFormatter|null $fileLinkFormat + * @param bool|callable $outputBuffer The output buffer as a string or a callable that should return it + */ + public function __construct($debug = false, string $charset = null, $fileLinkFormat = null, string $projectDir = null, $outputBuffer = '', LoggerInterface $logger = null) + { + if (!\is_bool($debug) && !\is_callable($debug)) { + throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a boolean or a callable, "%s" given.', __METHOD__, \is_object($debug) ? \get_class($debug) : \gettype($debug))); + } + + if (!\is_string($outputBuffer) && !\is_callable($outputBuffer)) { + throw new \TypeError(sprintf('Argument 5 passed to "%s()" must be a string or a callable, "%s" given.', __METHOD__, \is_object($outputBuffer) ? \get_class($outputBuffer) : \gettype($outputBuffer))); + } + + $this->debug = $debug; + $this->charset = $charset ?: (\ini_get('default_charset') ?: 'UTF-8'); + $this->fileLinkFormat = $fileLinkFormat ?: (\ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')); + $this->projectDir = $projectDir; + $this->outputBuffer = $outputBuffer; + $this->logger = $logger; + } + + /** + * {@inheritdoc} + */ + public function render(\Throwable $exception): FlattenException + { + $exception = FlattenException::createFromThrowable($exception, null, [ + 'Content-Type' => 'text/html; charset='.$this->charset, + ]); + + return $exception->setAsString($this->renderException($exception)); + } + + /** + * Gets the HTML content associated with the given exception. + */ + public function getBody(FlattenException $exception): string + { + return $this->renderException($exception, 'views/exception.html.php'); + } + + /** + * Gets the stylesheet associated with the given exception. + */ + public function getStylesheet(): string + { + if (!$this->debug) { + return $this->include('assets/css/error.css'); + } + + return $this->include('assets/css/exception.css'); + } + + public static function isDebug(RequestStack $requestStack, bool $debug): \Closure + { + return static function () use ($requestStack, $debug): bool { + if (!$request = $requestStack->getCurrentRequest()) { + return $debug; + } + + return $debug && $request->attributes->getBoolean('showException', true); + }; + } + + public static function getAndCleanOutputBuffer(RequestStack $requestStack): \Closure + { + return static function () use ($requestStack): string { + if (!$request = $requestStack->getCurrentRequest()) { + return ''; + } + + $startObLevel = $request->headers->get('X-Php-Ob-Level', -1); + + if (ob_get_level() <= $startObLevel) { + return ''; + } + + Response::closeOutputBuffers($startObLevel + 1, true); + + return ob_get_clean(); + }; + } + + private function renderException(FlattenException $exception, string $debugTemplate = 'views/exception_full.html.php'): string + { + $debug = \is_bool($this->debug) ? $this->debug : ($this->debug)($exception); + $statusText = $this->escape($exception->getStatusText()); + $statusCode = $this->escape($exception->getStatusCode()); + + if (!$debug) { + return $this->include('views/error.html.php', [ + 'statusText' => $statusText, + 'statusCode' => $statusCode, + ]); + } + + $exceptionMessage = $this->escape($exception->getMessage()); + + return $this->include($debugTemplate, [ + 'exception' => $exception, + 'exceptionMessage' => $exceptionMessage, + 'statusText' => $statusText, + 'statusCode' => $statusCode, + 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, + 'currentContent' => \is_string($this->outputBuffer) ? $this->outputBuffer : ($this->outputBuffer)(), + ]); + } + + /** + * Formats an array as a string. + */ + private function formatArgs(array $args): string + { + $result = []; + foreach ($args as $key => $item) { + if ('object' === $item[0]) { + $formattedValue = sprintf('object(%s)', $this->abbrClass($item[1])); + } elseif ('array' === $item[0]) { + $formattedValue = sprintf('array(%s)', \is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]); + } elseif ('null' === $item[0]) { + $formattedValue = 'null'; + } elseif ('boolean' === $item[0]) { + $formattedValue = ''.strtolower(var_export($item[1], true)).''; + } elseif ('resource' === $item[0]) { + $formattedValue = 'resource'; + } else { + $formattedValue = str_replace("\n", '', $this->escape(var_export($item[1], true))); + } + + $result[] = \is_int($key) ? $formattedValue : sprintf("'%s' => %s", $this->escape($key), $formattedValue); + } + + return implode(', ', $result); + } + + private function formatArgsAsText(array $args) + { + return strip_tags($this->formatArgs($args)); + } + + private function escape(string $string): string + { + return htmlspecialchars($string, \ENT_COMPAT | \ENT_SUBSTITUTE, $this->charset); + } + + private function abbrClass(string $class): string + { + $parts = explode('\\', $class); + $short = array_pop($parts); + + return sprintf('%s', $class, $short); + } + + private function getFileRelative(string $file): ?string + { + $file = str_replace('\\', '/', $file); + + if (null !== $this->projectDir && 0 === strpos($file, $this->projectDir)) { + return ltrim(substr($file, \strlen($this->projectDir)), '/'); + } + + return null; + } + + /** + * Returns the link for a given file/line pair. + * + * @return string|false A link or false + */ + private function getFileLink(string $file, int $line) + { + if ($fmt = $this->fileLinkFormat) { + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line); + } + + return false; + } + + /** + * Formats a file path. + * + * @param string $file An absolute file path + * @param int $line The line number + * @param string $text Use this text for the link rather than the file path + */ + private function formatFile(string $file, int $line, string $text = null): string + { + $file = trim($file); + + if (null === $text) { + $text = $file; + if (null !== $rel = $this->getFileRelative($text)) { + $rel = explode('/', $rel, 2); + $text = sprintf('%s%s', $this->projectDir, $rel[0], '/'.($rel[1] ?? '')); + } + } + + if (0 < $line) { + $text .= ' at line '.$line; + } + + if (false !== $link = $this->getFileLink($file, $line)) { + return sprintf('%s', $this->escape($link), $text); + } + + return $text; + } + + /** + * Returns an excerpt of a code file around the given line number. + * + * @param string $file A file path + * @param int $line The selected line number + * @param int $srcContext The number of displayed lines around or -1 for the whole file + * + * @return string An HTML string + */ + private function fileExcerpt(string $file, int $line, int $srcContext = 3): string + { + if (is_file($file) && is_readable($file)) { + // highlight_file could throw warnings + // see https://bugs.php.net/25725 + $code = @highlight_file($file, true); + // remove main code/span tags + $code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code); + // split multiline spans + $code = preg_replace_callback('#]++)>((?:[^<]*+
)++[^<]*+)
#', function ($m) { + return "".str_replace('
', "

", $m[2]).''; + }, $code); + $content = explode('
', $code); + + $lines = []; + if (0 > $srcContext) { + $srcContext = \count($content); + } + + for ($i = max($line - $srcContext, 1), $max = min($line + $srcContext, \count($content)); $i <= $max; ++$i) { + $lines[] = ''.$this->fixCodeMarkup($content[$i - 1]).''; + } + + return '
    '.implode("\n", $lines).'
'; + } + + return ''; + } + + private function fixCodeMarkup(string $line) + { + // ending tag from previous line + $opening = strpos($line, ''); + if (false !== $closing && (false === $opening || $closing < $opening)) { + $line = substr_replace($line, '', $closing, 7); + } + + // missing tag at the end of line + $opening = strpos($line, ''); + if (false !== $opening && (false === $closing || $closing > $opening)) { + $line .= ''; + } + + return trim($line); + } + + private function formatFileFromText(string $text) + { + return preg_replace_callback('/in ("|")?(.+?)\1(?: +(?:on|at))? +line (\d+)/s', function ($match) { + return 'in '.$this->formatFile($match[2], $match[3]); + }, $text); + } + + private function formatLogMessage(string $message, array $context) + { + if ($context && false !== strpos($message, '{')) { + $replacements = []; + foreach ($context as $key => $val) { + if (\is_scalar($val)) { + $replacements['{'.$key.'}'] = $val; + } + } + + if ($replacements) { + $message = strtr($message, $replacements); + } + } + + return $this->escape($message); + } + + private function addElementToGhost(): string + { + if (!isset(self::GHOST_ADDONS[date('m-d')])) { + return ''; + } + + return ''; + } + + private function include(string $name, array $context = []): string + { + extract($context, \EXTR_SKIP); + ob_start(); + include __DIR__.'/../Resources/'.$name; + + return trim(ob_get_clean()); + } +} diff --git a/vendor/symfony/error-handler/ErrorRenderer/SerializerErrorRenderer.php b/vendor/symfony/error-handler/ErrorRenderer/SerializerErrorRenderer.php new file mode 100644 index 00000000..e0640850 --- /dev/null +++ b/vendor/symfony/error-handler/ErrorRenderer/SerializerErrorRenderer.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\ErrorRenderer; + +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\Serializer\Exception\NotEncodableValueException; +use Symfony\Component\Serializer\SerializerInterface; + +/** + * Formats an exception using Serializer for rendering. + * + * @author Nicolas Grekas + */ +class SerializerErrorRenderer implements ErrorRendererInterface +{ + private $serializer; + private $format; + private $fallbackErrorRenderer; + private $debug; + + /** + * @param string|callable(FlattenException) $format The format as a string or a callable that should return it + * formats not supported by Request::getMimeTypes() should be given as mime types + * @param bool|callable $debug The debugging mode as a boolean or a callable that should return it + */ + public function __construct(SerializerInterface $serializer, $format, ErrorRendererInterface $fallbackErrorRenderer = null, $debug = false) + { + if (!\is_string($format) && !\is_callable($format)) { + throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be a string or a callable, "%s" given.', __METHOD__, \is_object($format) ? \get_class($format) : \gettype($format))); + } + + if (!\is_bool($debug) && !\is_callable($debug)) { + throw new \TypeError(sprintf('Argument 4 passed to "%s()" must be a boolean or a callable, "%s" given.', __METHOD__, \is_object($debug) ? \get_class($debug) : \gettype($debug))); + } + + $this->serializer = $serializer; + $this->format = $format; + $this->fallbackErrorRenderer = $fallbackErrorRenderer ?? new HtmlErrorRenderer(); + $this->debug = $debug; + } + + /** + * {@inheritdoc} + */ + public function render(\Throwable $exception): FlattenException + { + $flattenException = FlattenException::createFromThrowable($exception); + + try { + $format = \is_string($this->format) ? $this->format : ($this->format)($flattenException); + $headers = [ + 'Content-Type' => Request::getMimeTypes($format)[0] ?? $format, + 'Vary' => 'Accept', + ]; + + return $flattenException->setAsString($this->serializer->serialize($flattenException, $format, [ + 'exception' => $exception, + 'debug' => \is_bool($this->debug) ? $this->debug : ($this->debug)($exception), + ])) + ->setHeaders($flattenException->getHeaders() + $headers); + } catch (NotEncodableValueException $e) { + return $this->fallbackErrorRenderer->render($exception); + } + } + + public static function getPreferredFormat(RequestStack $requestStack): \Closure + { + return static function () use ($requestStack) { + if (!$request = $requestStack->getCurrentRequest()) { + throw new NotEncodableValueException(); + } + + return $request->getPreferredFormat(); + }; + } +} diff --git a/vendor/symfony/error-handler/Exception/FlattenException.php b/vendor/symfony/error-handler/Exception/FlattenException.php new file mode 100644 index 00000000..44bf9c93 --- /dev/null +++ b/vendor/symfony/error-handler/Exception/FlattenException.php @@ -0,0 +1,454 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Exception; + +use Symfony\Component\Debug\Exception\FatalThrowableError; +use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException; +use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; + +/** + * FlattenException wraps a PHP Error or Exception to be able to serialize it. + * + * Basically, this class removes all objects from the trace. + * + * @author Fabien Potencier + */ +class FlattenException extends LegacyFlattenException +{ + /** @var string */ + private $message; + + /** @var int|string */ + private $code; + + /** @var self|null */ + private $previous; + + /** @var array */ + private $trace; + + /** @var string */ + private $traceAsString; + + /** @var string */ + private $class; + + /** @var int */ + private $statusCode; + + /** @var string */ + private $statusText; + + /** @var array */ + private $headers; + + /** @var string */ + private $file; + + /** @var int */ + private $line; + + /** @var string|null */ + private $asString; + + /** + * @return static + */ + public static function create(\Exception $exception, $statusCode = null, array $headers = []): self + { + return static::createFromThrowable($exception, $statusCode, $headers); + } + + /** + * @return static + */ + public static function createFromThrowable(\Throwable $exception, int $statusCode = null, array $headers = []): self + { + $e = new static(); + $e->setMessage($exception->getMessage()); + $e->setCode($exception->getCode()); + + if ($exception instanceof HttpExceptionInterface) { + $statusCode = $exception->getStatusCode(); + $headers = array_merge($headers, $exception->getHeaders()); + } elseif ($exception instanceof RequestExceptionInterface) { + $statusCode = 400; + } + + if (null === $statusCode) { + $statusCode = 500; + } + + if (class_exists(Response::class) && isset(Response::$statusTexts[$statusCode])) { + $statusText = Response::$statusTexts[$statusCode]; + } else { + $statusText = 'Whoops, looks like something went wrong.'; + } + + $e->setStatusText($statusText); + $e->setStatusCode($statusCode); + $e->setHeaders($headers); + $e->setTraceFromThrowable($exception); + $e->setClass($exception instanceof FatalThrowableError ? $exception->getOriginalClassName() : \get_class($exception)); + $e->setFile($exception->getFile()); + $e->setLine($exception->getLine()); + + $previous = $exception->getPrevious(); + + if ($previous instanceof \Throwable) { + $e->setPrevious(static::createFromThrowable($previous)); + } + + return $e; + } + + public function toArray(): array + { + $exceptions = []; + foreach (array_merge([$this], $this->getAllPrevious()) as $exception) { + $exceptions[] = [ + 'message' => $exception->getMessage(), + 'class' => $exception->getClass(), + 'trace' => $exception->getTrace(), + ]; + } + + return $exceptions; + } + + public function getStatusCode(): int + { + return $this->statusCode; + } + + /** + * @param int $code + * + * @return $this + */ + public function setStatusCode($code): self + { + $this->statusCode = $code; + + return $this; + } + + public function getHeaders(): array + { + return $this->headers; + } + + /** + * @return $this + */ + public function setHeaders(array $headers): self + { + $this->headers = $headers; + + return $this; + } + + public function getClass(): string + { + return $this->class; + } + + /** + * @param string $class + * + * @return $this + */ + public function setClass($class): self + { + $this->class = false !== strpos($class, "@anonymous\0") ? (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous' : $class; + + return $this; + } + + public function getFile(): string + { + return $this->file; + } + + /** + * @param string $file + * + * @return $this + */ + public function setFile($file): self + { + $this->file = $file; + + return $this; + } + + public function getLine(): int + { + return $this->line; + } + + /** + * @param int $line + * + * @return $this + */ + public function setLine($line): self + { + $this->line = $line; + + return $this; + } + + public function getStatusText(): string + { + return $this->statusText; + } + + public function setStatusText(string $statusText): self + { + $this->statusText = $statusText; + + return $this; + } + + public function getMessage(): string + { + return $this->message; + } + + /** + * @param string $message + * + * @return $this + */ + public function setMessage($message): self + { + if (false !== strpos($message, "@anonymous\0")) { + $message = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $message); + } + + $this->message = $message; + + return $this; + } + + /** + * @return int|string int most of the time (might be a string with PDOException) + */ + public function getCode() + { + return $this->code; + } + + /** + * @param int|string $code + * + * @return $this + */ + public function setCode($code): self + { + $this->code = $code; + + return $this; + } + + /** + * @return self|null + */ + public function getPrevious() + { + return $this->previous; + } + + /** + * @return $this + */ + final public function setPrevious(?LegacyFlattenException $previous): self + { + $this->previous = $previous; + + return $this; + } + + /** + * @return self[] + */ + public function getAllPrevious(): array + { + $exceptions = []; + $e = $this; + while ($e = $e->getPrevious()) { + $exceptions[] = $e; + } + + return $exceptions; + } + + public function getTrace(): array + { + return $this->trace; + } + + /** + * @deprecated since 4.1, use {@see setTraceFromThrowable()} instead. + */ + public function setTraceFromException(\Exception $exception) + { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED); + + $this->setTraceFromThrowable($exception); + } + + /** + * @return $this + */ + public function setTraceFromThrowable(\Throwable $throwable): self + { + $this->traceAsString = $throwable->getTraceAsString(); + + return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine()); + } + + /** + * @param array $trace + * @param string|null $file + * @param int|null $line + * + * @return $this + */ + public function setTrace($trace, $file, $line): self + { + $this->trace = []; + $this->trace[] = [ + 'namespace' => '', + 'short_class' => '', + 'class' => '', + 'type' => '', + 'function' => '', + 'file' => $file, + 'line' => $line, + 'args' => [], + ]; + foreach ($trace as $entry) { + $class = ''; + $namespace = ''; + if (isset($entry['class'])) { + $parts = explode('\\', $entry['class']); + $class = array_pop($parts); + $namespace = implode('\\', $parts); + } + + $this->trace[] = [ + 'namespace' => $namespace, + 'short_class' => $class, + 'class' => $entry['class'] ?? '', + 'type' => $entry['type'] ?? '', + 'function' => $entry['function'] ?? null, + 'file' => $entry['file'] ?? null, + 'line' => $entry['line'] ?? null, + 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : [], + ]; + } + + return $this; + } + + private function flattenArgs(array $args, int $level = 0, int &$count = 0): array + { + $result = []; + foreach ($args as $key => $value) { + if (++$count > 1e4) { + return ['array', '*SKIPPED over 10000 entries*']; + } + if ($value instanceof \__PHP_Incomplete_Class) { + // is_object() returns false on PHP<=7.1 + $result[$key] = ['incomplete-object', $this->getClassNameFromIncomplete($value)]; + } elseif (\is_object($value)) { + $result[$key] = ['object', \get_class($value)]; + } elseif (\is_array($value)) { + if ($level > 10) { + $result[$key] = ['array', '*DEEP NESTED ARRAY*']; + } else { + $result[$key] = ['array', $this->flattenArgs($value, $level + 1, $count)]; + } + } elseif (null === $value) { + $result[$key] = ['null', null]; + } elseif (\is_bool($value)) { + $result[$key] = ['boolean', $value]; + } elseif (\is_int($value)) { + $result[$key] = ['integer', $value]; + } elseif (\is_float($value)) { + $result[$key] = ['float', $value]; + } elseif (\is_resource($value)) { + $result[$key] = ['resource', get_resource_type($value)]; + } else { + $result[$key] = ['string', (string) $value]; + } + } + + return $result; + } + + private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value): string + { + $array = new \ArrayObject($value); + + return $array['__PHP_Incomplete_Class_Name']; + } + + public function getTraceAsString(): string + { + return $this->traceAsString; + } + + /** + * @return $this + */ + public function setAsString(?string $asString): self + { + $this->asString = $asString; + + return $this; + } + + public function getAsString(): string + { + if (null !== $this->asString) { + return $this->asString; + } + + $message = ''; + $next = false; + + foreach (array_reverse(array_merge([$this], $this->getAllPrevious())) as $exception) { + if ($next) { + $message .= 'Next '; + } else { + $next = true; + } + $message .= $exception->getClass(); + + if ('' != $exception->getMessage()) { + $message .= ': '.$exception->getMessage(); + } + + $message .= ' in '.$exception->getFile().':'.$exception->getLine(). + "\nStack trace:\n".$exception->getTraceAsString()."\n\n"; + } + + return rtrim($message); + } +} diff --git a/vendor/symfony/error-handler/Exception/SilencedErrorContext.php b/vendor/symfony/error-handler/Exception/SilencedErrorContext.php new file mode 100644 index 00000000..18defc72 --- /dev/null +++ b/vendor/symfony/error-handler/Exception/SilencedErrorContext.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler\Exception; + +/** + * Data Object that represents a Silenced Error. + * + * @author Grégoire Pineau + */ +class SilencedErrorContext implements \JsonSerializable +{ + public $count = 1; + + private $severity; + private $file; + private $line; + private $trace; + + public function __construct(int $severity, string $file, int $line, array $trace = [], int $count = 1) + { + $this->severity = $severity; + $this->file = $file; + $this->line = $line; + $this->trace = $trace; + $this->count = $count; + } + + public function getSeverity(): int + { + return $this->severity; + } + + public function getFile(): string + { + return $this->file; + } + + public function getLine(): int + { + return $this->line; + } + + public function getTrace(): array + { + return $this->trace; + } + + public function jsonSerialize(): array + { + return [ + 'severity' => $this->severity, + 'file' => $this->file, + 'line' => $this->line, + 'trace' => $this->trace, + 'count' => $this->count, + ]; + } +} diff --git a/vendor/symfony/error-handler/LICENSE b/vendor/symfony/error-handler/LICENSE new file mode 100644 index 00000000..9c907a46 --- /dev/null +++ b/vendor/symfony/error-handler/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2019-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/error-handler/README.md b/vendor/symfony/error-handler/README.md new file mode 100644 index 00000000..dd0be15e --- /dev/null +++ b/vendor/symfony/error-handler/README.md @@ -0,0 +1,41 @@ +ErrorHandler Component +====================== + +The ErrorHandler component provides tools to manage errors and ease debugging PHP code. + +Getting Started +--------------- + +``` +$ composer require symfony/error-handler +``` + +```php +use Symfony\Component\ErrorHandler\Debug; +use Symfony\Component\ErrorHandler\ErrorHandler; +use Symfony\Component\ErrorHandler\DebugClassLoader; + +Debug::enable(); + +// or enable only one feature +//ErrorHandler::register(); +//DebugClassLoader::enable(); + +$data = ErrorHandler::call(static function () use ($filename, $datetimeFormat) { + // if any code executed inside this anonymous function fails, a PHP exception + // will be thrown, even if the code uses the '@' PHP silence operator + $data = json_decode(file_get_contents($filename), true); + $data['read_at'] = date($datetimeFormat); + file_put_contents($filename, json_encode($data)); + + return $data; +}); +``` + +Resources +--------- + + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/error-handler/Resources/assets/css/error.css b/vendor/symfony/error-handler/Resources/assets/css/error.css new file mode 100644 index 00000000..332d8187 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/css/error.css @@ -0,0 +1,4 @@ +body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; } +.container { margin: 30px; max-width: 600px; } +h1 { color: #dc3545; font-size: 24px; } +h2 { font-size: 18px; } diff --git a/vendor/symfony/error-handler/Resources/assets/css/exception.css b/vendor/symfony/error-handler/Resources/assets/css/exception.css new file mode 100644 index 00000000..3f629a41 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/css/exception.css @@ -0,0 +1,209 @@ +/* This file is based on WebProfilerBundle/Resources/views/Profiler/profiler.css.twig. + If you make any change in this file, verify the same change is needed in the other file. */ +:root { + --font-sans-serif: Helvetica, Arial, sans-serif; + --page-background: #f9f9f9; + --color-text: #222; + /* when updating any of these colors, do the same in toolbar.css.twig */ + --color-success: #4f805d; + --color-warning: #a46a1f; + --color-error: #b0413e; + --color-muted: #999; + --tab-background: #fff; + --tab-color: #444; + --tab-active-background: #666; + --tab-active-color: #fafafa; + --tab-disabled-background: #f5f5f5; + --tab-disabled-color: #999; + --metric-value-background: #fff; + --metric-value-color: inherit; + --metric-unit-color: #999; + --metric-label-background: #e0e0e0; + --metric-label-color: inherit; + --table-border: #e0e0e0; + --table-background: #fff; + --table-header: #e0e0e0; + --trace-selected-background: #F7E5A1; + --tree-active-background: #F7E5A1; + --exception-title-color: var(--base-2); + --shadow: 0px 0px 1px rgba(128, 128, 128, .2); + --border: 1px solid #e0e0e0; + --background-error: var(--color-error); + --highlight-comment: #969896; + --highlight-default: #222222; + --highlight-keyword: #a71d5d; + --highlight-string: #183691; + --base-0: #fff; + --base-1: #f5f5f5; + --base-2: #e0e0e0; + --base-3: #ccc; + --base-4: #666; + --base-5: #444; + --base-6: #222; +} + +html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{margin:.67em 0;font-size:2em}mark{color:#000;background:#ff0}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{height:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{margin:0;font:inherit;color:inherit}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid silver}legend{padding:0;border:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-spacing:0;border-collapse:collapse}td,th{padding:0} + +html { + /* always display the vertical scrollbar to avoid jumps when toggling contents */ + overflow-y: scroll; +} +body { background-color: #F9F9F9; color: var(--base-6); font: 14px/1.4 Helvetica, Arial, sans-serif; padding-bottom: 45px; } + +a { cursor: pointer; text-decoration: none; } +a:hover { text-decoration: underline; } +abbr[title] { border-bottom: none; cursor: help; text-decoration: none; } + +code, pre { font: 13px/1.5 Consolas, Monaco, Menlo, "Ubuntu Mono", "Liberation Mono", monospace; } + +table, tr, th, td { background: #FFF; border-collapse: collapse; vertical-align: top; } +table { background: #FFF; border: var(--border); box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; width: 100%; } +table th, table td { border: solid var(--base-2); border-width: 1px 0; padding: 8px 10px; } +table th { background-color: var(--base-2); font-weight: bold; text-align: left; } + +.m-t-5 { margin-top: 5px; } +.hidden-xs-down { display: none; } +.block { display: block; } +.full-width { width: 100%; } +.hidden { display: none; } +.prewrap { white-space: pre-wrap; } +.nowrap { white-space: nowrap; } +.newline { display: block; } +.break-long-words { word-wrap: break-word; overflow-wrap: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; min-width: 0; } +.text-small { font-size: 12px !important; } +.text-muted { color: #999; } +.text-bold { font-weight: bold; } +.empty { border: 4px dashed var(--base-2); color: #999; margin: 1em 0; padding: .5em 2em; } + +.status-success { background: rgba(94, 151, 110, 0.3); } +.status-warning { background: rgba(240, 181, 24, 0.3); } +.status-error { background: rgba(176, 65, 62, 0.2); } +.status-success td, .status-warning td, .status-error td { background: transparent; } +tr.status-error td, tr.status-warning td { border-bottom: 1px solid #FAFAFA; border-top: 1px solid #FAFAFA; } +.status-warning .colored { color: #A46A1F; } +.status-error .colored { color: var(--color-error); } + +.sf-toggle { cursor: pointer; } +.sf-toggle-content { -moz-transition: display .25s ease; -webkit-transition: display .25s ease; transition: display .25s ease; } +.sf-toggle-content.sf-toggle-hidden { display: none; } +.sf-toggle-content.sf-toggle-visible { display: block; } +thead.sf-toggle-content.sf-toggle-visible, tbody.sf-toggle-content.sf-toggle-visible { display: table-row-group; } +.sf-toggle-off .icon-close, .sf-toggle-on .icon-open { display: none; } +.sf-toggle-off .icon-open, .sf-toggle-on .icon-close { display: block; } + +.tab-navigation { margin: 0 0 1em 0; padding: 0; } +.tab-navigation li { background: var(--tab-background); border: 1px solid var(--table-border); color: var(--tab-color); cursor: pointer; display: inline-block; font-size: 16px; margin: 0 0 0 -1px; padding: .5em .75em; z-index: 1; } +.tab-navigation li .badge { background-color: var(--base-1); color: var(--base-4); display: inline-block; font-size: 14px; font-weight: bold; margin-left: 8px; min-width: 10px; padding: 1px 6px; text-align: center; white-space: nowrap; } +.tab-navigation li.disabled { background: var(--tab-disabled-background); color: var(--tab-disabled-color); } +.tab-navigation li.active { background: var(--tab-active-background); color: var(--tab-active-color); z-index: 1100; } +.tab-navigation li.active .badge { background-color: var(--base-5); color: var(--base-2); } +.tab-content > *:first-child { margin-top: 0; } +.tab-navigation li .badge.status-warning { background: var(--color-warning); color: #FFF; } +.tab-navigation li .badge.status-error { background: var(--background-error); color: #FFF; } +.sf-tabs .tab:not(:first-child) { display: none; } + +[data-filters] { position: relative; } +[data-filtered] { cursor: pointer; } +[data-filtered]:after { content: '\00a0\25BE'; } +[data-filtered]:hover .filter-list li { display: inline-flex; } +[class*="filter-hidden-"] { display: none; } +.filter-list { position: absolute; border: var(--border); box-shadow: var(--shadow); margin: 0; padding: 0; display: flex; flex-direction: column; } +.filter-list :after { content: ''; } +.filter-list li { + background: var(--tab-disabled-background); + border-bottom: var(--border); + color: var(--tab-disabled-color); + display: none; + list-style: none; + margin: 0; + padding: 5px 10px; + text-align: left; + font-weight: normal; +} +.filter-list li.active { + background: var(--tab-background); + color: var(--tab-color); +} +.filter-list li.last-active { + background: var(--tab-active-background); + color: var(--tab-active-color); +} + +.filter-list-level li { cursor: s-resize; } +.filter-list-level li.active { cursor: n-resize; } +.filter-list-level li.last-active { cursor: default; } +.filter-list-level li.last-active:before { content: '\2714\00a0'; } +.filter-list-choice li:before { content: '\2714\00a0'; color: transparent; } +.filter-list-choice li.active:before { color: unset; } + +.container { max-width: 1024px; margin: 0 auto; padding: 0 15px; } +.container::after { content: ""; display: table; clear: both; } + +header { background-color: var(--base-6); color: rgba(255, 255, 255, 0.75); font-size: 13px; height: 33px; line-height: 33px; padding: 0; } +header .container { display: flex; justify-content: space-between; } +.logo { flex: 1; font-size: 13px; font-weight: normal; margin: 0; padding: 0; } +.logo svg { height: 18px; width: 18px; opacity: .8; vertical-align: -5px; } + +.help-link { margin-left: 15px; } +.help-link a { color: inherit; } +.help-link .icon svg { height: 15px; width: 15px; opacity: .7; vertical-align: -2px; } +.help-link a:hover { color: #EEE; text-decoration: none; } +.help-link a:hover svg { opacity: .9; } + +.exception-summary { background: var(--background-error); border-bottom: 2px solid rgba(0, 0, 0, 0.1); border-top: 1px solid rgba(0, 0, 0, .3); flex: 0 0 auto; margin-bottom: 15px; } +.exception-metadata { background: rgba(0, 0, 0, 0.1); padding: 7px 0; } +.exception-metadata .container { display: flex; flex-direction: row; justify-content: space-between; } +.exception-metadata h2, .exception-metadata h2 > a { color: rgba(255, 255, 255, 0.8); font-size: 13px; font-weight: 400; margin: 0; } +.exception-http small { font-size: 13px; opacity: .7; } +.exception-hierarchy { flex: 1; } +.exception-hierarchy .icon { margin: 0 3px; opacity: .7; } +.exception-hierarchy .icon svg { height: 13px; width: 13px; vertical-align: -2px; } + +.exception-without-message .exception-message-wrapper { display: none; } +.exception-message-wrapper .container { display: flex; align-items: flex-start; min-height: 70px; padding: 10px 15px 8px; } +.exception-message { flex-grow: 1; } +.exception-message, .exception-message a { color: #FFF; font-size: 21px; font-weight: 400; margin: 0; } +.exception-message.long { font-size: 18px; } +.exception-message a { border-bottom: 1px solid rgba(255, 255, 255, 0.5); font-size: inherit; text-decoration: none; } +.exception-message a:hover { border-bottom-color: #ffffff; } + +.exception-illustration { flex-basis: 111px; flex-shrink: 0; height: 66px; margin-left: 15px; opacity: .7; } + +.trace + .trace { margin-top: 30px; } +.trace-head { background-color: var(--base-2); padding: 10px; position: relative; } +.trace-head .trace-class { color: var(--base-6); font-size: 18px; font-weight: bold; line-height: 1.3; margin: 0; position: relative; } +.trace-head .trace-namespace { color: #999; display: block; font-size: 13px; } +.trace-head .icon { position: absolute; right: 0; top: 0; } +.trace-head .icon svg { height: 24px; width: 24px; } + +.trace-details { background: var(--base-0); border: var(--border); box-shadow: 0px 0px 1px rgba(128, 128, 128, .2); margin: 1em 0; table-layout: fixed; } + +.trace-message { font-size: 14px; font-weight: normal; margin: .5em 0 0; } + +.trace-line { position: relative; padding-top: 8px; padding-bottom: 8px; } +.trace-line + .trace-line { border-top: var(--border); } +.trace-line:hover { background: var(--base-1); } +.trace-line a { color: var(--base-6); } +.trace-line .icon { opacity: .4; position: absolute; left: 10px; } +.trace-line .icon svg { height: 16px; width: 16px; } +.trace-line-header { padding-left: 36px; padding-right: 10px; } + +.trace-file-path, .trace-file-path a { color: var(--base-6); font-size: 13px; } +.trace-class { color: var(--color-error); } +.trace-type { padding: 0 2px; } +.trace-method { color: var(--color-error); font-weight: bold; } +.trace-arguments { color: #777; font-weight: normal; padding-left: 2px; } + +.trace-code { background: var(--base-0); font-size: 12px; margin: 10px 10px 2px 10px; padding: 10px; overflow-x: auto; white-space: nowrap; } +.trace-code ol { margin: 0; float: left; } +.trace-code li { color: #969896; margin: 0; padding-left: 10px; float: left; width: 100%; } +.trace-code li + li { margin-top: 5px; } +.trace-code li.selected { background: var(--trace-selected-background); margin-top: 2px; } +.trace-code li code { color: var(--base-6); white-space: nowrap; } + +.trace-as-text .stacktrace { line-height: 1.8; margin: 0 0 15px; white-space: pre-wrap; } + +@media (min-width: 575px) { + .hidden-xs-down { display: initial; } + .help-link { margin-left: 30px; } +} diff --git a/vendor/symfony/error-handler/Resources/assets/css/exception_full.css b/vendor/symfony/error-handler/Resources/assets/css/exception_full.css new file mode 100644 index 00000000..fa77cb32 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/css/exception_full.css @@ -0,0 +1,128 @@ +.sf-reset .traces { + padding-bottom: 14px; +} +.sf-reset .traces li { + font-size: 12px; + color: #868686; + padding: 5px 4px; + list-style-type: decimal; + margin-left: 20px; +} +.sf-reset #logs .traces li.error { + font-style: normal; + color: #AA3333; + background: #f9ecec; +} +.sf-reset #logs .traces li.warning { + font-style: normal; + background: #ffcc00; +} +/* fix for Opera not liking empty
  • */ +.sf-reset .traces li:after { + content: "\00A0"; +} +.sf-reset .trace { + border: 1px solid #D3D3D3; + padding: 10px; + overflow: auto; + margin: 10px 0 20px; +} +.sf-reset .block-exception { + -moz-border-radius: 16px; + -webkit-border-radius: 16px; + border-radius: 16px; + margin-bottom: 20px; + background-color: #f6f6f6; + border: 1px solid #dfdfdf; + padding: 30px 28px; + word-wrap: break-word; + overflow: hidden; +} +.sf-reset .block-exception div { + color: #313131; + font-size: 10px; +} +.sf-reset .block-exception-detected .illustration-exception, +.sf-reset .block-exception-detected .text-exception { + float: left; +} +.sf-reset .block-exception-detected .illustration-exception { + width: 152px; +} +.sf-reset .block-exception-detected .text-exception { + width: 670px; + padding: 30px 44px 24px 46px; + position: relative; +} +.sf-reset .text-exception .open-quote, +.sf-reset .text-exception .close-quote { + font-family: Arial, Helvetica, sans-serif; + position: absolute; + color: #C9C9C9; + font-size: 8em; +} +.sf-reset .open-quote { + top: 0; + left: 0; +} +.sf-reset .close-quote { + bottom: -0.5em; + right: 50px; +} +.sf-reset .block-exception p { + font-family: Arial, Helvetica, sans-serif; +} +.sf-reset .block-exception p a, +.sf-reset .block-exception p a:hover { + color: #565656; +} +.sf-reset .logs h2 { + float: left; + width: 654px; +} +.sf-reset .error-count, .sf-reset .support { + float: right; + width: 170px; + text-align: right; +} +.sf-reset .error-count span { + display: inline-block; + background-color: #aacd4e; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: 4px; + color: white; + margin-right: 2px; + font-size: 11px; + font-weight: bold; +} + +.sf-reset .support a { + display: inline-block; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + border-radius: 6px; + padding: 4px; + color: #000000; + margin-right: 2px; + font-size: 11px; + font-weight: bold; +} + +.sf-reset .toggle { + vertical-align: middle; +} +.sf-reset .linked ul, +.sf-reset .linked li { + display: inline; +} +.sf-reset #output-content { + color: #000; + font-size: 12px; +} +.sf-reset #traces-text pre { + white-space: pre; + font-size: 12px; + font-family: monospace; +} diff --git a/vendor/symfony/error-handler/Resources/assets/images/chevron-right.svg b/vendor/symfony/error-handler/Resources/assets/images/chevron-right.svg new file mode 100644 index 00000000..6837aff1 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/chevron-right.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/favicon.png.base64 b/vendor/symfony/error-handler/Resources/assets/images/favicon.png.base64 new file mode 100644 index 00000000..fb076ed1 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/favicon.png.base64 @@ -0,0 +1 @@ +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAgCAYAAAABtRhCAAADVUlEQVRIx82XX0jTURTHLYPyqZdefQx66CEo80+aYpoIkqzUikz6Z5klQoWUWYRIJYEUGpQ+lIr9U5dOTLdCtkmWZis3rbnC5fw/neYW002307mX/cZvP3/7o1PwwOdh95x7vnf39zvnd29AgBer2xO6DclAXiMqZAqxIiNIN/IYSUS2BPhjmGATchUxI+ADWiRhpWK7HKuHFVBFdmU5YvnI4grFGCaReF/EBH4KsZlGgj2JBTuCYBWRIYF8YoEOJ6wBt/gEs7mBbyOjQXruPLSdOgPCiEiPSUUHDoL8Ug5IUo9B/d5wrt+G7OAKNrODPuVdB6vRCIzN6SdBlpW9RIgk/1FeAXabzRlrUPVCS/JhbmwudztnGeeH9AyXBIwtmM3wLinZJZHifjHw2V+NBoRh+9ixQrbgbnaSIcl7cGea6hoXQbNe7za241oeO5Z0p42M4BV2EqP2D50wo+6HzvwC6C4sApNOR8cmOrtcnhtj2kYRyC9eBvXzKrBZrXSs72kFd1t3MoKVbMekQkEnSNKOO8fac3LpmK6l1TlGtsxmsdKFsecPYgwxst0cwROMYDXboSotg0WLBRqjY51jLYcENElXwW2XJKPydvoI2GN9T8rBtrAArYIUruBJXkFheCQYlCpQP6uk5dAQFQNaUROMSGVQFxLmkoQsxDJrhLbTZ+nvVsERME9MgPJRKV/58AsyomTSzE813WLFvWK++qI0xSfQl8k8Pg46sYRuv5t6dS+4RqxDwaa4BGjYH+NTQvKScIp9+YL/hoZh3jDtLRHtt2C3g6bmhX+CpsFBWg7ilDSPgj0lD2ncr5ev/BP8VvyAJhqVyZeUhPOrEhEFxgEtjft846Z/guQTNT89Q5P9flMLoth4F7808wKtWWKzAwNQHxrh/1vaid2F+XpYTSbQf1XA2McOmOpROnvpvMEA4tSjq1cW0sws2gCYxswY6TKkvzYnJq1NHZLnRU4BX+4U0uburvusu8Kv8iHY7qefkM4IFngJHEOUXmLEPgiGsI8YnlZILit3vSSLRTQe/MPIZva5pshNIEmyFQlCvruJKXPkCEfmePzkphXHdzZNQdoRI9KPlBAxlj/I8U97ERPS5bjGbWDFbEdqHVe5caTBeZZx2H/IMvzeN15yoQAAAABJRU5ErkJggg== diff --git a/vendor/symfony/error-handler/Resources/assets/images/icon-book.svg b/vendor/symfony/error-handler/Resources/assets/images/icon-book.svg new file mode 100644 index 00000000..498a74f4 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/icon-book.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/icon-minus-square-o.svg b/vendor/symfony/error-handler/Resources/assets/images/icon-minus-square-o.svg new file mode 100644 index 00000000..be534ad4 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/icon-minus-square-o.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/icon-minus-square.svg b/vendor/symfony/error-handler/Resources/assets/images/icon-minus-square.svg new file mode 100644 index 00000000..471c2741 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/icon-minus-square.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/icon-plus-square-o.svg b/vendor/symfony/error-handler/Resources/assets/images/icon-plus-square-o.svg new file mode 100644 index 00000000..b2593a9f --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/icon-plus-square-o.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/icon-plus-square.svg b/vendor/symfony/error-handler/Resources/assets/images/icon-plus-square.svg new file mode 100644 index 00000000..2f5c3b35 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/icon-plus-square.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/icon-support.svg b/vendor/symfony/error-handler/Resources/assets/images/icon-support.svg new file mode 100644 index 00000000..03fd8e76 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/icon-support.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/images/symfony-ghost.svg.php b/vendor/symfony/error-handler/Resources/assets/images/symfony-ghost.svg.php new file mode 100644 index 00000000..4b2f9c1b --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/symfony-ghost.svg.php @@ -0,0 +1 @@ +addElementToGhost(); ?> diff --git a/vendor/symfony/error-handler/Resources/assets/images/symfony-logo.svg b/vendor/symfony/error-handler/Resources/assets/images/symfony-logo.svg new file mode 100644 index 00000000..f10824ae --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/images/symfony-logo.svg @@ -0,0 +1 @@ + diff --git a/vendor/symfony/error-handler/Resources/assets/js/exception.js b/vendor/symfony/error-handler/Resources/assets/js/exception.js new file mode 100644 index 00000000..0720a3a3 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/assets/js/exception.js @@ -0,0 +1,280 @@ +/* This file is based on WebProfilerBundle/Resources/views/Profiler/base_js.html.twig. + If you make any change in this file, verify the same change is needed in the other file. */ +/* .tab'); + var tabNavigation = document.createElement('ul'); + tabNavigation.className = 'tab-navigation'; + + var selectedTabId = 'tab-' + i + '-0'; /* select the first tab by default */ + for (var j = 0; j < tabs.length; j++) { + var tabId = 'tab-' + i + '-' + j; + var tabTitle = tabs[j].querySelector('.tab-title').innerHTML; + + var tabNavigationItem = document.createElement('li'); + tabNavigationItem.setAttribute('data-tab-id', tabId); + if (hasClass(tabs[j], 'active')) { selectedTabId = tabId; } + if (hasClass(tabs[j], 'disabled')) { addClass(tabNavigationItem, 'disabled'); } + tabNavigationItem.innerHTML = tabTitle; + tabNavigation.appendChild(tabNavigationItem); + + var tabContent = tabs[j].querySelector('.tab-content'); + tabContent.parentElement.setAttribute('id', tabId); + } + + tabGroups[i].insertBefore(tabNavigation, tabGroups[i].firstChild); + addClass(document.querySelector('[data-tab-id="' + selectedTabId + '"]'), 'active'); + } + + /* display the active tab and add the 'click' event listeners */ + for (i = 0; i < tabGroups.length; i++) { + tabNavigation = tabGroups[i].querySelectorAll(':scope >.tab-navigation li'); + + for (j = 0; j < tabNavigation.length; j++) { + tabId = tabNavigation[j].getAttribute('data-tab-id'); + document.getElementById(tabId).querySelector('.tab-title').className = 'hidden'; + + if (hasClass(tabNavigation[j], 'active')) { + document.getElementById(tabId).className = 'block'; + } else { + document.getElementById(tabId).className = 'hidden'; + } + + tabNavigation[j].addEventListener('click', function(e) { + var activeTab = e.target || e.srcElement; + + /* needed because when the tab contains HTML contents, user can click */ + /* on any of those elements instead of their parent '
  • ' element */ + while (activeTab.tagName.toLowerCase() !== 'li') { + activeTab = activeTab.parentNode; + } + + /* get the full list of tabs through the parent of the active tab element */ + var tabNavigation = activeTab.parentNode.children; + for (var k = 0; k < tabNavigation.length; k++) { + var tabId = tabNavigation[k].getAttribute('data-tab-id'); + document.getElementById(tabId).className = 'hidden'; + removeClass(tabNavigation[k], 'active'); + } + + addClass(activeTab, 'active'); + var activeTabId = activeTab.getAttribute('data-tab-id'); + document.getElementById(activeTabId).className = 'block'; + }); + } + + tabGroups[i].setAttribute('data-processed', 'true'); + } + }, + + createToggles: function() { + var toggles = document.querySelectorAll('.sf-toggle:not([data-processed=true])'); + + for (var i = 0; i < toggles.length; i++) { + var elementSelector = toggles[i].getAttribute('data-toggle-selector'); + var element = document.querySelector(elementSelector); + + addClass(element, 'sf-toggle-content'); + + if (toggles[i].hasAttribute('data-toggle-initial') && toggles[i].getAttribute('data-toggle-initial') == 'display') { + addClass(toggles[i], 'sf-toggle-on'); + addClass(element, 'sf-toggle-visible'); + } else { + addClass(toggles[i], 'sf-toggle-off'); + addClass(element, 'sf-toggle-hidden'); + } + + addEventListener(toggles[i], 'click', function(e) { + e.preventDefault(); + + if ('' !== window.getSelection().toString()) { + /* Don't do anything on text selection */ + return; + } + + var toggle = e.target || e.srcElement; + + /* needed because when the toggle contains HTML contents, user can click */ + /* on any of those elements instead of their parent '.sf-toggle' element */ + while (!hasClass(toggle, 'sf-toggle')) { + toggle = toggle.parentNode; + } + + var element = document.querySelector(toggle.getAttribute('data-toggle-selector')); + + toggleClass(toggle, 'sf-toggle-on'); + toggleClass(toggle, 'sf-toggle-off'); + toggleClass(element, 'sf-toggle-hidden'); + toggleClass(element, 'sf-toggle-visible'); + + /* the toggle doesn't change its contents when clicking on it */ + if (!toggle.hasAttribute('data-toggle-alt-content')) { + return; + } + + if (!toggle.hasAttribute('data-toggle-original-content')) { + toggle.setAttribute('data-toggle-original-content', toggle.innerHTML); + } + + var currentContent = toggle.innerHTML; + var originalContent = toggle.getAttribute('data-toggle-original-content'); + var altContent = toggle.getAttribute('data-toggle-alt-content'); + toggle.innerHTML = currentContent !== altContent ? altContent : originalContent; + }); + + /* Prevents from disallowing clicks on links inside toggles */ + var toggleLinks = toggles[i].querySelectorAll('a'); + for (var j = 0; j < toggleLinks.length; j++) { + addEventListener(toggleLinks[j], 'click', function(e) { + e.stopPropagation(); + }); + } + + toggles[i].setAttribute('data-processed', 'true'); + } + }, + + createFilters: function() { + document.querySelectorAll('[data-filters] [data-filter]').forEach(function (filter) { + var filters = filter.closest('[data-filters]'), + type = 'choice', + name = filter.dataset.filter, + ucName = name.charAt(0).toUpperCase()+name.slice(1), + list = document.createElement('ul'), + values = filters.dataset['filter'+ucName] || filters.querySelectorAll('[data-filter-'+name+']'), + labels = {}, + defaults = null, + indexed = {}, + processed = {}; + if (typeof values === 'string') { + type = 'level'; + labels = values.split(','); + values = values.toLowerCase().split(','); + defaults = values.length - 1; + } + addClass(list, 'filter-list'); + addClass(list, 'filter-list-'+type); + values.forEach(function (value, i) { + if (value instanceof HTMLElement) { + value = value.dataset['filter'+ucName]; + } + if (value in processed) { + return; + } + var option = document.createElement('li'), + label = i in labels ? labels[i] : value, + active = false, + matches; + if ('' === label) { + option.innerHTML = '(none)'; + } else { + option.innerText = label; + } + option.dataset.filter = value; + option.setAttribute('title', 1 === (matches = filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').length) ? 'Matches 1 row' : 'Matches '+matches+' rows'); + indexed[value] = i; + list.appendChild(option); + addEventListener(option, 'click', function () { + if ('choice' === type) { + filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { + if (option.dataset.filter === row.dataset['filter'+ucName]) { + toggleClass(row, 'filter-hidden-'+name); + } + }); + toggleClass(option, 'active'); + } else if ('level' === type) { + if (i === this.parentNode.querySelectorAll('.active').length - 1) { + return; + } + this.parentNode.querySelectorAll('li').forEach(function (currentOption, j) { + if (j <= i) { + addClass(currentOption, 'active'); + if (i === j) { + addClass(currentOption, 'last-active'); + } else { + removeClass(currentOption, 'last-active'); + } + } else { + removeClass(currentOption, 'active'); + removeClass(currentOption, 'last-active'); + } + }); + filters.querySelectorAll('[data-filter-'+name+']').forEach(function (row) { + if (i < indexed[row.dataset['filter'+ucName]]) { + addClass(row, 'filter-hidden-'+name); + } else { + removeClass(row, 'filter-hidden-'+name); + } + }); + } + }); + if ('choice' === type) { + active = null === defaults || 0 <= defaults.indexOf(value); + } else if ('level' === type) { + active = i <= defaults; + if (active && i === defaults) { + addClass(option, 'last-active'); + } + } + if (active) { + addClass(option, 'active'); + } else { + filters.querySelectorAll('[data-filter-'+name+'="'+value+'"]').forEach(function (row) { + toggleClass(row, 'filter-hidden-'+name); + }); + } + processed[value] = true; + }); + + if (1 < list.childNodes.length) { + filter.appendChild(list); + filter.dataset.filtered = ''; + } + }); + } + }; + })(); + + Sfjs.addEventListener(document, 'DOMContentLoaded', function() { + Sfjs.createTabs(); + Sfjs.createToggles(); + Sfjs.createFilters(); + }); +} +/*]]>*/ diff --git a/vendor/symfony/error-handler/Resources/views/error.html.php b/vendor/symfony/error-handler/Resources/views/error.html.php new file mode 100644 index 00000000..5416d03c --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/error.html.php @@ -0,0 +1,20 @@ + + + + + + An Error Occurred: <?= $statusText; ?> + + + +
    +

    Oops! An Error Occurred

    +

    The server returned a " ".

    + +

    + Something is broken. Please let us know what you were doing when this error occurred. + We will fix it as soon as possible. Sorry for any inconvenience caused. +

    +
    + + diff --git a/vendor/symfony/error-handler/Resources/views/exception.html.php b/vendor/symfony/error-handler/Resources/views/exception.html.php new file mode 100644 index 00000000..c3e7a867 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/exception.html.php @@ -0,0 +1,116 @@ +
    + + +
    +
    +

    formatFileFromText(nl2br($exceptionMessage)); ?>

    + +
    + include('assets/images/symfony-ghost.svg.php'); ?> +
    +
    +
    +
    + +
    +
    +
    + toArray(); + $exceptionWithUserCode = []; + $exceptionAsArrayCount = count($exceptionAsArray); + $last = $exceptionAsArrayCount - 1; + foreach ($exceptionAsArray as $i => $e) { + foreach ($e['trace'] as $trace) { + if ($trace['file'] && false === mb_strpos($trace['file'], '/vendor/') && false === mb_strpos($trace['file'], '/var/cache/') && $i < $last) { + $exceptionWithUserCode[] = $i; + } + } + } + ?> +

    + 1) { ?> + Exceptions + + Exception + +

    + +
    + $e) { + echo $this->include('views/traces.html.php', [ + 'exception' => $e, + 'index' => $i + 1, + 'expand' => in_array($i, $exceptionWithUserCode, true) || ([] === $exceptionWithUserCode && 0 === $i), + ]); + } + ?> +
    +
    + + +
    +

    + Logs + countErrors()) { ?>countErrors(); ?> +

    + +
    + getLogs()) { ?> + include('views/logs.html.php', ['logs' => $logger->getLogs()]); ?> + +
    +

    No log messages

    +
    + +
    +
    + + +
    +

    + 1) { ?> + Stack Traces + + Stack Trace + +

    + +
    + $e) { + echo $this->include('views/traces_text.html.php', [ + 'exception' => $e, + 'index' => $i + 1, + 'numExceptions' => $exceptionAsArrayCount, + ]); + } + ?> +
    +
    + + +
    +

    Output content

    + +
    + +
    +
    + +
    +
    diff --git a/vendor/symfony/error-handler/Resources/views/exception_full.html.php b/vendor/symfony/error-handler/Resources/views/exception_full.html.php new file mode 100644 index 00000000..cb5a5675 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/exception_full.html.php @@ -0,0 +1,36 @@ + + + + + + + + <?= $_message; ?> + + + + + + +
    +
    +

    include('assets/images/symfony-logo.svg'); ?> Symfony Exception

    + + +
    +
    + + + include('views/exception.html.php', $context); ?> + + + + + diff --git a/vendor/symfony/error-handler/Resources/views/logs.html.php b/vendor/symfony/error-handler/Resources/views/logs.html.php new file mode 100644 index 00000000..bd2dbe2f --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/logs.html.php @@ -0,0 +1,45 @@ + + + + + + + + + + + + = 400) { + $status = 'error'; + } elseif ($log['priority'] >= 300) { + $status = 'warning'; + } else { + $severity = 0; + if (($exception = $log['context']['exception'] ?? null) instanceof \ErrorException || $exception instanceof \Symfony\Component\ErrorHandler\Exception\SilencedErrorContext) { + $severity = $exception->getSeverity(); + } + $status = \E_DEPRECATED === $severity || \E_USER_DEPRECATED === $severity ? 'warning' : 'normal'; + } ?> + data-filter-channel="escape($log['channel']); ?>"> + + + + + + + + +
    LevelChannelMessage
    + escape($log['priorityName']); ?> + + + escape($log['channel']); ?> + + formatLogMessage($log['message'], $log['context']); ?> + +
    escape(json_encode($log['context'], \JSON_PRETTY_PRINT | \JSON_UNESCAPED_UNICODE | \JSON_UNESCAPED_SLASHES)); ?>
    + +
    diff --git a/vendor/symfony/error-handler/Resources/views/trace.html.php b/vendor/symfony/error-handler/Resources/views/trace.html.php new file mode 100644 index 00000000..6b4261f3 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/trace.html.php @@ -0,0 +1,40 @@ +
    + + include('assets/images/icon-minus-square.svg'); ?> + include('assets/images/icon-plus-square.svg'); ?> + + + + abbrClass($trace['class']); ?>(formatArgs($trace['args']); ?>) + + + + getFileLink($trace['file'], $lineNumber); + $filePath = strtr(strip_tags($this->formatFile($trace['file'], $lineNumber)), [' at line '.$lineNumber => '']); + $filePathParts = explode(\DIRECTORY_SEPARATOR, $filePath); + ?> + + in + + + + + + + + (line ) + + +
    + +
    + fileExcerpt($trace['file'], $trace['line'], 5), [ + '#DD0000' => 'var(--highlight-string)', + '#007700' => 'var(--highlight-keyword)', + '#0000BB' => 'var(--highlight-default)', + '#FF8000' => 'var(--highlight-comment)', + ]); ?> +
    + diff --git a/vendor/symfony/error-handler/Resources/views/traces.html.php b/vendor/symfony/error-handler/Resources/views/traces.html.php new file mode 100644 index 00000000..d587b058 --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/traces.html.php @@ -0,0 +1,42 @@ +
    +
    +
    + +

    + include('assets/images/icon-minus-square-o.svg'); ?> + include('assets/images/icon-plus-square-o.svg'); ?> + + + 1 ? '\\' : ''; ?> + + +

    + + 1) { ?> +

    escape($exception['message']); ?>

    + +
    +
    + +
    + $trace) { + $isVendorTrace = $trace['file'] && (false !== mb_strpos($trace['file'], '/vendor/') || false !== mb_strpos($trace['file'], '/var/cache/')); + $displayCodeSnippet = $isFirstUserCode && !$isVendorTrace; + if ($displayCodeSnippet) { + $isFirstUserCode = false; + } ?> +
    + include('views/trace.html.php', [ + 'prefix' => $index, + 'i' => $i, + 'trace' => $trace, + 'style' => $isVendorTrace ? 'compact' : ($displayCodeSnippet ? 'expanded' : ''), + ]); ?> +
    + +
    +
    +
    diff --git a/vendor/symfony/error-handler/Resources/views/traces_text.html.php b/vendor/symfony/error-handler/Resources/views/traces_text.html.php new file mode 100644 index 00000000..a7090fbe --- /dev/null +++ b/vendor/symfony/error-handler/Resources/views/traces_text.html.php @@ -0,0 +1,43 @@ + + + + + + + + + + + + +
    +

    + 1) { ?> + [/] + + + include('assets/images/icon-minus-square-o.svg'); ?> + include('assets/images/icon-plus-square-o.svg'); ?> +

    +
    + +
    +escape($exception['class']).":\n";
    +                    if ($exception['message']) {
    +                        echo $this->escape($exception['message'])."\n";
    +                    }
    +
    +                    foreach ($exception['trace'] as $trace) {
    +                        echo "\n  ";
    +                        if ($trace['function']) {
    +                            echo $this->escape('at '.$trace['class'].$trace['type'].$trace['function']).'('.(isset($trace['args']) ? $this->formatArgsAsText($trace['args']) : '').')';
    +                        }
    +                        if ($trace['file'] && $trace['line']) {
    +                            echo($trace['function'] ? "\n     (" : 'at ').strtr(strip_tags($this->formatFile($trace['file'], $trace['line'])), [' at line '.$trace['line'] => '']).':'.$trace['line'].($trace['function'] ? ')' : '');
    +                        }
    +                    }
    +?>
    +                
    + +
    diff --git a/vendor/symfony/error-handler/ThrowableUtils.php b/vendor/symfony/error-handler/ThrowableUtils.php new file mode 100644 index 00000000..18d04988 --- /dev/null +++ b/vendor/symfony/error-handler/ThrowableUtils.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\ErrorHandler; + +use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; + +/** + * @internal + */ +class ThrowableUtils +{ + /** + * @param SilencedErrorContext|\Throwable + */ + public static function getSeverity($throwable): int + { + if ($throwable instanceof \ErrorException || $throwable instanceof SilencedErrorContext) { + return $throwable->getSeverity(); + } + + if ($throwable instanceof \ParseError) { + return \E_PARSE; + } + + if ($throwable instanceof \TypeError) { + return \E_RECOVERABLE_ERROR; + } + + return \E_ERROR; + } +} diff --git a/vendor/symfony/error-handler/composer.json b/vendor/symfony/error-handler/composer.json new file mode 100644 index 00000000..ef829f6d --- /dev/null +++ b/vendor/symfony/error-handler/composer.json @@ -0,0 +1,35 @@ +{ + "name": "symfony/error-handler", + "type": "library", + "description": "Provides tools to manage errors and ease debugging PHP code", + "keywords": [], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1.3", + "psr/log": "^1|^2|^3", + "symfony/debug": "^4.4.5", + "symfony/var-dumper": "^4.4|^5.0" + }, + "require-dev": { + "symfony/http-kernel": "^4.4|^5.0", + "symfony/serializer": "^4.4|^5.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\ErrorHandler\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +} diff --git a/vendor/symfony/dependency-injection/.gitignore b/vendor/symfony/event-dispatcher-contracts/.gitignore similarity index 100% rename from vendor/symfony/dependency-injection/.gitignore rename to vendor/symfony/event-dispatcher-contracts/.gitignore diff --git a/vendor/symfony/event-dispatcher-contracts/Event.php b/vendor/symfony/event-dispatcher-contracts/Event.php new file mode 100644 index 00000000..84f60f3e --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/Event.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; + +if (interface_exists(StoppableEventInterface::class)) { + /** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Nicolas Grekas + */ + class Event implements StoppableEventInterface + { + private $propagationStopped = false; + + /** + * Returns whether further event listeners should be triggered. + */ + public function isPropagationStopped(): bool + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + */ + public function stopPropagation(): void + { + $this->propagationStopped = true; + } + } +} else { + /** + * Event is the base class for classes containing event data. + * + * This class contains no event data. It is used by events that do not pass + * state information to an event handler when an event is raised. + * + * You can call the method stopPropagation() to abort the execution of + * further listeners in your event listener. + * + * @author Guilherme Blanco + * @author Jonathan Wage + * @author Roman Borschel + * @author Bernhard Schussek + * @author Nicolas Grekas + */ + class Event + { + private $propagationStopped = false; + + /** + * Returns whether further event listeners should be triggered. + */ + public function isPropagationStopped(): bool + { + return $this->propagationStopped; + } + + /** + * Stops the propagation of the event to further event listeners. + * + * If multiple event listeners are connected to the same event, no + * further event listener will be triggered once any trigger calls + * stopPropagation(). + */ + public function stopPropagation(): void + { + $this->propagationStopped = true; + } + } +} diff --git a/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php new file mode 100644 index 00000000..2d470af9 --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\EventDispatcher; + +use Psr\EventDispatcher\EventDispatcherInterface as PsrEventDispatcherInterface; + +if (interface_exists(PsrEventDispatcherInterface::class)) { + /** + * Allows providing hooks on domain-specific lifecycles by dispatching events. + */ + interface EventDispatcherInterface extends PsrEventDispatcherInterface + { + /** + * Dispatches an event to all registered listeners. + * + * For BC with Symfony 4, the $eventName argument is not declared explicitly on the + * signature of the method. Implementations that are not bound by this BC constraint + * MUST declare it explicitly, as allowed by PHP. + * + * @param object $event The event to pass to the event handlers/listeners + * @param string|null $eventName The name of the event to dispatch. If not supplied, + * the class of $event should be used instead. + * + * @return object The passed $event MUST be returned + */ + public function dispatch($event/*, string $eventName = null*/); + } +} else { + /** + * Allows providing hooks on domain-specific lifecycles by dispatching events. + */ + interface EventDispatcherInterface + { + /** + * Dispatches an event to all registered listeners. + * + * For BC with Symfony 4, the $eventName argument is not declared explicitly on the + * signature of the method. Implementations that are not bound by this BC constraint + * MUST declare it explicitly, as allowed by PHP. + * + * @param object $event The event to pass to the event handlers/listeners + * @param string|null $eventName The name of the event to dispatch. If not supplied, + * the class of $event should be used instead. + * + * @return object The passed $event MUST be returned + */ + public function dispatch($event/*, string $eventName = null*/); + } +} diff --git a/vendor/symfony/event-dispatcher-contracts/LICENSE b/vendor/symfony/event-dispatcher-contracts/LICENSE new file mode 100644 index 00000000..74cdc2db --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/event-dispatcher-contracts/README.md b/vendor/symfony/event-dispatcher-contracts/README.md new file mode 100644 index 00000000..b1ab4c00 --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/README.md @@ -0,0 +1,9 @@ +Symfony EventDispatcher Contracts +================================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/vendor/symfony/event-dispatcher-contracts/composer.json b/vendor/symfony/event-dispatcher-contracts/composer.json new file mode 100644 index 00000000..9d4bd7be --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/composer.json @@ -0,0 +1,38 @@ +{ + "name": "symfony/event-dispatcher-contracts", + "type": "library", + "description": "Generic abstractions related to dispatching event", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\EventDispatcher\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.1-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/vendor/symfony/event-dispatcher/CHANGELOG.md b/vendor/symfony/event-dispatcher/CHANGELOG.md index c6aa5389..4a3ea066 100644 --- a/vendor/symfony/event-dispatcher/CHANGELOG.md +++ b/vendor/symfony/event-dispatcher/CHANGELOG.md @@ -1,24 +1,49 @@ CHANGELOG ========= +4.4.0 +----- + + * `AddEventAliasesPass` has been added, allowing applications and bundles to extend the event alias mapping used by `RegisterListenersPass`. + * Made the `event` attribute of the `kernel.event_listener` tag optional for FQCN events. + +4.3.0 +----- + + * The signature of the `EventDispatcherInterface::dispatch()` method should be updated to `dispatch($event, string $eventName = null)`, not doing so is deprecated + * deprecated the `Event` class, use `Symfony\Contracts\EventDispatcher\Event` instead + +4.1.0 +----- + + * added support for invokable event listeners tagged with `kernel.event_listener` by default + * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. + * The `TraceableEventDispatcherInterface` has been deprecated. + +4.0.0 +----- + + * removed the `ContainerAwareEventDispatcher` class + * added the `reset()` method to the `TraceableEventDispatcherInterface` + 3.4.0 ----- - * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. + * Implementing `TraceableEventDispatcherInterface` without the `reset()` method has been deprecated. 3.3.0 ----- - * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. + * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. 3.0.0 ----- - * The method `getListenerPriority($eventName, $listener)` has been added to the - `EventDispatcherInterface`. - * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` - and `Event::getName()` have been removed. - The event dispatcher and the event name are passed to the listener call. + * The method `getListenerPriority($eventName, $listener)` has been added to the + `EventDispatcherInterface`. + * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` + and `Event::getName()` have been removed. + The event dispatcher and the event name are passed to the listener call. 2.5.0 ----- diff --git a/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php b/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php deleted file mode 100644 index cbb9b12a..00000000 --- a/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php +++ /dev/null @@ -1,198 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher; - -use PHPUnit\Framework\MockObject\MockObject; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Lazily loads listeners and subscribers from the dependency injection - * container. - * - * @author Fabien Potencier - * @author Bernhard Schussek - * @author Jordan Alliot - * - * @deprecated since 3.3, to be removed in 4.0. Use EventDispatcher with closure factories instead. - */ -class ContainerAwareEventDispatcher extends EventDispatcher -{ - private $container; - - /** - * The service IDs of the event listeners and subscribers. - */ - private $listenerIds = []; - - /** - * The services registered as listeners. - */ - private $listeners = []; - - public function __construct(ContainerInterface $container) - { - $this->container = $container; - - $class = static::class; - if ($this instanceof \PHPUnit_Framework_MockObject_MockObject || $this instanceof MockObject || $this instanceof \Prophecy\Doubler\DoubleInterface) { - $class = get_parent_class($class); - } - if (__CLASS__ !== $class) { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), \E_USER_DEPRECATED); - } - } - - /** - * Adds a service as event listener. - * - * @param string $eventName Event for which the listener is added - * @param array $callback The service ID of the listener service & the method - * name that has to be called - * @param int $priority The higher this value, the earlier an event listener - * will be triggered in the chain. - * Defaults to 0. - * - * @throws \InvalidArgumentException - */ - public function addListenerService($eventName, $callback, $priority = 0) - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), \E_USER_DEPRECATED); - - if (!\is_array($callback) || 2 !== \count($callback)) { - throw new \InvalidArgumentException('Expected an ["service", "method"] argument.'); - } - - $this->listenerIds[$eventName][] = [$callback[0], $callback[1], $priority]; - } - - public function removeListener($eventName, $listener) - { - $this->lazyLoad($eventName); - - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method)) { - $key = $serviceId.'.'.$method; - if (isset($this->listeners[$eventName][$key]) && $listener === [$this->listeners[$eventName][$key], $method]) { - unset($this->listeners[$eventName][$key]); - if (empty($this->listeners[$eventName])) { - unset($this->listeners[$eventName]); - } - unset($this->listenerIds[$eventName][$i]); - if (empty($this->listenerIds[$eventName])) { - unset($this->listenerIds[$eventName]); - } - } - } - } - - parent::removeListener($eventName, $listener); - } - - /** - * {@inheritdoc} - */ - public function hasListeners($eventName = null) - { - if (null === $eventName) { - return $this->listenerIds || $this->listeners || parent::hasListeners(); - } - - if (isset($this->listenerIds[$eventName])) { - return true; - } - - return parent::hasListeners($eventName); - } - - /** - * {@inheritdoc} - */ - public function getListeners($eventName = null) - { - if (null === $eventName) { - foreach ($this->listenerIds as $serviceEventName => $args) { - $this->lazyLoad($serviceEventName); - } - } else { - $this->lazyLoad($eventName); - } - - return parent::getListeners($eventName); - } - - /** - * {@inheritdoc} - */ - public function getListenerPriority($eventName, $listener) - { - $this->lazyLoad($eventName); - - return parent::getListenerPriority($eventName, $listener); - } - - /** - * Adds a service as event subscriber. - * - * @param string $serviceId The service ID of the subscriber service - * @param string $class The service's class name (which must implement EventSubscriberInterface) - */ - public function addSubscriberService($serviceId, $class) - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), \E_USER_DEPRECATED); - - foreach ($class::getSubscribedEvents() as $eventName => $params) { - if (\is_string($params)) { - $this->listenerIds[$eventName][] = [$serviceId, $params, 0]; - } elseif (\is_string($params[0])) { - $this->listenerIds[$eventName][] = [$serviceId, $params[0], isset($params[1]) ? $params[1] : 0]; - } else { - foreach ($params as $listener) { - $this->listenerIds[$eventName][] = [$serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0]; - } - } - } - } - - public function getContainer() - { - @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 as its class will be removed in 4.0. Inject the container or the services you need in your listeners/subscribers instead.', \E_USER_DEPRECATED); - - return $this->container; - } - - /** - * Lazily loads listeners for this event from the dependency injection - * container. - * - * @param string $eventName The name of the event to dispatch. The name of - * the event is the name of the method that is - * invoked on listeners. - */ - protected function lazyLoad($eventName) - { - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) { - $listener = $this->container->get($serviceId); - - $key = $serviceId.'.'.$method; - if (!isset($this->listeners[$eventName][$key])) { - $this->addListener($eventName, [$listener, $method], $priority); - } elseif ($this->listeners[$eventName][$key] !== $listener) { - parent::removeListener($eventName, [$this->listeners[$eventName][$key], $method]); - $this->addListener($eventName, [$listener, $method], $priority); - } - - $this->listeners[$eventName][$key] = $listener; - } - } - } -} diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php index 01745972..98e7df63 100644 --- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @@ -11,11 +11,17 @@ namespace Symfony\Component\EventDispatcher\Debug; +use Psr\EventDispatcher\StoppableEventInterface; use Psr\Log\LoggerInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; +use Symfony\Component\EventDispatcher\LegacyEventProxy; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** * Collects some data about event listeners. @@ -32,13 +38,18 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface private $callStack; private $dispatcher; private $wrappedListeners; + private $orphanedEvents; + private $requestStack; + private $currentRequestHash = ''; - public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null) + public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null, RequestStack $requestStack = null) { - $this->dispatcher = $dispatcher; + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); $this->stopwatch = $stopwatch; $this->logger = $logger; $this->wrappedListeners = []; + $this->orphanedEvents = []; + $this->requestStack = $requestStack; } /** @@ -64,7 +75,7 @@ public function removeListener($eventName, $listener) { if (isset($this->wrappedListeners[$eventName])) { foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { - if ($wrappedListener->getWrappedListener() === $listener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { $listener = $wrappedListener; unset($this->wrappedListeners[$eventName][$index]); break; @@ -99,8 +110,8 @@ public function getListenerPriority($eventName, $listener) // we might have wrapped listeners for the event (if called while dispatching) // in that case get the priority by wrapper if (isset($this->wrappedListeners[$eventName])) { - foreach ($this->wrappedListeners[$eventName] as $index => $wrappedListener) { - if ($wrappedListener->getWrappedListener() === $listener) { + foreach ($this->wrappedListeners[$eventName] as $wrappedListener) { + if ($wrappedListener->getWrappedListener() === $listener || ($listener instanceof \Closure && $wrappedListener->getWrappedListener() == $listener)) { return $this->dispatcher->getListenerPriority($eventName, $wrappedListener); } } @@ -119,37 +130,52 @@ public function hasListeners($eventName = null) /** * {@inheritdoc} + * + * @param string|null $eventName */ - public function dispatch($eventName, Event $event = null) + public function dispatch($event/* , string $eventName = null */) { if (null === $this->callStack) { $this->callStack = new \SplObjectStorage(); } - if (null === $event) { - $event = new Event(); + $currentRequestHash = $this->currentRequestHash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; + $eventName = 1 < \func_num_args() ? func_get_arg(1) : null; + + if (\is_object($event)) { + $eventName = $eventName ?? \get_class($event); + } else { + @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as first argument is deprecated since Symfony 4.3, pass it second and provide the event object first instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED); + $swap = $event; + $event = $eventName ?? new Event(); + $eventName = $swap; + + if (!$event instanceof Event) { + throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an instance of "%s", "%s" given.', EventDispatcherInterface::class, Event::class, \is_object($event) ? \get_class($event) : \gettype($event))); + } } - if (null !== $this->logger && $event->isPropagationStopped()) { + if (null !== $this->logger && ($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { $this->logger->debug(sprintf('The "%s" event is already stopped. No listeners have been called.', $eventName)); } $this->preProcess($eventName); try { - $this->preDispatch($eventName, $event); + $this->beforeDispatch($eventName, $event); try { $e = $this->stopwatch->start($eventName, 'section'); try { - $this->dispatcher->dispatch($eventName, $event); + $this->dispatcher->dispatch($event, $eventName); } finally { if ($e->isStarted()) { $e->stop(); } } } finally { - $this->postDispatch($eventName, $event); + $this->afterDispatch($eventName, $event); } } finally { + $this->currentRequestHash = $currentRequestHash; $this->postProcess($eventName); } @@ -158,18 +184,22 @@ public function dispatch($eventName, Event $event = null) /** * {@inheritdoc} + * + * @param Request|null $request The request to get listeners for */ - public function getCalledListeners() + public function getCalledListeners(/* Request $request = null */) { if (null === $this->callStack) { return []; } + $hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null; $called = []; foreach ($this->callStack as $listener) { - list($eventName) = $this->callStack->getInfo(); - - $called[] = $listener->getInfo($eventName); + [$eventName, $requestHash] = $this->callStack->getInfo(); + if (null === $hash || $hash === $requestHash) { + $called[] = $listener->getInfo($eventName); + } } return $called; @@ -177,8 +207,10 @@ public function getCalledListeners() /** * {@inheritdoc} + * + * @param Request|null $request The request to get listeners for */ - public function getNotCalledListeners() + public function getNotCalledListeners(/* Request $request = null */) { try { $allListeners = $this->getListeners(); @@ -191,11 +223,16 @@ public function getNotCalledListeners() return []; } + $hash = 1 <= \func_num_args() && null !== ($request = func_get_arg(0)) ? spl_object_hash($request) : null; $calledListeners = []; if (null !== $this->callStack) { foreach ($this->callStack as $calledListener) { - $calledListeners[] = $calledListener->getWrappedListener(); + [, $requestHash] = $this->callStack->getInfo(); + + if (null === $hash || $hash === $requestHash) { + $calledListeners[] = $calledListener->getWrappedListener(); + } } } @@ -216,9 +253,27 @@ public function getNotCalledListeners() return $notCalled; } + /** + * @param Request|null $request The request to get orphaned events for + */ + public function getOrphanedEvents(/* Request $request = null */): array + { + if (1 <= \func_num_args() && null !== $request = func_get_arg(0)) { + return $this->orphanedEvents[spl_object_hash($request)] ?? []; + } + + if (!$this->orphanedEvents) { + return []; + } + + return array_merge(...array_values($this->orphanedEvents)); + } + public function reset() { $this->callStack = null; + $this->orphanedEvents = []; + $this->currentRequestHash = ''; } /** @@ -231,42 +286,62 @@ public function reset() */ public function __call($method, $arguments) { - return \call_user_func_array([$this->dispatcher, $method], $arguments); + return $this->dispatcher->{$method}(...$arguments); } /** * Called before dispatching the event. * - * @param string $eventName The event name - * @param Event $event The event + * @param object $event */ - protected function preDispatch($eventName, Event $event) + protected function beforeDispatch(string $eventName, $event) { + $this->preDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event)); } /** * Called after dispatching the event. * - * @param string $eventName The event name - * @param Event $event The event + * @param object $event + */ + protected function afterDispatch(string $eventName, $event) + { + $this->postDispatch($eventName, $event instanceof Event ? $event : new LegacyEventProxy($event)); + } + + /** + * @deprecated since Symfony 4.3, will be removed in 5.0, use beforeDispatch instead + */ + protected function preDispatch($eventName, Event $event) + { + } + + /** + * @deprecated since Symfony 4.3, will be removed in 5.0, use afterDispatch instead */ protected function postDispatch($eventName, Event $event) { } - private function preProcess($eventName) + private function preProcess(string $eventName) { + if (!$this->dispatcher->hasListeners($eventName)) { + $this->orphanedEvents[$this->currentRequestHash][] = $eventName; + + return; + } + foreach ($this->dispatcher->getListeners($eventName) as $listener) { $priority = $this->getListenerPriority($eventName, $listener); $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this); $this->wrappedListeners[$eventName][] = $wrappedListener; $this->dispatcher->removeListener($eventName, $listener); $this->dispatcher->addListener($eventName, $wrappedListener, $priority); - $this->callStack->attach($wrappedListener, [$eventName]); + $this->callStack->attach($wrappedListener, [$eventName, $this->currentRequestHash]); } } - private function postProcess($eventName) + private function postProcess(string $eventName) { unset($this->wrappedListeners[$eventName]); $skipped = false; diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php index f0212753..4fedb9a4 100644 --- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php @@ -12,25 +12,31 @@ namespace Symfony\Component\EventDispatcher\Debug; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Contracts\Service\ResetInterface; /** - * @author Fabien Potencier + * @deprecated since Symfony 4.1 * - * @method reset() Resets the trace. + * @author Fabien Potencier */ -interface TraceableEventDispatcherInterface extends EventDispatcherInterface +interface TraceableEventDispatcherInterface extends EventDispatcherInterface, ResetInterface { /** * Gets the called listeners. * + * @param Request|null $request The request to get listeners for + * * @return array An array of called listeners */ - public function getCalledListeners(); + public function getCalledListeners(/* Request $request = null */); /** * Gets the not called listeners. * + * @param Request|null $request The request to get listeners for + * * @return array An array of not called listeners */ - public function getNotCalledListeners(); + public function getNotCalledListeners(/* Request $request = null */); } diff --git a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php index de2b8509..9b910e66 100644 --- a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php +++ b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php @@ -11,17 +11,23 @@ namespace Symfony\Component\EventDispatcher\Debug; +use Psr\EventDispatcher\StoppableEventInterface; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\LegacyEventProxy; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** * @author Fabien Potencier + * + * @final since Symfony 4.3: the "Event" type-hint on __invoke() will be replaced by "object" in 5.0 */ class WrappedListener { private $listener; + private $optimizedListener; private $name; private $called; private $stoppedPropagation; @@ -32,9 +38,10 @@ class WrappedListener private $priority; private static $hasClassStub; - public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) + public function __construct($listener, ?string $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) { $this->listener = $listener; + $this->optimizedListener = $listener instanceof \Closure ? $listener : (\is_callable($listener) ? \Closure::fromCallable($listener) : null); $this->stopwatch = $stopwatch; $this->dispatcher = $dispatcher; $this->called = false; @@ -45,7 +52,7 @@ public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatc $this->pretty = $this->name.'::'.$listener[1]; } elseif ($listener instanceof \Closure) { $r = new \ReflectionFunction($listener); - if (false !== strpos($r->name, '{closure}')) { + if (str_contains($r->name, '{closure}')) { $this->pretty = $this->name = 'closure'; } elseif ($class = $r->getClosureScopeClass()) { $this->name = $class->name; @@ -105,6 +112,10 @@ public function getInfo($eventName) public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) { + if ($event instanceof LegacyEventProxy) { + $event = $event->getEvent(); + } + $dispatcher = $this->dispatcher ?: $dispatcher; $this->called = true; @@ -112,13 +123,13 @@ public function __invoke(Event $event, $eventName, EventDispatcherInterface $dis $e = $this->stopwatch->start($this->name, 'event_listener'); - \call_user_func($this->listener, $event, $eventName, $dispatcher); + ($this->optimizedListener ?? $this->listener)($event, $eventName, $dispatcher); if ($e->isStarted()) { $e->stop(); } - if ($event->isPropagationStopped()) { + if (($event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface) && $event->isPropagationStopped()) { $this->stoppedPropagation = true; } } diff --git a/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php new file mode 100644 index 00000000..c4ea50f7 --- /dev/null +++ b/vendor/symfony/event-dispatcher/DependencyInjection/AddEventAliasesPass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * This pass allows bundles to extend the list of event aliases. + * + * @author Alexander M. Turek + */ +class AddEventAliasesPass implements CompilerPassInterface +{ + private $eventAliases; + private $eventAliasesParameter; + + public function __construct(array $eventAliases, string $eventAliasesParameter = 'event_dispatcher.event_aliases') + { + $this->eventAliases = $eventAliases; + $this->eventAliasesParameter = $eventAliasesParameter; + } + + public function process(ContainerBuilder $container): void + { + $eventAliases = $container->hasParameter($this->eventAliasesParameter) ? $container->getParameter($this->eventAliasesParameter) : []; + + $container->setParameter( + $this->eventAliasesParameter, + array_merge($eventAliases, $this->eventAliases) + ); + } +} diff --git a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php index 2951c1ee..1c4e12ec 100644 --- a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php +++ b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -16,8 +16,10 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\EventDispatcher\Event as LegacyEvent; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event; /** * Compiler pass to register tagged services for an event dispatcher. @@ -27,20 +29,17 @@ class RegisterListenersPass implements CompilerPassInterface protected $dispatcherService; protected $listenerTag; protected $subscriberTag; + protected $eventAliasesParameter; private $hotPathEvents = []; private $hotPathTagName; - /** - * @param string $dispatcherService Service name of the event dispatcher in processed container - * @param string $listenerTag Tag name used for listener - * @param string $subscriberTag Tag name used for subscribers - */ - public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber') + public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber', string $eventAliasesParameter = 'event_dispatcher.event_aliases') { $this->dispatcherService = $dispatcherService; $this->listenerTag = $listenerTag; $this->subscriberTag = $subscriberTag; + $this->eventAliasesParameter = $eventAliasesParameter; } public function setHotPathEvents(array $hotPathEvents, $tagName = 'container.hot_path') @@ -57,22 +56,39 @@ public function process(ContainerBuilder $container) return; } + $aliases = []; + + if ($container->hasParameter($this->eventAliasesParameter)) { + $aliases = $container->getParameter($this->eventAliasesParameter); + } + $definition = $container->findDefinition($this->dispatcherService); foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) { foreach ($events as $event) { - $priority = isset($event['priority']) ? $event['priority'] : 0; + $priority = $event['priority'] ?? 0; if (!isset($event['event'])) { - throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + if ($container->getDefinition($id)->hasTag($this->subscriberTag)) { + continue; + } + + $event['method'] = $event['method'] ?? '__invoke'; + $event['event'] = $this->getEventFromTypeDeclaration($container, $id, $event['method']); } + $event['event'] = $aliases[$event['event']] ?? $event['event']; + if (!isset($event['method'])) { $event['method'] = 'on'.preg_replace_callback([ - '/(?<=\b)[a-z]/i', + '/(?<=\b|_)[a-z]/i', '/[^a-z0-9]/i', ], function ($matches) { return strtoupper($matches[0]); }, $event['event']); $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); + + if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method']) && $r->hasMethod('__invoke')) { + $event['method'] = '__invoke'; + } } $definition->addMethodCall('addListener', [$event['event'], [new ServiceClosureArgument(new Reference($id)), $event['method']], $priority]); @@ -99,6 +115,7 @@ public function process(ContainerBuilder $container) } $class = $r->name; + ExtractingEventDispatcher::$aliases = $aliases; ExtractingEventDispatcher::$subscriber = $class; $extractingDispatcher->addSubscriber($extractingDispatcher); foreach ($extractingDispatcher->listeners as $args) { @@ -110,8 +127,27 @@ public function process(ContainerBuilder $container) } } $extractingDispatcher->listeners = []; + ExtractingEventDispatcher::$aliases = []; } } + + private function getEventFromTypeDeclaration(ContainerBuilder $container, string $id, string $method): string + { + if ( + null === ($class = $container->getDefinition($id)->getClass()) + || !($r = $container->getReflectionClass($class, false)) + || !$r->hasMethod($method) + || 1 > ($m = $r->getMethod($method))->getNumberOfParameters() + || !($type = $m->getParameters()[0]->getType()) instanceof \ReflectionNamedType + || $type->isBuiltin() + || Event::class === ($name = $type->getName()) + || LegacyEvent::class === $name + ) { + throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); + } + + return $name; + } } /** @@ -121,6 +157,7 @@ class ExtractingEventDispatcher extends EventDispatcher implements EventSubscrib { public $listeners = []; + public static $aliases = []; public static $subscriber; public function addListener($eventName, $listener, $priority = 0) @@ -128,10 +165,14 @@ public function addListener($eventName, $listener, $priority = 0) $this->listeners[] = [$eventName, $listener[1], $priority]; } - public static function getSubscribedEvents() + public static function getSubscribedEvents(): array { - $callback = [self::$subscriber, 'getSubscribedEvents']; + $events = []; + + foreach ([self::$subscriber, 'getSubscribedEvents']() as $eventName => $params) { + $events[self::$aliases[$eventName] ?? $eventName] = $params; + } - return $callback(); + return $events; } } diff --git a/vendor/symfony/event-dispatcher/Event.php b/vendor/symfony/event-dispatcher/Event.php index 9c56b2f5..307c4be5 100644 --- a/vendor/symfony/event-dispatcher/Event.php +++ b/vendor/symfony/event-dispatcher/Event.php @@ -12,32 +12,16 @@ namespace Symfony\Component\EventDispatcher; /** - * Event is the base class for classes containing event data. - * - * This class contains no event data. It is used by events that do not pass - * state information to an event handler when an event is raised. - * - * You can call the method stopPropagation() to abort the execution of - * further listeners in your event listener. - * - * @author Guilherme Blanco - * @author Jonathan Wage - * @author Roman Borschel - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead */ class Event { - /** - * @var bool Whether no further event listeners should be triggered - */ private $propagationStopped = false; /** - * Returns whether further event listeners should be triggered. - * - * @see Event::stopPropagation() - * * @return bool Whether propagation was already stopped for this event + * + * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead */ public function isPropagationStopped() { @@ -45,11 +29,7 @@ public function isPropagationStopped() } /** - * Stops the propagation of the event to further event listeners. - * - * If multiple event listeners are connected to the same event, no - * further event listener will be triggered once any trigger calls - * stopPropagation(). + * @deprecated since Symfony 4.3, use "Symfony\Contracts\EventDispatcher\Event" instead */ public function stopPropagation() { diff --git a/vendor/symfony/event-dispatcher/EventDispatcher.php b/vendor/symfony/event-dispatcher/EventDispatcher.php index 207790f0..3d8ac428 100644 --- a/vendor/symfony/event-dispatcher/EventDispatcher.php +++ b/vendor/symfony/event-dispatcher/EventDispatcher.php @@ -11,6 +11,10 @@ namespace Symfony\Component\EventDispatcher; +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Component\EventDispatcher\Debug\WrappedListener; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; + /** * The EventDispatcherInterface is the central point of Symfony's event listener system. * @@ -30,18 +34,43 @@ class EventDispatcher implements EventDispatcherInterface { private $listeners = []; private $sorted = []; + private $optimized; + + public function __construct() + { + if (__CLASS__ === static::class) { + $this->optimized = []; + } + } /** * {@inheritdoc} + * + * @param string|null $eventName */ - public function dispatch($eventName, Event $event = null) + public function dispatch($event/* , string $eventName = null */) { - if (null === $event) { - $event = new Event(); + $eventName = 1 < \func_num_args() ? func_get_arg(1) : null; + + if (\is_object($event)) { + $eventName = $eventName ?? \get_class($event); + } elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) { + @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', EventDispatcherInterface::class), \E_USER_DEPRECATED); + $swap = $event; + $event = $eventName ?? new Event(); + $eventName = $swap; + } else { + throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', EventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event))); } - if ($listeners = $this->getListeners($eventName)) { - $this->doDispatch($listeners, $eventName, $event); + if (null !== $this->optimized && null !== $eventName) { + $listeners = $this->optimized[$eventName] ?? (empty($this->listeners[$eventName]) ? [] : $this->optimizeListeners($eventName)); + } else { + $listeners = $this->getListeners($eventName); + } + + if ($listeners) { + $this->callListeners($listeners, $eventName, $event); } return $event; @@ -82,17 +111,18 @@ public function getListenerPriority($eventName, $listener) return null; } - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; } - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $v) { - if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as &$v) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { $v[0] = $v[0](); - $this->listeners[$eventName][$priority][$k] = $v; + $v[1] = $v[1] ?? '__invoke'; } - if ($v === $listener) { + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { return $priority; } } @@ -125,7 +155,7 @@ public function hasListeners($eventName = null) public function addListener($eventName, $listener, $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; - unset($this->sorted[$eventName]); + unset($this->sorted[$eventName], $this->optimized[$eventName]); } /** @@ -137,25 +167,23 @@ public function removeListener($eventName, $listener) return; } - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; } - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $v) { - if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as $k => &$v) { + if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure && 2 >= \count($v)) { $v[0] = $v[0](); + $v[1] = $v[1] ?? '__invoke'; } - if ($v === $listener) { - unset($listeners[$k], $this->sorted[$eventName]); - } else { - $listeners[$k] = $v; + if ($v === $listener || ($listener instanceof \Closure && $v == $listener)) { + unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); } } - if ($listeners) { - $this->listeners[$eventName][$priority] = $listeners; - } else { + if (!$listeners) { unset($this->listeners[$eventName][$priority]); } } @@ -170,10 +198,10 @@ public function addSubscriber(EventSubscriberInterface $subscriber) if (\is_string($params)) { $this->addListener($eventName, [$subscriber, $params]); } elseif (\is_string($params[0])) { - $this->addListener($eventName, [$subscriber, $params[0]], isset($params[1]) ? $params[1] : 0); + $this->addListener($eventName, [$subscriber, $params[0]], $params[1] ?? 0); } else { foreach ($params as $listener) { - $this->addListener($eventName, [$subscriber, $listener[0]], isset($listener[1]) ? $listener[1] : 0); + $this->addListener($eventName, [$subscriber, $listener[0]], $listener[1] ?? 0); } } } @@ -203,7 +231,29 @@ public function removeSubscriber(EventSubscriberInterface $subscriber) * * @param callable[] $listeners The event listeners * @param string $eventName The name of the event to dispatch - * @param Event $event The event object to pass to the event handlers/listeners + * @param object $event The event object to pass to the event handlers/listeners + */ + protected function callListeners(iterable $listeners, string $eventName, $event) + { + if ($event instanceof Event) { + $this->doDispatch($listeners, $eventName, $event); + + return; + } + + $stoppable = $event instanceof ContractsEvent || $event instanceof StoppableEventInterface; + + foreach ($listeners as $listener) { + if ($stoppable && $event->isPropagationStopped()) { + break; + } + // @deprecated: the ternary operator is part of a BC layer and should be removed in 5.0 + $listener($listener instanceof WrappedListener ? new LegacyEventProxy($event) : $event, $eventName, $this); + } + } + + /** + * @deprecated since Symfony 4.3, use callListeners() instead */ protected function doDispatch($listeners, $eventName, Event $event) { @@ -211,28 +261,54 @@ protected function doDispatch($listeners, $eventName, Event $event) if ($event->isPropagationStopped()) { break; } - \call_user_func($listener, $event, $eventName, $this); + $listener($event, $eventName, $this); } } /** * Sorts the internal list of listeners for the given event by priority. - * - * @param string $eventName The name of the event */ - private function sortListeners($eventName) + private function sortListeners(string $eventName) { krsort($this->listeners[$eventName]); $this->sorted[$eventName] = []; - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $listener) { - if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as $k => &$listener) { + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { $listener[0] = $listener[0](); - $this->listeners[$eventName][$priority][$k] = $listener; + $listener[1] = $listener[1] ?? '__invoke'; } $this->sorted[$eventName][] = $listener; } } } + + /** + * Optimizes the internal list of listeners for the given event by priority. + */ + private function optimizeListeners(string $eventName): array + { + krsort($this->listeners[$eventName]); + $this->optimized[$eventName] = []; + + foreach ($this->listeners[$eventName] as &$listeners) { + foreach ($listeners as &$listener) { + $closure = &$this->optimized[$eventName][]; + if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure && 2 >= \count($listener)) { + $closure = static function (...$args) use (&$listener, &$closure) { + if ($listener[0] instanceof \Closure) { + $listener[0] = $listener[0](); + $listener[1] = $listener[1] ?? '__invoke'; + } + ($closure = \Closure::fromCallable($listener))(...$args); + }; + } else { + $closure = $listener instanceof \Closure || $listener instanceof WrappedListener ? $listener : \Closure::fromCallable($listener); + } + } + } + + return $this->optimized[$eventName]; + } } diff --git a/vendor/symfony/event-dispatcher/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher/EventDispatcherInterface.php index bde753a1..ceaa62ae 100644 --- a/vendor/symfony/event-dispatcher/EventDispatcherInterface.php +++ b/vendor/symfony/event-dispatcher/EventDispatcherInterface.php @@ -11,6 +11,8 @@ namespace Symfony\Component\EventDispatcher; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; + /** * The EventDispatcherInterface is the central point of Symfony's event listener system. * Listeners are registered on the manager and events are dispatched through the @@ -18,21 +20,8 @@ * * @author Bernhard Schussek */ -interface EventDispatcherInterface +interface EventDispatcherInterface extends ContractsEventDispatcherInterface { - /** - * Dispatches an event to all registered listeners. - * - * @param string $eventName The name of the event to dispatch. The name of - * the event is the name of the method that is - * invoked on listeners. - * @param Event|null $event The event to pass to the event handlers/listeners - * If not supplied, an empty Event instance is created - * - * @return Event - */ - public function dispatch($eventName, Event $event = null); - /** * Adds an event listener that listens on the specified events. * diff --git a/vendor/symfony/event-dispatcher/EventSubscriberInterface.php b/vendor/symfony/event-dispatcher/EventSubscriberInterface.php index 741590b1..a0fc96df 100644 --- a/vendor/symfony/event-dispatcher/EventSubscriberInterface.php +++ b/vendor/symfony/event-dispatcher/EventSubscriberInterface.php @@ -43,7 +43,7 @@ interface EventSubscriberInterface * The code must not depend on runtime state as it will only be called at compile time. * All logic depending on runtime state must be put into the individual methods handling the events. * - * @return array The event names to listen to + * @return array The event names to listen to */ public static function getSubscribedEvents(); } diff --git a/vendor/symfony/event-dispatcher/GenericEvent.php b/vendor/symfony/event-dispatcher/GenericEvent.php index f005e3a3..23333bc2 100644 --- a/vendor/symfony/event-dispatcher/GenericEvent.php +++ b/vendor/symfony/event-dispatcher/GenericEvent.php @@ -123,6 +123,7 @@ public function hasArgument($key) * * @throws \InvalidArgumentException if key does not exist in $this->args */ + #[\ReturnTypeWillChange] public function offsetGet($key) { return $this->getArgument($key); @@ -133,7 +134,10 @@ public function offsetGet($key) * * @param string $key Array key to set * @param mixed $value Value + * + * @return void */ + #[\ReturnTypeWillChange] public function offsetSet($key, $value) { $this->setArgument($key, $value); @@ -143,7 +147,10 @@ public function offsetSet($key, $value) * ArrayAccess for unset argument. * * @param string $key Array key + * + * @return void */ + #[\ReturnTypeWillChange] public function offsetUnset($key) { if ($this->hasArgument($key)) { @@ -158,6 +165,7 @@ public function offsetUnset($key) * * @return bool */ + #[\ReturnTypeWillChange] public function offsetExists($key) { return $this->hasArgument($key); @@ -168,6 +176,7 @@ public function offsetExists($key) * * @return \ArrayIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->arguments); diff --git a/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php index b3cf56c5..f3d04d25 100644 --- a/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php +++ b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php @@ -22,15 +22,26 @@ class ImmutableEventDispatcher implements EventDispatcherInterface public function __construct(EventDispatcherInterface $dispatcher) { - $this->dispatcher = $dispatcher; + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); } /** * {@inheritdoc} + * + * @param string|null $eventName */ - public function dispatch($eventName, Event $event = null) + public function dispatch($event/* , string $eventName = null */) { - return $this->dispatcher->dispatch($eventName, $event); + $eventName = 1 < \func_num_args() ? func_get_arg(1) : null; + + if (\is_scalar($event)) { + // deprecated + $swap = $event; + $event = $eventName ?? new Event(); + $eventName = $swap; + } + + return $this->dispatcher->dispatch($event, $eventName); } /** diff --git a/vendor/symfony/event-dispatcher/LICENSE b/vendor/symfony/event-dispatcher/LICENSE index 9e936ec0..88bf75bb 100644 --- a/vendor/symfony/event-dispatcher/LICENSE +++ b/vendor/symfony/event-dispatcher/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-2022 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php b/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php new file mode 100644 index 00000000..a802c993 --- /dev/null +++ b/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface as ContractsEventDispatcherInterface; + +/** + * A helper class to provide BC/FC with the legacy signature of EventDispatcherInterface::dispatch(). + * + * This class should be deprecated in Symfony 5.1 + * + * @author Nicolas Grekas + */ +final class LegacyEventDispatcherProxy implements EventDispatcherInterface +{ + private $dispatcher; + + public static function decorate(?ContractsEventDispatcherInterface $dispatcher): ?ContractsEventDispatcherInterface + { + if (null === $dispatcher) { + return null; + } + $r = new \ReflectionMethod($dispatcher, 'dispatch'); + $param2 = $r->getParameters()[1] ?? null; + + if (!$param2 || !$param2->hasType() || $param2->getType()->isBuiltin()) { + return $dispatcher; + } + + @trigger_error(sprintf('The signature of the "%s::dispatch()" method should be updated to "dispatch($event, string $eventName = null)", not doing so is deprecated since Symfony 4.3.', $r->class), \E_USER_DEPRECATED); + + $self = new self(); + $self->dispatcher = $dispatcher; + + return $self; + } + + /** + * {@inheritdoc} + * + * @param string|null $eventName + * + * @return object + */ + public function dispatch($event/* , string $eventName = null */) + { + $eventName = 1 < \func_num_args() ? func_get_arg(1) : null; + + if (\is_object($event)) { + $eventName = $eventName ?? \get_class($event); + } elseif (\is_string($event) && (null === $eventName || $eventName instanceof ContractsEvent || $eventName instanceof Event)) { + @trigger_error(sprintf('Calling the "%s::dispatch()" method with the event name as the first argument is deprecated since Symfony 4.3, pass it as the second argument and provide the event object as the first argument instead.', ContractsEventDispatcherInterface::class), \E_USER_DEPRECATED); + $swap = $event; + $event = $eventName ?? new Event(); + $eventName = $swap; + } else { + throw new \TypeError(sprintf('Argument 1 passed to "%s::dispatch()" must be an object, "%s" given.', ContractsEventDispatcherInterface::class, \is_object($event) ? \get_class($event) : \gettype($event))); + } + + $listeners = $this->getListeners($eventName); + $stoppable = $event instanceof Event || $event instanceof ContractsEvent || $event instanceof StoppableEventInterface; + + foreach ($listeners as $listener) { + if ($stoppable && $event->isPropagationStopped()) { + break; + } + $listener($event, $eventName, $this); + } + + return $event; + } + + /** + * {@inheritdoc} + */ + public function addListener($eventName, $listener, $priority = 0) + { + return $this->dispatcher->addListener($eventName, $listener, $priority); + } + + /** + * {@inheritdoc} + */ + public function addSubscriber(EventSubscriberInterface $subscriber) + { + return $this->dispatcher->addSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function removeListener($eventName, $listener) + { + return $this->dispatcher->removeListener($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function removeSubscriber(EventSubscriberInterface $subscriber) + { + return $this->dispatcher->removeSubscriber($subscriber); + } + + /** + * {@inheritdoc} + */ + public function getListeners($eventName = null): array + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function getListenerPriority($eventName, $listener): ?int + { + return $this->dispatcher->getListenerPriority($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null): bool + { + return $this->dispatcher->hasListeners($eventName); + } + + /** + * Proxies all method calls to the original event dispatcher. + */ + public function __call($method, $arguments) + { + return $this->dispatcher->{$method}(...$arguments); + } +} diff --git a/vendor/symfony/event-dispatcher/LegacyEventProxy.php b/vendor/symfony/event-dispatcher/LegacyEventProxy.php new file mode 100644 index 00000000..45ee251d --- /dev/null +++ b/vendor/symfony/event-dispatcher/LegacyEventProxy.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Psr\EventDispatcher\StoppableEventInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; + +/** + * @internal to be removed in 5.0. + */ +final class LegacyEventProxy extends Event +{ + private $event; + + /** + * @param object $event + */ + public function __construct($event) + { + $this->event = $event; + } + + /** + * @return object $event + */ + public function getEvent() + { + return $this->event; + } + + public function isPropagationStopped(): bool + { + if (!$this->event instanceof ContractsEvent && !$this->event instanceof StoppableEventInterface) { + return false; + } + + return $this->event->isPropagationStopped(); + } + + public function stopPropagation() + { + if (!$this->event instanceof ContractsEvent) { + return; + } + + $this->event->stopPropagation(); + } + + public function __call($name, $args) + { + return $this->event->{$name}(...$args); + } +} diff --git a/vendor/symfony/event-dispatcher/README.md b/vendor/symfony/event-dispatcher/README.md index e0d38eed..dcdb68d2 100644 --- a/vendor/symfony/event-dispatcher/README.md +++ b/vendor/symfony/event-dispatcher/README.md @@ -8,8 +8,8 @@ them. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php deleted file mode 100644 index 359e6005..00000000 --- a/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php +++ /dev/null @@ -1,442 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -abstract class AbstractEventDispatcherTest extends TestCase -{ - /* Some pseudo events */ - const preFoo = 'pre.foo'; - const postFoo = 'post.foo'; - const preBar = 'pre.bar'; - const postBar = 'post.bar'; - - /** - * @var EventDispatcher - */ - private $dispatcher; - - private $listener; - - protected function setUp() - { - $this->dispatcher = $this->createEventDispatcher(); - $this->listener = new TestEventListener(); - } - - protected function tearDown() - { - $this->dispatcher = null; - $this->listener = null; - } - - abstract protected function createEventDispatcher(); - - public function testInitialState() - { - $this->assertEquals([], $this->dispatcher->getListeners()); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); - } - - public function testAddListener() - { - $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); - $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); - $this->assertTrue($this->dispatcher->hasListeners()); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); - $this->assertCount(1, $this->dispatcher->getListeners(self::preFoo)); - $this->assertCount(1, $this->dispatcher->getListeners(self::postFoo)); - $this->assertCount(2, $this->dispatcher->getListeners()); - } - - public function testGetListenersSortsByPriority() - { - $listener1 = new TestEventListener(); - $listener2 = new TestEventListener(); - $listener3 = new TestEventListener(); - $listener1->name = '1'; - $listener2->name = '2'; - $listener3->name = '3'; - - $this->dispatcher->addListener('pre.foo', [$listener1, 'preFoo'], -10); - $this->dispatcher->addListener('pre.foo', [$listener2, 'preFoo'], 10); - $this->dispatcher->addListener('pre.foo', [$listener3, 'preFoo']); - - $expected = [ - [$listener2, 'preFoo'], - [$listener3, 'preFoo'], - [$listener1, 'preFoo'], - ]; - - $this->assertSame($expected, $this->dispatcher->getListeners('pre.foo')); - } - - public function testGetAllListenersSortsByPriority() - { - $listener1 = new TestEventListener(); - $listener2 = new TestEventListener(); - $listener3 = new TestEventListener(); - $listener4 = new TestEventListener(); - $listener5 = new TestEventListener(); - $listener6 = new TestEventListener(); - - $this->dispatcher->addListener('pre.foo', $listener1, -10); - $this->dispatcher->addListener('pre.foo', $listener2); - $this->dispatcher->addListener('pre.foo', $listener3, 10); - $this->dispatcher->addListener('post.foo', $listener4, -10); - $this->dispatcher->addListener('post.foo', $listener5); - $this->dispatcher->addListener('post.foo', $listener6, 10); - - $expected = [ - 'pre.foo' => [$listener3, $listener2, $listener1], - 'post.foo' => [$listener6, $listener5, $listener4], - ]; - - $this->assertSame($expected, $this->dispatcher->getListeners()); - } - - public function testGetListenerPriority() - { - $listener1 = new TestEventListener(); - $listener2 = new TestEventListener(); - - $this->dispatcher->addListener('pre.foo', $listener1, -10); - $this->dispatcher->addListener('pre.foo', $listener2); - - $this->assertSame(-10, $this->dispatcher->getListenerPriority('pre.foo', $listener1)); - $this->assertSame(0, $this->dispatcher->getListenerPriority('pre.foo', $listener2)); - $this->assertNull($this->dispatcher->getListenerPriority('pre.bar', $listener2)); - $this->assertNull($this->dispatcher->getListenerPriority('pre.foo', function () {})); - } - - public function testDispatch() - { - $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); - $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); - $this->dispatcher->dispatch(self::preFoo); - $this->assertTrue($this->listener->preFooInvoked); - $this->assertFalse($this->listener->postFooInvoked); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch('noevent')); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(self::preFoo)); - $event = new Event(); - $return = $this->dispatcher->dispatch(self::preFoo, $event); - $this->assertSame($event, $return); - } - - public function testDispatchForClosure() - { - $invoked = 0; - $listener = function () use (&$invoked) { - ++$invoked; - }; - $this->dispatcher->addListener('pre.foo', $listener); - $this->dispatcher->addListener('post.foo', $listener); - $this->dispatcher->dispatch(self::preFoo); - $this->assertEquals(1, $invoked); - } - - public function testStopEventPropagation() - { - $otherListener = new TestEventListener(); - - // postFoo() stops the propagation, so only one listener should - // be executed - // Manually set priority to enforce $this->listener to be called first - $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo'], 10); - $this->dispatcher->addListener('post.foo', [$otherListener, 'postFoo']); - $this->dispatcher->dispatch(self::postFoo); - $this->assertTrue($this->listener->postFooInvoked); - $this->assertFalse($otherListener->postFooInvoked); - } - - public function testDispatchByPriority() - { - $invoked = []; - $listener1 = function () use (&$invoked) { - $invoked[] = '1'; - }; - $listener2 = function () use (&$invoked) { - $invoked[] = '2'; - }; - $listener3 = function () use (&$invoked) { - $invoked[] = '3'; - }; - $this->dispatcher->addListener('pre.foo', $listener1, -10); - $this->dispatcher->addListener('pre.foo', $listener2); - $this->dispatcher->addListener('pre.foo', $listener3, 10); - $this->dispatcher->dispatch(self::preFoo); - $this->assertEquals(['3', '2', '1'], $invoked); - } - - public function testRemoveListener() - { - $this->dispatcher->addListener('pre.bar', $this->listener); - $this->assertTrue($this->dispatcher->hasListeners(self::preBar)); - $this->dispatcher->removeListener('pre.bar', $this->listener); - $this->assertFalse($this->dispatcher->hasListeners(self::preBar)); - $this->dispatcher->removeListener('notExists', $this->listener); - } - - public function testAddSubscriber() - { - $eventSubscriber = new TestEventSubscriber(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); - } - - public function testAddSubscriberWithPriorities() - { - $eventSubscriber = new TestEventSubscriber(); - $this->dispatcher->addSubscriber($eventSubscriber); - - $eventSubscriber = new TestEventSubscriberWithPriorities(); - $this->dispatcher->addSubscriber($eventSubscriber); - - $listeners = $this->dispatcher->getListeners('pre.foo'); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertCount(2, $listeners); - $this->assertInstanceOf('Symfony\Component\EventDispatcher\Tests\TestEventSubscriberWithPriorities', $listeners[0][0]); - } - - public function testAddSubscriberWithMultipleListeners() - { - $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); - $this->dispatcher->addSubscriber($eventSubscriber); - - $listeners = $this->dispatcher->getListeners('pre.foo'); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertCount(2, $listeners); - $this->assertEquals('preFoo2', $listeners[0][1]); - } - - public function testRemoveSubscriber() - { - $eventSubscriber = new TestEventSubscriber(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertTrue($this->dispatcher->hasListeners(self::postFoo)); - $this->dispatcher->removeSubscriber($eventSubscriber); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - $this->assertFalse($this->dispatcher->hasListeners(self::postFoo)); - } - - public function testRemoveSubscriberWithPriorities() - { - $eventSubscriber = new TestEventSubscriberWithPriorities(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->dispatcher->removeSubscriber($eventSubscriber); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - } - - public function testRemoveSubscriberWithMultipleListeners() - { - $eventSubscriber = new TestEventSubscriberWithMultipleListeners(); - $this->dispatcher->addSubscriber($eventSubscriber); - $this->assertTrue($this->dispatcher->hasListeners(self::preFoo)); - $this->assertCount(2, $this->dispatcher->getListeners(self::preFoo)); - $this->dispatcher->removeSubscriber($eventSubscriber); - $this->assertFalse($this->dispatcher->hasListeners(self::preFoo)); - } - - public function testEventReceivesTheDispatcherInstanceAsArgument() - { - $listener = new TestWithDispatcher(); - $this->dispatcher->addListener('test', [$listener, 'foo']); - $this->assertNull($listener->name); - $this->assertNull($listener->dispatcher); - $this->dispatcher->dispatch('test'); - $this->assertEquals('test', $listener->name); - $this->assertSame($this->dispatcher, $listener->dispatcher); - } - - /** - * @see https://bugs.php.net/62976 - * - * This bug affects: - * - The PHP 5.3 branch for versions < 5.3.18 - * - The PHP 5.4 branch for versions < 5.4.8 - * - The PHP 5.5 branch is not affected - */ - public function testWorkaroundForPhpBug62976() - { - $dispatcher = $this->createEventDispatcher(); - $dispatcher->addListener('bug.62976', new CallableClass()); - $dispatcher->removeListener('bug.62976', function () {}); - $this->assertTrue($dispatcher->hasListeners('bug.62976')); - } - - public function testHasListenersWhenAddedCallbackListenerIsRemoved() - { - $listener = function () {}; - $this->dispatcher->addListener('foo', $listener); - $this->dispatcher->removeListener('foo', $listener); - $this->assertFalse($this->dispatcher->hasListeners()); - } - - public function testGetListenersWhenAddedCallbackListenerIsRemoved() - { - $listener = function () {}; - $this->dispatcher->addListener('foo', $listener); - $this->dispatcher->removeListener('foo', $listener); - $this->assertSame([], $this->dispatcher->getListeners()); - } - - public function testHasListenersWithoutEventsReturnsFalseAfterHasListenersWithEventHasBeenCalled() - { - $this->assertFalse($this->dispatcher->hasListeners('foo')); - $this->assertFalse($this->dispatcher->hasListeners()); - } - - public function testHasListenersIsLazy() - { - $called = 0; - $listener = [function () use (&$called) { ++$called; }, 'onFoo']; - $this->dispatcher->addListener('foo', $listener); - $this->assertTrue($this->dispatcher->hasListeners()); - $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->assertSame(0, $called); - } - - public function testDispatchLazyListener() - { - $called = 0; - $factory = function () use (&$called) { - ++$called; - - return new TestWithDispatcher(); - }; - $this->dispatcher->addListener('foo', [$factory, 'foo']); - $this->assertSame(0, $called); - $this->dispatcher->dispatch('foo', new Event()); - $this->dispatcher->dispatch('foo', new Event()); - $this->assertSame(1, $called); - } - - public function testRemoveFindsLazyListeners() - { - $test = new TestWithDispatcher(); - $factory = function () use ($test) { return $test; }; - - $this->dispatcher->addListener('foo', [$factory, 'foo']); - $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->dispatcher->removeListener('foo', [$test, 'foo']); - $this->assertFalse($this->dispatcher->hasListeners('foo')); - - $this->dispatcher->addListener('foo', [$test, 'foo']); - $this->assertTrue($this->dispatcher->hasListeners('foo')); - $this->dispatcher->removeListener('foo', [$factory, 'foo']); - $this->assertFalse($this->dispatcher->hasListeners('foo')); - } - - public function testPriorityFindsLazyListeners() - { - $test = new TestWithDispatcher(); - $factory = function () use ($test) { return $test; }; - - $this->dispatcher->addListener('foo', [$factory, 'foo'], 3); - $this->assertSame(3, $this->dispatcher->getListenerPriority('foo', [$test, 'foo'])); - $this->dispatcher->removeListener('foo', [$factory, 'foo']); - - $this->dispatcher->addListener('foo', [$test, 'foo'], 5); - $this->assertSame(5, $this->dispatcher->getListenerPriority('foo', [$factory, 'foo'])); - } - - public function testGetLazyListeners() - { - $test = new TestWithDispatcher(); - $factory = function () use ($test) { return $test; }; - - $this->dispatcher->addListener('foo', [$factory, 'foo'], 3); - $this->assertSame([[$test, 'foo']], $this->dispatcher->getListeners('foo')); - - $this->dispatcher->removeListener('foo', [$test, 'foo']); - $this->dispatcher->addListener('bar', [$factory, 'foo'], 3); - $this->assertSame(['bar' => [[$test, 'foo']]], $this->dispatcher->getListeners()); - } -} - -class CallableClass -{ - public function __invoke() - { - } -} - -class TestEventListener -{ - public $preFooInvoked = false; - public $postFooInvoked = false; - - /* Listener methods */ - - public function preFoo(Event $e) - { - $this->preFooInvoked = true; - } - - public function postFoo(Event $e) - { - $this->postFooInvoked = true; - - $e->stopPropagation(); - } -} - -class TestWithDispatcher -{ - public $name; - public $dispatcher; - - public function foo(Event $e, $name, $dispatcher) - { - $this->name = $name; - $this->dispatcher = $dispatcher; - } -} - -class TestEventSubscriber implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return ['pre.foo' => 'preFoo', 'post.foo' => 'postFoo']; - } -} - -class TestEventSubscriberWithPriorities implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return [ - 'pre.foo' => ['preFoo', 10], - 'post.foo' => ['postFoo'], - ]; - } -} - -class TestEventSubscriberWithMultipleListeners implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return ['pre.foo' => [ - ['preFoo1'], - ['preFoo2', 10], - ]]; - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php deleted file mode 100644 index 685cdfc3..00000000 --- a/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ /dev/null @@ -1,210 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use Symfony\Component\DependencyInjection\Container; -use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -/** - * @group legacy - */ -class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest -{ - protected function createEventDispatcher() - { - $container = new Container(); - - return new ContainerAwareEventDispatcher($container); - } - - public function testAddAListenerService() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent']); - - $dispatcher->dispatch('onEvent', $event); - } - - public function testAddASubscriberService() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\SubscriberService')->getMock(); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $service - ->expects($this->once()) - ->method('onEventWithPriority') - ->with($event) - ; - - $service - ->expects($this->once()) - ->method('onEventNested') - ->with($event) - ; - - $container = new Container(); - $container->set('service.subscriber', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService'); - - $dispatcher->dispatch('onEvent', $event); - $dispatcher->dispatch('onEventWithPriority', $event); - $dispatcher->dispatch('onEventNested', $event); - } - - public function testPreventDuplicateListenerService() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent'], 5); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent'], 10); - - $dispatcher->dispatch('onEvent', $event); - } - - public function testHasListenersOnLazyLoad() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent']); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $this->assertTrue($dispatcher->hasListeners()); - - if ($dispatcher->hasListeners('onEvent')) { - $dispatcher->dispatch('onEvent'); - } - } - - public function testGetListenersOnLazyLoad() - { - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent']); - - $listeners = $dispatcher->getListeners(); - - $this->assertArrayHasKey('onEvent', $listeners); - - $this->assertCount(1, $dispatcher->getListeners('onEvent')); - } - - public function testRemoveAfterDispatch() - { - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent']); - - $dispatcher->dispatch('onEvent', new Event()); - $dispatcher->removeListener('onEvent', [$container->get('service.listener'), 'onEvent']); - $this->assertFalse($dispatcher->hasListeners('onEvent')); - } - - public function testRemoveBeforeDispatch() - { - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', ['service.listener', 'onEvent']); - - $dispatcher->removeListener('onEvent', [$container->get('service.listener'), 'onEvent']); - $this->assertFalse($dispatcher->hasListeners('onEvent')); - } -} - -class Service -{ - public function onEvent(Event $e) - { - } -} - -class SubscriberService implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return [ - 'onEvent' => 'onEvent', - 'onEventWithPriority' => ['onEventWithPriority', 10], - 'onEventNested' => [['onEventNested']], - ]; - } - - public function onEvent(Event $e) - { - } - - public function onEventWithPriority(Event $e) - { - } - - public function onEventNested(Event $e) - { - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php deleted file mode 100644 index 4ba622d1..00000000 --- a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ /dev/null @@ -1,294 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests\Debug; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Debug\BufferingLogger; -use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\Stopwatch\Stopwatch; - -class TraceableEventDispatcherTest extends TestCase -{ - public function testAddRemoveListener() - { - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - - $tdispatcher->addListener('foo', $listener = function () {}); - $listeners = $dispatcher->getListeners('foo'); - $this->assertCount(1, $listeners); - $this->assertSame($listener, $listeners[0]); - - $tdispatcher->removeListener('foo', $listener); - $this->assertCount(0, $dispatcher->getListeners('foo')); - } - - public function testGetListeners() - { - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - - $tdispatcher->addListener('foo', $listener = function () {}); - $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); - } - - public function testHasListeners() - { - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - - $this->assertFalse($dispatcher->hasListeners('foo')); - $this->assertFalse($tdispatcher->hasListeners('foo')); - - $tdispatcher->addListener('foo', $listener = function () {}); - $this->assertTrue($dispatcher->hasListeners('foo')); - $this->assertTrue($tdispatcher->hasListeners('foo')); - } - - public function testGetListenerPriority() - { - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - - $tdispatcher->addListener('foo', function () {}, 123); - - $listeners = $dispatcher->getListeners('foo'); - $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0])); - - // Verify that priority is preserved when listener is removed and re-added - // in preProcess() and postProcess(). - $tdispatcher->dispatch('foo', new Event()); - $listeners = $dispatcher->getListeners('foo'); - $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0])); - } - - public function testGetListenerPriorityWhileDispatching() - { - $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $priorityWhileDispatching = null; - - $listener = function () use ($tdispatcher, &$priorityWhileDispatching, &$listener) { - $priorityWhileDispatching = $tdispatcher->getListenerPriority('bar', $listener); - }; - - $tdispatcher->addListener('bar', $listener, 5); - $tdispatcher->dispatch('bar'); - $this->assertSame(5, $priorityWhileDispatching); - } - - public function testAddRemoveSubscriber() - { - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - - $subscriber = new EventSubscriber(); - - $tdispatcher->addSubscriber($subscriber); - $listeners = $dispatcher->getListeners('foo'); - $this->assertCount(1, $listeners); - $this->assertSame([$subscriber, 'call'], $listeners[0]); - - $tdispatcher->removeSubscriber($subscriber); - $this->assertCount(0, $dispatcher->getListeners('foo')); - } - - public function testGetCalledListeners() - { - $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $tdispatcher->addListener('foo', function () {}, 5); - - $listeners = $tdispatcher->getNotCalledListeners(); - $this->assertArrayHasKey('stub', $listeners[0]); - unset($listeners[0]['stub']); - $this->assertEquals([], $tdispatcher->getCalledListeners()); - $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); - - $tdispatcher->dispatch('foo'); - - $listeners = $tdispatcher->getCalledListeners(); - $this->assertArrayHasKey('stub', $listeners[0]); - unset($listeners[0]['stub']); - $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); - $this->assertEquals([], $tdispatcher->getNotCalledListeners()); - } - - public function testClearCalledListeners() - { - $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $tdispatcher->addListener('foo', function () {}, 5); - - $tdispatcher->dispatch('foo'); - $tdispatcher->reset(); - - $listeners = $tdispatcher->getNotCalledListeners(); - $this->assertArrayHasKey('stub', $listeners[0]); - unset($listeners[0]['stub']); - $this->assertEquals([], $tdispatcher->getCalledListeners()); - $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); - } - - public function testDispatchAfterReset() - { - $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $tdispatcher->addListener('foo', function () {}, 5); - - $tdispatcher->reset(); - $tdispatcher->dispatch('foo'); - - $listeners = $tdispatcher->getCalledListeners(); - $this->assertArrayHasKey('stub', $listeners[0]); - } - - public function testGetCalledListenersNested() - { - $tdispatcher = null; - $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) { - $tdispatcher = $dispatcher; - $dispatcher->dispatch('bar'); - }); - $dispatcher->addListener('bar', function (Event $event) {}); - $dispatcher->dispatch('foo'); - $this->assertSame($dispatcher, $tdispatcher); - $this->assertCount(2, $dispatcher->getCalledListeners()); - } - - public function testLogger() - { - $logger = new BufferingLogger(); - - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); - $tdispatcher->addListener('foo', $listener1 = function () {}); - $tdispatcher->addListener('foo', $listener2 = function () {}); - - $tdispatcher->dispatch('foo'); - - $this->assertSame([ - [ - 'debug', - 'Notified event "{event}" to listener "{listener}".', - ['event' => 'foo', 'listener' => 'closure'], - ], - [ - 'debug', - 'Notified event "{event}" to listener "{listener}".', - ['event' => 'foo', 'listener' => 'closure'], - ], - ], $logger->cleanLogs()); - } - - public function testLoggerWithStoppedEvent() - { - $logger = new BufferingLogger(); - - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); - $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); - $tdispatcher->addListener('foo', $listener2 = function () {}); - - $tdispatcher->dispatch('foo'); - - $this->assertSame([ - [ - 'debug', - 'Notified event "{event}" to listener "{listener}".', - ['event' => 'foo', 'listener' => 'closure'], - ], - [ - 'debug', - 'Listener "{listener}" stopped propagation of the event "{event}".', - ['event' => 'foo', 'listener' => 'closure'], - ], - [ - 'debug', - 'Listener "{listener}" was not called for event "{event}".', - ['event' => 'foo', 'listener' => 'closure'], - ], - ], $logger->cleanLogs()); - } - - public function testDispatchCallListeners() - { - $called = []; - - $dispatcher = new EventDispatcher(); - $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10); - $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20); - - $tdispatcher->dispatch('foo'); - - $this->assertSame(['foo2', 'foo1'], $called); - } - - public function testDispatchNested() - { - $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $loop = 1; - $dispatchedEvents = 0; - $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) { - ++$loop; - if (2 == $loop) { - $dispatcher->dispatch('foo'); - } - }); - $dispatcher->addListener('foo', function () use (&$dispatchedEvents) { - ++$dispatchedEvents; - }); - - $dispatcher->dispatch('foo'); - - $this->assertSame(2, $dispatchedEvents); - } - - public function testDispatchReusedEventNested() - { - $nestedCall = false; - $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) { - $dispatcher->dispatch('bar', $e); - }); - $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) { - $nestedCall = true; - }); - - $this->assertFalse($nestedCall); - $dispatcher->dispatch('foo'); - $this->assertTrue($nestedCall); - } - - public function testListenerCanRemoveItselfWhenExecuted() - { - $eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $listener1 = function ($event, $eventName, EventDispatcherInterface $dispatcher) use (&$listener1) { - $dispatcher->removeListener('foo', $listener1); - }; - $eventDispatcher->addListener('foo', $listener1); - $eventDispatcher->addListener('foo', function () {}); - $eventDispatcher->dispatch('foo'); - - $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); - } -} - -class EventSubscriber implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return ['foo' => 'call']; - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php deleted file mode 100644 index 258938ed..00000000 --- a/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests\Debug; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\Debug\WrappedListener; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Stopwatch\Stopwatch; - -class WrappedListenerTest extends TestCase -{ - /** - * @dataProvider provideListenersToDescribe - */ - public function testListenerDescription(callable $listener, $expected) - { - $wrappedListener = new WrappedListener($listener, null, $this->getMockBuilder(Stopwatch::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock()); - - $this->assertStringMatchesFormat($expected, $wrappedListener->getPretty()); - } - - public function provideListenersToDescribe() - { - $listeners = [ - [new FooListener(), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::__invoke'], - [[new FooListener(), 'listen'], 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen'], - [['Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'listenStatic'], 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listenStatic'], - ['var_dump', 'var_dump'], - [function () {}, 'closure'], - ]; - - if (\PHP_VERSION_ID >= 70100) { - $listeners[] = [\Closure::fromCallable([new FooListener(), 'listen']), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen']; - $listeners[] = [\Closure::fromCallable(['Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'listenStatic']), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listenStatic']; - $listeners[] = [\Closure::fromCallable(function () {}), 'closure']; - } - - return $listeners; - } -} - -class FooListener -{ - public function listen() - { - } - - public function __invoke() - { - } - - public static function listenStatic() - { - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php b/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php deleted file mode 100644 index 61c047af..00000000 --- a/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php +++ /dev/null @@ -1,143 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests\DependencyInjection; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; - -class RegisterListenersPassTest extends TestCase -{ - /** - * Tests that event subscribers not implementing EventSubscriberInterface - * trigger an exception. - */ - public function testEventSubscriberWithoutInterface() - { - $this->expectException('InvalidArgumentException'); - $builder = new ContainerBuilder(); - $builder->register('event_dispatcher'); - $builder->register('my_event_subscriber', 'stdClass') - ->addTag('kernel.event_subscriber'); - - $registerListenersPass = new RegisterListenersPass(); - $registerListenersPass->process($builder); - } - - public function testValidEventSubscriber() - { - $builder = new ContainerBuilder(); - $eventDispatcherDefinition = $builder->register('event_dispatcher'); - $builder->register('my_event_subscriber', 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService') - ->addTag('kernel.event_subscriber'); - - $registerListenersPass = new RegisterListenersPass(); - $registerListenersPass->process($builder); - - $expectedCalls = [ - [ - 'addListener', - [ - 'event', - [new ServiceClosureArgument(new Reference('my_event_subscriber')), 'onEvent'], - 0, - ], - ], - ]; - $this->assertEquals($expectedCalls, $eventDispatcherDefinition->getMethodCalls()); - } - - public function testAbstractEventListener() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The service "foo" tagged "kernel.event_listener" must not be abstract.'); - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_listener', []); - $container->register('event_dispatcher', 'stdClass'); - - $registerListenersPass = new RegisterListenersPass(); - $registerListenersPass->process($container); - } - - public function testAbstractEventSubscriber() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('The service "foo" tagged "kernel.event_subscriber" must not be abstract.'); - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->setAbstract(true)->addTag('kernel.event_subscriber', []); - $container->register('event_dispatcher', 'stdClass'); - - $registerListenersPass = new RegisterListenersPass(); - $registerListenersPass->process($container); - } - - public function testEventSubscriberResolvableClassName() - { - $container = new ContainerBuilder(); - - $container->setParameter('subscriber.class', 'Symfony\Component\EventDispatcher\Tests\DependencyInjection\SubscriberService'); - $container->register('foo', '%subscriber.class%')->addTag('kernel.event_subscriber', []); - $container->register('event_dispatcher', 'stdClass'); - - $registerListenersPass = new RegisterListenersPass(); - $registerListenersPass->process($container); - - $definition = $container->getDefinition('event_dispatcher'); - $expectedCalls = [ - [ - 'addListener', - [ - 'event', - [new ServiceClosureArgument(new Reference('foo')), 'onEvent'], - 0, - ], - ], - ]; - $this->assertEquals($expectedCalls, $definition->getMethodCalls()); - } - - public function testHotPathEvents() - { - $container = new ContainerBuilder(); - - $container->register('foo', SubscriberService::class)->addTag('kernel.event_subscriber', []); - $container->register('event_dispatcher', 'stdClass'); - - (new RegisterListenersPass())->setHotPathEvents(['event'])->process($container); - - $this->assertTrue($container->getDefinition('foo')->hasTag('container.hot_path')); - } - - public function testEventSubscriberUnresolvableClassName() - { - $this->expectException('InvalidArgumentException'); - $this->expectExceptionMessage('You have requested a non-existent parameter "subscriber.class"'); - $container = new ContainerBuilder(); - $container->register('foo', '%subscriber.class%')->addTag('kernel.event_subscriber', []); - $container->register('event_dispatcher', 'stdClass'); - - $registerListenersPass = new RegisterListenersPass(); - $registerListenersPass->process($container); - } -} - -class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return [ - 'event' => 'onEvent', - ]; - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php deleted file mode 100644 index 5faa5c8b..00000000 --- a/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use Symfony\Component\EventDispatcher\EventDispatcher; - -class EventDispatcherTest extends AbstractEventDispatcherTest -{ - protected function createEventDispatcher() - { - return new EventDispatcher(); - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/EventTest.php b/vendor/symfony/event-dispatcher/Tests/EventTest.php deleted file mode 100644 index 5be2ea09..00000000 --- a/vendor/symfony/event-dispatcher/Tests/EventTest.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\Event; - -/** - * Test class for Event. - */ -class EventTest extends TestCase -{ - /** - * @var \Symfony\Component\EventDispatcher\Event - */ - protected $event; - - /** - * Sets up the fixture, for example, opens a network connection. - * This method is called before a test is executed. - */ - protected function setUp() - { - $this->event = new Event(); - } - - /** - * Tears down the fixture, for example, closes a network connection. - * This method is called after a test is executed. - */ - protected function tearDown() - { - $this->event = null; - } - - public function testIsPropagationStopped() - { - $this->assertFalse($this->event->isPropagationStopped()); - } - - public function testStopPropagationAndIsPropagationStopped() - { - $this->event->stopPropagation(); - $this->assertTrue($this->event->isPropagationStopped()); - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php b/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php deleted file mode 100644 index f0f0d71f..00000000 --- a/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php +++ /dev/null @@ -1,134 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\GenericEvent; - -/** - * Test class for Event. - */ -class GenericEventTest extends TestCase -{ - /** - * @var GenericEvent - */ - private $event; - - private $subject; - - /** - * Prepares the environment before running a test. - */ - protected function setUp() - { - $this->subject = new \stdClass(); - $this->event = new GenericEvent($this->subject, ['name' => 'Event']); - } - - /** - * Cleans up the environment after running a test. - */ - protected function tearDown() - { - $this->subject = null; - $this->event = null; - } - - public function testConstruct() - { - $this->assertEquals($this->event, new GenericEvent($this->subject, ['name' => 'Event'])); - } - - /** - * Tests Event->getArgs(). - */ - public function testGetArguments() - { - // test getting all - $this->assertSame(['name' => 'Event'], $this->event->getArguments()); - } - - public function testSetArguments() - { - $result = $this->event->setArguments(['foo' => 'bar']); - $this->assertSame(['foo' => 'bar'], $this->event->getArguments()); - $this->assertSame($this->event, $result); - } - - public function testSetArgument() - { - $result = $this->event->setArgument('foo2', 'bar2'); - $this->assertSame(['name' => 'Event', 'foo2' => 'bar2'], $this->event->getArguments()); - $this->assertEquals($this->event, $result); - } - - public function testGetArgument() - { - // test getting key - $this->assertEquals('Event', $this->event->getArgument('name')); - } - - public function testGetArgException() - { - $this->expectException('\InvalidArgumentException'); - $this->event->getArgument('nameNotExist'); - } - - public function testOffsetGet() - { - // test getting key - $this->assertEquals('Event', $this->event['name']); - - // test getting invalid arg - $this->expectException('InvalidArgumentException'); - $this->assertFalse($this->event['nameNotExist']); - } - - public function testOffsetSet() - { - $this->event['foo2'] = 'bar2'; - $this->assertSame(['name' => 'Event', 'foo2' => 'bar2'], $this->event->getArguments()); - } - - public function testOffsetUnset() - { - unset($this->event['name']); - $this->assertSame([], $this->event->getArguments()); - } - - public function testOffsetIsset() - { - $this->assertArrayHasKey('name', $this->event); - $this->assertArrayNotHasKey('nameNotExist', $this->event); - } - - public function testHasArgument() - { - $this->assertTrue($this->event->hasArgument('name')); - $this->assertFalse($this->event->hasArgument('nameNotExist')); - } - - public function testGetSubject() - { - $this->assertSame($this->subject, $this->event->getSubject()); - } - - public function testHasIterator() - { - $data = []; - foreach ($this->event as $key => $value) { - $data[$key] = $value; - } - $this->assertEquals(['name' => 'Event'], $data); - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php deleted file mode 100644 index da8502ab..00000000 --- a/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php +++ /dev/null @@ -1,100 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\EventDispatcher\Tests; - -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\ImmutableEventDispatcher; - -/** - * @author Bernhard Schussek - */ -class ImmutableEventDispatcherTest extends TestCase -{ - /** - * @var MockObject - */ - private $innerDispatcher; - - /** - * @var ImmutableEventDispatcher - */ - private $dispatcher; - - protected function setUp() - { - $this->innerDispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->dispatcher = new ImmutableEventDispatcher($this->innerDispatcher); - } - - public function testDispatchDelegates() - { - $event = new Event(); - $resultEvent = new Event(); - - $this->innerDispatcher->expects($this->once()) - ->method('dispatch') - ->with('event', $event) - ->willReturn($resultEvent); - - $this->assertSame($resultEvent, $this->dispatcher->dispatch('event', $event)); - } - - public function testGetListenersDelegates() - { - $this->innerDispatcher->expects($this->once()) - ->method('getListeners') - ->with('event') - ->willReturn(['result']); - - $this->assertSame(['result'], $this->dispatcher->getListeners('event')); - } - - public function testHasListenersDelegates() - { - $this->innerDispatcher->expects($this->once()) - ->method('hasListeners') - ->with('event') - ->willReturn(true); - - $this->assertTrue($this->dispatcher->hasListeners('event')); - } - - public function testAddListenerDisallowed() - { - $this->expectException('\BadMethodCallException'); - $this->dispatcher->addListener('event', function () { return 'foo'; }); - } - - public function testAddSubscriberDisallowed() - { - $this->expectException('\BadMethodCallException'); - $subscriber = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventSubscriberInterface')->getMock(); - - $this->dispatcher->addSubscriber($subscriber); - } - - public function testRemoveListenerDisallowed() - { - $this->expectException('\BadMethodCallException'); - $this->dispatcher->removeListener('event', function () { return 'foo'; }); - } - - public function testRemoveSubscriberDisallowed() - { - $this->expectException('\BadMethodCallException'); - $subscriber = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventSubscriberInterface')->getMock(); - - $this->dispatcher->removeSubscriber($subscriber); - } -} diff --git a/vendor/symfony/event-dispatcher/composer.json b/vendor/symfony/event-dispatcher/composer.json index 408022f6..55c2716a 100644 --- a/vendor/symfony/event-dispatcher/composer.json +++ b/vendor/symfony/event-dispatcher/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/event-dispatcher", "type": "library", - "description": "Symfony EventDispatcher Component", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,18 +16,26 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8" + "php": ">=7.1.3", + "symfony/event-dispatcher-contracts": "^1.1", + "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/debug": "~3.4|~4.4", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "psr/log": "~1.0" + "symfony/dependency-injection": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/error-handler": "~3.4|~4.4", + "symfony/http-foundation": "^3.4|^4.0|^5.0", + "symfony/service-contracts": "^1.1|^2", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "psr/log": "^1|^2|^3" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" }, "suggest": { "symfony/dependency-injection": "", diff --git a/vendor/symfony/event-dispatcher/phpunit.xml.dist b/vendor/symfony/event-dispatcher/phpunit.xml.dist deleted file mode 100644 index f2eb1692..00000000 --- a/vendor/symfony/event-dispatcher/phpunit.xml.dist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/filesystem/CHANGELOG.md b/vendor/symfony/filesystem/CHANGELOG.md index d01f5f45..fcb7170c 100644 --- a/vendor/symfony/filesystem/CHANGELOG.md +++ b/vendor/symfony/filesystem/CHANGELOG.md @@ -1,6 +1,35 @@ CHANGELOG ========= +5.4 +--- + + * Add `Path` class + * Add `$lock` argument to `Filesystem::appendToFile()` + +5.0.0 +----- + + * `Filesystem::dumpFile()` and `appendToFile()` don't accept arrays anymore + +4.4.0 +----- + + * support for passing a `null` value to `Filesystem::isAbsolutePath()` is deprecated and will be removed in 5.0 + * `tempnam()` now accepts a third argument `$suffix`. + +4.3.0 +----- + + * support for passing arrays to `Filesystem::dumpFile()` is deprecated and will be removed in 5.0 + * support for passing arrays to `Filesystem::appendToFile()` is deprecated and will be removed in 5.0 + +4.0.0 +----- + + * removed `LockHandler` + * Support for passing relative paths to `Filesystem::makePathRelative()` has been removed. + 3.4.0 ----- diff --git a/vendor/symfony/filesystem/Exception/ExceptionInterface.php b/vendor/symfony/filesystem/Exception/ExceptionInterface.php index 8f4f10aa..fc438d9f 100644 --- a/vendor/symfony/filesystem/Exception/ExceptionInterface.php +++ b/vendor/symfony/filesystem/Exception/ExceptionInterface.php @@ -16,6 +16,6 @@ * * @author Romain Neutron */ -interface ExceptionInterface +interface ExceptionInterface extends \Throwable { } diff --git a/vendor/symfony/filesystem/Exception/FileNotFoundException.php b/vendor/symfony/filesystem/Exception/FileNotFoundException.php index bcc8fe81..48b64080 100644 --- a/vendor/symfony/filesystem/Exception/FileNotFoundException.php +++ b/vendor/symfony/filesystem/Exception/FileNotFoundException.php @@ -19,7 +19,7 @@ */ class FileNotFoundException extends IOException { - public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null) + public function __construct(string $message = null, int $code = 0, \Throwable $previous = null, string $path = null) { if (null === $message) { if (null === $path) { diff --git a/vendor/symfony/filesystem/Exception/IOException.php b/vendor/symfony/filesystem/Exception/IOException.php index 144e0e60..fea26e4d 100644 --- a/vendor/symfony/filesystem/Exception/IOException.php +++ b/vendor/symfony/filesystem/Exception/IOException.php @@ -22,7 +22,7 @@ class IOException extends \RuntimeException implements IOExceptionInterface { private $path; - public function __construct($message, $code = 0, \Exception $previous = null, $path = null) + public function __construct(string $message, int $code = 0, \Throwable $previous = null, string $path = null) { $this->path = $path; diff --git a/vendor/symfony/filesystem/Exception/IOExceptionInterface.php b/vendor/symfony/filesystem/Exception/IOExceptionInterface.php index f9d4644a..42829ab6 100644 --- a/vendor/symfony/filesystem/Exception/IOExceptionInterface.php +++ b/vendor/symfony/filesystem/Exception/IOExceptionInterface.php @@ -21,7 +21,7 @@ interface IOExceptionInterface extends ExceptionInterface /** * Returns the associated path for the exception. * - * @return string|null The path + * @return string|null */ public function getPath(); } diff --git a/vendor/symfony/filesystem/Exception/InvalidArgumentException.php b/vendor/symfony/filesystem/Exception/InvalidArgumentException.php new file mode 100644 index 00000000..abadc200 --- /dev/null +++ b/vendor/symfony/filesystem/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Filesystem\Exception; + +/** + * @author Christian Flothmann + */ +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/filesystem/Exception/RuntimeException.php b/vendor/symfony/filesystem/Exception/RuntimeException.php new file mode 100644 index 00000000..a7512dca --- /dev/null +++ b/vendor/symfony/filesystem/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Filesystem\Exception; + +/** + * @author Théo Fidry + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/filesystem/Filesystem.php b/vendor/symfony/filesystem/Filesystem.php index 96b2e960..23192bc7 100644 --- a/vendor/symfony/filesystem/Filesystem.php +++ b/vendor/symfony/filesystem/Filesystem.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Filesystem; use Symfony\Component\Filesystem\Exception\FileNotFoundException; +use Symfony\Component\Filesystem\Exception\InvalidArgumentException; use Symfony\Component\Filesystem\Exception\IOException; /** @@ -30,14 +31,10 @@ class Filesystem * If the target file is newer, it is overwritten only when the * $overwriteNewerFiles option is set to true. * - * @param string $originFile The original filename - * @param string $targetFile The target filename - * @param bool $overwriteNewerFiles If true, target files newer than origin files are overwritten - * * @throws FileNotFoundException When originFile doesn't exist * @throws IOException When copy fails */ - public function copy($originFile, $targetFile, $overwriteNewerFiles = false) + public function copy(string $originFile, string $targetFile, bool $overwriteNewerFiles = false) { $originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://'); if ($originIsLocal && !is_file($originFile)) { @@ -53,13 +50,13 @@ public function copy($originFile, $targetFile, $overwriteNewerFiles = false) if ($doCopy) { // https://bugs.php.net/64634 - if (false === $source = @fopen($originFile, 'r')) { - throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile); + if (!$source = self::box('fopen', $originFile, 'r')) { + throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); } // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default - if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(['ftp' => ['overwrite' => true]]))) { - throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile); + if (!$target = self::box('fopen', $targetFile, 'w', false, stream_context_create(['ftp' => ['overwrite' => true]]))) { + throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing: ', $originFile, $targetFile).self::$lastError, 0, null, $originFile); } $bytesCopied = stream_copy_to_stream($source, $target); @@ -73,7 +70,7 @@ public function copy($originFile, $targetFile, $overwriteNewerFiles = false) if ($originIsLocal) { // Like `cp`, preserve executable permission bits - @chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111)); + self::box('chmod', $targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111)); if ($bytesCopied !== $bytesOrigin = filesize($originFile)) { throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile); @@ -86,25 +83,18 @@ public function copy($originFile, $targetFile, $overwriteNewerFiles = false) * Creates a directory recursively. * * @param string|iterable $dirs The directory path - * @param int $mode The directory mode * * @throws IOException On any directory creation failure */ - public function mkdir($dirs, $mode = 0777) + public function mkdir($dirs, int $mode = 0777) { foreach ($this->toIterable($dirs) as $dir) { if (is_dir($dir)) { continue; } - if (!self::box('mkdir', $dir, $mode, true)) { - if (!is_dir($dir)) { - // The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one - if (self::$lastError) { - throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); - } - throw new IOException(sprintf('Failed to create "%s".', $dir), 0, null, $dir); - } + if (!self::box('mkdir', $dir, $mode, true) && !is_dir($dir)) { + throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); } } } @@ -114,7 +104,7 @@ public function mkdir($dirs, $mode = 0777) * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to check * - * @return bool true if the file exists, false otherwise + * @return bool */ public function exists($files) { @@ -142,12 +132,11 @@ public function exists($files) * * @throws IOException When touch fails */ - public function touch($files, $time = null, $atime = null) + public function touch($files, int $time = null, int $atime = null) { foreach ($this->toIterable($files) as $file) { - $touch = $time ? @touch($file, $time, $atime) : @touch($file); - if (true !== $touch) { - throw new IOException(sprintf('Failed to touch "%s".', $file), 0, null, $file); + if (!($time ? self::box('touch', $file, $time, $atime) : self::box('touch', $file))) { + throw new IOException(sprintf('Failed to touch "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -166,6 +155,12 @@ public function remove($files) } elseif (!\is_array($files)) { $files = [$files]; } + + self::doRemove($files, false); + } + + private static function doRemove(array $files, bool $isRecursive): void + { $files = array_reverse($files); foreach ($files as $file) { if (is_link($file)) { @@ -174,12 +169,37 @@ public function remove($files) throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); } } elseif (is_dir($file)) { - $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)); + if (!$isRecursive) { + $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-_')); + + if (file_exists($tmpName)) { + try { + self::doRemove([$tmpName], true); + } catch (IOException $e) { + } + } - if (!self::box('rmdir', $file) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove directory "%s": ', $file).self::$lastError); + if (!file_exists($tmpName) && self::box('rename', $file, $tmpName)) { + $origFile = $file; + $file = $tmpName; + } else { + $origFile = null; + } } - } elseif (!self::box('unlink', $file) && (false !== strpos(self::$lastError, 'Permission denied') || file_exists($file))) { + + $files = new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS); + self::doRemove(iterator_to_array($files, true), true); + + if (!self::box('rmdir', $file) && file_exists($file) && !$isRecursive) { + $lastError = self::$lastError; + + if (null !== $origFile && self::box('rename', $file, $origFile)) { + $file = $origFile; + } + + throw new IOException(sprintf('Failed to remove directory "%s": ', $file).$lastError); + } + } elseif (!self::box('unlink', $file) && (str_contains(self::$lastError, 'Permission denied') || file_exists($file))) { throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError); } } @@ -195,11 +215,11 @@ public function remove($files) * * @throws IOException When the change fails */ - public function chmod($files, $mode, $umask = 0000, $recursive = false) + public function chmod($files, int $mode, int $umask = 0000, bool $recursive = false) { foreach ($this->toIterable($files) as $file) { - if ((\PHP_VERSION_ID < 80000 || \is_int($mode)) && true !== @chmod($file, $mode & ~$umask)) { - throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file); + if ((\PHP_VERSION_ID < 80000 || \is_int($mode)) && !self::box('chmod', $file, $mode & ~$umask)) { + throw new IOException(sprintf('Failed to chmod file "%s": ', $file).self::$lastError, 0, null, $file); } if ($recursive && is_dir($file) && !is_link($file)) { $this->chmod(new \FilesystemIterator($file), $mode, $umask, true); @@ -216,19 +236,19 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) * * @throws IOException When the change fails */ - public function chown($files, $user, $recursive = false) + public function chown($files, $user, bool $recursive = false) { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { $this->chown(new \FilesystemIterator($file), $user, true); } if (is_link($file) && \function_exists('lchown')) { - if (true !== @lchown($file, $user)) { - throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file); + if (!self::box('lchown', $file, $user)) { + throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); } } else { - if (true !== @chown($file, $user)) { - throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file); + if (!self::box('chown', $file, $user)) { + throw new IOException(sprintf('Failed to chown file "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -243,19 +263,19 @@ public function chown($files, $user, $recursive = false) * * @throws IOException When the change fails */ - public function chgrp($files, $group, $recursive = false) + public function chgrp($files, $group, bool $recursive = false) { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { $this->chgrp(new \FilesystemIterator($file), $group, true); } if (is_link($file) && \function_exists('lchgrp')) { - if (true !== @lchgrp($file, $group) || (\defined('HHVM_VERSION') && !posix_getgrnam($group))) { - throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file); + if (!self::box('lchgrp', $file, $group)) { + throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); } } else { - if (true !== @chgrp($file, $group)) { - throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file); + if (!self::box('chgrp', $file, $group)) { + throw new IOException(sprintf('Failed to chgrp file "%s": ', $file).self::$lastError, 0, null, $file); } } } @@ -264,21 +284,17 @@ public function chgrp($files, $group, $recursive = false) /** * Renames a file or a directory. * - * @param string $origin The origin filename or directory - * @param string $target The new filename or directory - * @param bool $overwrite Whether to overwrite the target if it already exists - * * @throws IOException When target file or directory already exists * @throws IOException When origin cannot be renamed */ - public function rename($origin, $target, $overwrite = false) + public function rename(string $origin, string $target, bool $overwrite = false) { // we check that target does not exist if (!$overwrite && $this->isReadable($target)) { throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target); } - if (true !== @rename($origin, $target)) { + if (!self::box('rename', $origin, $target)) { if (is_dir($origin)) { // See https://bugs.php.net/54097 & https://php.net/rename#113943 $this->mirror($origin, $target, null, ['override' => $overwrite, 'delete' => $overwrite]); @@ -286,20 +302,16 @@ public function rename($origin, $target, $overwrite = false) return; } - throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target); + throw new IOException(sprintf('Cannot rename "%s" to "%s": ', $origin, $target).self::$lastError, 0, null, $target); } } /** * Tells whether a file exists and is readable. * - * @param string $filename Path to the file - * - * @return bool - * * @throws IOException When windows path is longer than 258 characters */ - private function isReadable($filename) + private function isReadable(string $filename): bool { $maxPathLength = \PHP_MAXPATHLEN - 2; @@ -313,14 +325,12 @@ private function isReadable($filename) /** * Creates a symbolic link or copy a directory. * - * @param string $originDir The origin directory path - * @param string $targetDir The symbolic link name - * @param bool $copyOnWindows Whether to copy files if on Windows - * * @throws IOException When symlink fails */ - public function symlink($originDir, $targetDir, $copyOnWindows = false) + public function symlink(string $originDir, string $targetDir, bool $copyOnWindows = false) { + self::assertFunctionExists('symlink'); + if ('\\' === \DIRECTORY_SEPARATOR) { $originDir = strtr($originDir, '/', '\\'); $targetDir = strtr($targetDir, '/', '\\'); @@ -349,14 +359,15 @@ public function symlink($originDir, $targetDir, $copyOnWindows = false) /** * Creates a hard link, or several hard links to a file. * - * @param string $originFile The original file * @param string|string[] $targetFiles The target file(s) * * @throws FileNotFoundException When original file is missing or not a file * @throws IOException When link fails, including if link already exists */ - public function hardlink($originFile, $targetFiles) + public function hardlink(string $originFile, $targetFiles) { + self::assertFunctionExists('link'); + if (!$this->exists($originFile)) { throw new FileNotFoundException(null, 0, null, $originFile); } @@ -380,18 +391,16 @@ public function hardlink($originFile, $targetFiles) } /** - * @param string $origin - * @param string $target * @param string $linkType Name of the link type, typically 'symbolic' or 'hard' */ - private function linkException($origin, $target, $linkType) + private function linkException(string $origin, string $target, string $linkType) { if (self::$lastError) { - if ('\\' === \DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) { + if ('\\' === \DIRECTORY_SEPARATOR && str_contains(self::$lastError, 'error code(1314)')) { throw new IOException(sprintf('Unable to create "%s" link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target); } } - throw new IOException(sprintf('Failed to create "%s" link from "%s" to "%s".', $linkType, $origin, $target), 0, null, $target); + throw new IOException(sprintf('Failed to create "%s" link from "%s" to "%s": ', $linkType, $origin, $target).self::$lastError, 0, null, $target); } /** @@ -405,12 +414,9 @@ private function linkException($origin, $target, $linkType) * - if $path does not exist, returns null * - if $path exists, returns its absolute fully resolved final version * - * @param string $path A filesystem path - * @param bool $canonicalize Whether or not to return a canonicalized path - * * @return string|null */ - public function readlink($path, $canonicalize = false) + public function readlink(string $path, bool $canonicalize = false) { if (!$canonicalize && !is_link($path)) { return null; @@ -421,14 +427,14 @@ public function readlink($path, $canonicalize = false) return null; } - if ('\\' === \DIRECTORY_SEPARATOR) { + if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70410) { $path = readlink($path); } return realpath($path); } - if ('\\' === \DIRECTORY_SEPARATOR) { + if ('\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 70400) { return realpath($path); } @@ -438,15 +444,16 @@ public function readlink($path, $canonicalize = false) /** * Given an existing path, convert it to a path relative to a given starting path. * - * @param string $endPath Absolute path of target - * @param string $startPath Absolute path where traversal begins - * - * @return string Path of target relative to starting path + * @return string */ - public function makePathRelative($endPath, $startPath) + public function makePathRelative(string $endPath, string $startPath) { - if (!$this->isAbsolutePath($endPath) || !$this->isAbsolutePath($startPath)) { - @trigger_error(sprintf('Support for passing relative paths to %s() is deprecated since Symfony 3.4 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED); + if (!$this->isAbsolutePath($startPath)) { + throw new InvalidArgumentException(sprintf('The start path "%s" is not absolute.', $startPath)); + } + + if (!$this->isAbsolutePath($endPath)) { + throw new InvalidArgumentException(sprintf('The end path "%s" is not absolute.', $endPath)); } // Normalize separators on Windows @@ -461,11 +468,11 @@ public function makePathRelative($endPath, $startPath) : [$path, null]; }; - $splitPath = function ($path, $absolute) { + $splitPath = function ($path) { $result = []; foreach (explode('/', trim($path, '/')) as $segment) { - if ('..' === $segment && ($absolute || \count($result))) { + if ('..' === $segment) { array_pop($result); } elseif ('.' !== $segment && '' !== $segment) { $result[] = $segment; @@ -475,11 +482,11 @@ public function makePathRelative($endPath, $startPath) return $result; }; - list($endPath, $endDriveLetter) = $splitDriveLetter($endPath); - list($startPath, $startDriveLetter) = $splitDriveLetter($startPath); + [$endPath, $endDriveLetter] = $splitDriveLetter($endPath); + [$startPath, $startDriveLetter] = $splitDriveLetter($startPath); - $startPathArr = $splitPath($startPath, static::isAbsolutePath($startPath)); - $endPathArr = $splitPath($endPath, static::isAbsolutePath($endPath)); + $startPathArr = $splitPath($startPath); + $endPathArr = $splitPath($endPath); if ($endDriveLetter && $startDriveLetter && $endDriveLetter != $startDriveLetter) { // End path is on another drive, so no relative path exists @@ -518,23 +525,25 @@ public function makePathRelative($endPath, $startPath) * - existing files in the target directory will be overwritten, except if they are newer (see the `override` option) * - files in the target directory that do not exist in the source directory will not be deleted (see the `delete` option) * - * @param string $originDir The origin directory - * @param string $targetDir The target directory - * @param \Traversable|null $iterator Iterator that filters which files and directories to copy, if null a recursive iterator is created - * @param array $options An array of boolean options - * Valid options are: - * - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false) - * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) - * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) + * @param \Traversable|null $iterator Iterator that filters which files and directories to copy, if null a recursive iterator is created + * @param array $options An array of boolean options + * Valid options are: + * - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false) + * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) + * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) * * @throws IOException When file type is unknown */ - public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = []) + public function mirror(string $originDir, string $targetDir, \Traversable $iterator = null, array $options = []) { $targetDir = rtrim($targetDir, '/\\'); $originDir = rtrim($originDir, '/\\'); $originDirLen = \strlen($originDir); + if (!$this->exists($originDir)) { + throw new IOException(sprintf('The origin directory specified "%s" was not found.', $originDir), 0, null, $originDir); + } + // Iterate in destination folder to remove obsolete entries if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) { $deleteIterator = $iterator; @@ -551,41 +560,32 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o } } - $copyOnWindows = false; - if (isset($options['copy_on_windows'])) { - $copyOnWindows = $options['copy_on_windows']; - } + $copyOnWindows = $options['copy_on_windows'] ?? false; if (null === $iterator) { $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS; $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST); } - if ($this->exists($originDir)) { - $this->mkdir($targetDir); - } + $this->mkdir($targetDir); + $filesCreatedWhileMirroring = []; foreach ($iterator as $file) { + if ($file->getPathname() === $targetDir || $file->getRealPath() === $targetDir || isset($filesCreatedWhileMirroring[$file->getRealPath()])) { + continue; + } + $target = $targetDir.substr($file->getPathname(), $originDirLen); + $filesCreatedWhileMirroring[$target] = true; - if ($copyOnWindows) { - if (is_file($file)) { - $this->copy($file, $target, isset($options['override']) ? $options['override'] : false); - } elseif (is_dir($file)) { - $this->mkdir($target); - } else { - throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); - } + if (!$copyOnWindows && is_link($file)) { + $this->symlink($file->getLinkTarget(), $target); + } elseif (is_dir($file)) { + $this->mkdir($target); + } elseif (is_file($file)) { + $this->copy($file, $target, $options['override'] ?? false); } else { - if (is_link($file)) { - $this->symlink($file->getLinkTarget(), $target); - } elseif (is_dir($file)) { - $this->mkdir($target); - } elseif (is_file($file)) { - $this->copy($file, $target, isset($options['override']) ? $options['override'] : false); - } else { - throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); - } + throw new IOException(sprintf('Unable to guess "%s" file type.', $file), 0, null, $file); } } } @@ -593,13 +593,11 @@ public function mirror($originDir, $targetDir, \Traversable $iterator = null, $o /** * Returns whether the file path is an absolute path. * - * @param string $file A file path - * * @return bool */ - public function isAbsolutePath($file) + public function isAbsolutePath(string $file) { - return '' !== (string) $file && (strspn($file, '/\\', 0, 1) + return '' !== $file && (strspn($file, '/\\', 0, 1) || (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && strspn($file, '/\\', 2, 1) @@ -611,22 +609,21 @@ public function isAbsolutePath($file) /** * Creates a temporary file with support for custom stream wrappers. * - * @param string $dir The directory where the temporary filename will be created * @param string $prefix The prefix of the generated temporary filename * Note: Windows uses only the first three characters of prefix + * @param string $suffix The suffix of the generated temporary filename * * @return string The new temporary filename (with path), or throw an exception on failure */ - public function tempnam($dir, $prefix) + public function tempnam(string $dir, string $prefix/* , string $suffix = '' */) { - list($scheme, $hierarchy) = $this->getSchemeAndHierarchy($dir); + $suffix = \func_num_args() > 2 ? func_get_arg(2) : ''; + [$scheme, $hierarchy] = $this->getSchemeAndHierarchy($dir); // If no scheme or scheme is "file" or "gs" (Google Cloud) create temp file in local filesystem - if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) { - $tmpFile = @tempnam($hierarchy, $prefix); - + if ((null === $scheme || 'file' === $scheme || 'gs' === $scheme) && '' === $suffix) { // If tempnam failed or no scheme return the filename otherwise prepend the scheme - if (false !== $tmpFile) { + if ($tmpFile = self::box('tempnam', $hierarchy, $prefix)) { if (null !== $scheme && 'gs' !== $scheme) { return $scheme.'://'.$tmpFile; } @@ -634,140 +631,144 @@ public function tempnam($dir, $prefix) return $tmpFile; } - throw new IOException('A temporary file could not be created.'); + throw new IOException('A temporary file could not be created: '.self::$lastError); } // Loop until we create a valid temp file or have reached 10 attempts for ($i = 0; $i < 10; ++$i) { // Create a unique filename - $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true); + $tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true).$suffix; // Use fopen instead of file_exists as some streams do not support stat // Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability - $handle = @fopen($tmpFile, 'x+'); - - // If unsuccessful restart the loop - if (false === $handle) { + if (!$handle = self::box('fopen', $tmpFile, 'x+')) { continue; } // Close the file if it was successfully opened - @fclose($handle); + self::box('fclose', $handle); return $tmpFile; } - throw new IOException('A temporary file could not be created.'); + throw new IOException('A temporary file could not be created: '.self::$lastError); } /** * Atomically dumps content into a file. * - * @param string $filename The file to be written to - * @param string $content The data to write into the file + * @param string|resource $content The data to write into the file * * @throws IOException if the file cannot be written to */ - public function dumpFile($filename, $content) + public function dumpFile(string $filename, $content) { + if (\is_array($content)) { + throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); + } + $dir = \dirname($filename); - if (!is_dir($dir)) { - $this->mkdir($dir); + if (is_link($filename) && $linkTarget = $this->readlink($filename)) { + $this->dumpFile(Path::makeAbsolute($linkTarget, $dir), $content); + + return; } - if (!is_writable($dir)) { - throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir); + if (!is_dir($dir)) { + $this->mkdir($dir); } // Will create a temp file with 0600 access rights // when the filesystem supports chmod. $tmpFile = $this->tempnam($dir, basename($filename)); - if (false === @file_put_contents($tmpFile, $content)) { - throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename); - } + try { + if (false === self::box('file_put_contents', $tmpFile, $content)) { + throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); + } - @chmod($tmpFile, file_exists($filename) ? fileperms($filename) : 0666 & ~umask()); + self::box('chmod', $tmpFile, file_exists($filename) ? fileperms($filename) : 0666 & ~umask()); - $this->rename($tmpFile, $filename, true); + $this->rename($tmpFile, $filename, true); + } finally { + if (file_exists($tmpFile)) { + self::box('unlink', $tmpFile); + } + } } /** * Appends content to an existing file. * - * @param string $filename The file to which to append content - * @param string $content The content to append + * @param string|resource $content The content to append + * @param bool $lock Whether the file should be locked when writing to it * * @throws IOException If the file is not writable */ - public function appendToFile($filename, $content) + public function appendToFile(string $filename, $content/* , bool $lock = false */) { + if (\is_array($content)) { + throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be string or resource, array given.', __METHOD__)); + } + $dir = \dirname($filename); if (!is_dir($dir)) { $this->mkdir($dir); } - if (!is_writable($dir)) { - throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir); - } + $lock = \func_num_args() > 2 && func_get_arg(2); - if (false === @file_put_contents($filename, $content, \FILE_APPEND)) { - throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename); + if (false === self::box('file_put_contents', $filename, $content, \FILE_APPEND | ($lock ? \LOCK_EX : 0))) { + throw new IOException(sprintf('Failed to write file "%s": ', $filename).self::$lastError, 0, null, $filename); } } - /** - * @param mixed $files - * - * @return array|\Traversable - */ - private function toIterable($files) + private function toIterable($files): iterable { - return \is_array($files) || $files instanceof \Traversable ? $files : [$files]; + return is_iterable($files) ? $files : [$files]; } /** * Gets a 2-tuple of scheme (may be null) and hierarchical part of a filename (e.g. file:///tmp -> [file, tmp]). - * - * @param string $filename The filename to be parsed - * - * @return array The filename scheme and hierarchical part */ - private function getSchemeAndHierarchy($filename) + private function getSchemeAndHierarchy(string $filename): array { $components = explode('://', $filename, 2); return 2 === \count($components) ? [$components[0], $components[1]] : [null, $components[0]]; } + private static function assertFunctionExists(string $func): void + { + if (!\function_exists($func)) { + throw new IOException(sprintf('Unable to perform filesystem operation because the "%s()" function has been disabled.', $func)); + } + } + /** - * @param callable $func + * @param mixed ...$args * * @return mixed */ - private static function box($func) + private static function box(string $func, ...$args) { + self::assertFunctionExists($func); + self::$lastError = null; set_error_handler(__CLASS__.'::handleError'); try { - $result = \call_user_func_array($func, \array_slice(\func_get_args(), 1)); + return $func(...$args); + } finally { restore_error_handler(); - - return $result; - } catch (\Throwable $e) { - } catch (\Exception $e) { } - restore_error_handler(); - - throw $e; } /** * @internal */ - public static function handleError($type, $msg) + public static function handleError(int $type, string $msg) { self::$lastError = $msg; } diff --git a/vendor/symfony/filesystem/LICENSE b/vendor/symfony/filesystem/LICENSE index 9e936ec0..0138f8f0 100644 --- a/vendor/symfony/filesystem/LICENSE +++ b/vendor/symfony/filesystem/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/filesystem/LockHandler.php b/vendor/symfony/filesystem/LockHandler.php deleted file mode 100644 index 2aacfa71..00000000 --- a/vendor/symfony/filesystem/LockHandler.php +++ /dev/null @@ -1,121 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Filesystem; - -use Symfony\Component\Filesystem\Exception\IOException; -use Symfony\Component\Lock\Store\FlockStore; -use Symfony\Component\Lock\Store\SemaphoreStore; - -@trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Use %s or %s instead.', LockHandler::class, SemaphoreStore::class, FlockStore::class), \E_USER_DEPRECATED); - -/** - * LockHandler class provides a simple abstraction to lock anything by means of - * a file lock. - * - * A locked file is created based on the lock name when calling lock(). Other - * lock handlers will not be able to lock the same name until it is released - * (explicitly by calling release() or implicitly when the instance holding the - * lock is destroyed). - * - * @author Grégoire Pineau - * @author Romain Neutron - * @author Nicolas Grekas - * - * @deprecated since version 3.4, to be removed in 4.0. Use Symfony\Component\Lock\Store\SemaphoreStore or Symfony\Component\Lock\Store\FlockStore instead. - */ -class LockHandler -{ - private $file; - private $handle; - - /** - * @param string $name The lock name - * @param string|null $lockPath The directory to store the lock. Default values will use temporary directory - * - * @throws IOException If the lock directory could not be created or is not writable - */ - public function __construct($name, $lockPath = null) - { - $lockPath = $lockPath ?: sys_get_temp_dir(); - - if (!is_dir($lockPath)) { - $fs = new Filesystem(); - $fs->mkdir($lockPath); - } - - if (!is_writable($lockPath)) { - throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath); - } - - $this->file = sprintf('%s/sf.%s.%s.lock', $lockPath, preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name)); - } - - /** - * Lock the resource. - * - * @param bool $blocking Wait until the lock is released - * - * @return bool Returns true if the lock was acquired, false otherwise - * - * @throws IOException If the lock file could not be created or opened - */ - public function lock($blocking = false) - { - if ($this->handle) { - return true; - } - - $error = null; - - // Silence error reporting - set_error_handler(function ($errno, $msg) use (&$error) { - $error = $msg; - }); - - if (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) { - if ($this->handle = fopen($this->file, 'x')) { - chmod($this->file, 0666); - } elseif (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) { - usleep(100); // Give some time for chmod() to complete - $this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r'); - } - } - restore_error_handler(); - - if (!$this->handle) { - throw new IOException($error, 0, null, $this->file); - } - - // On Windows, even if PHP doc says the contrary, LOCK_NB works, see - // https://bugs.php.net/54129 - if (!flock($this->handle, \LOCK_EX | ($blocking ? 0 : \LOCK_NB))) { - fclose($this->handle); - $this->handle = null; - - return false; - } - - return true; - } - - /** - * Release the resource. - */ - public function release() - { - if ($this->handle) { - flock($this->handle, \LOCK_UN | \LOCK_NB); - fclose($this->handle); - $this->handle = null; - } - } -} diff --git a/vendor/symfony/filesystem/Path.php b/vendor/symfony/filesystem/Path.php new file mode 100644 index 00000000..9aa37355 --- /dev/null +++ b/vendor/symfony/filesystem/Path.php @@ -0,0 +1,819 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Filesystem; + +use Symfony\Component\Filesystem\Exception\InvalidArgumentException; +use Symfony\Component\Filesystem\Exception\RuntimeException; + +/** + * Contains utility methods for handling path strings. + * + * The methods in this class are able to deal with both UNIX and Windows paths + * with both forward and backward slashes. All methods return normalized parts + * containing only forward slashes and no excess "." and ".." segments. + * + * @author Bernhard Schussek + * @author Thomas Schulz + * @author Théo Fidry + */ +final class Path +{ + /** + * The number of buffer entries that triggers a cleanup operation. + */ + private const CLEANUP_THRESHOLD = 1250; + + /** + * The buffer size after the cleanup operation. + */ + private const CLEANUP_SIZE = 1000; + + /** + * Buffers input/output of {@link canonicalize()}. + * + * @var array + */ + private static $buffer = []; + + /** + * @var int + */ + private static $bufferSize = 0; + + /** + * Canonicalizes the given path. + * + * During normalization, all slashes are replaced by forward slashes ("/"). + * Furthermore, all "." and ".." segments are removed as far as possible. + * ".." segments at the beginning of relative paths are not removed. + * + * ```php + * echo Path::canonicalize("\symfony\puli\..\css\style.css"); + * // => /symfony/css/style.css + * + * echo Path::canonicalize("../css/./style.css"); + * // => ../css/style.css + * ``` + * + * This method is able to deal with both UNIX and Windows paths. + */ + public static function canonicalize(string $path): string + { + if ('' === $path) { + return ''; + } + + // This method is called by many other methods in this class. Buffer + // the canonicalized paths to make up for the severe performance + // decrease. + if (isset(self::$buffer[$path])) { + return self::$buffer[$path]; + } + + // Replace "~" with user's home directory. + if ('~' === $path[0]) { + $path = self::getHomeDirectory().substr($path, 1); + } + + $path = self::normalize($path); + + [$root, $pathWithoutRoot] = self::split($path); + + $canonicalParts = self::findCanonicalParts($root, $pathWithoutRoot); + + // Add the root directory again + self::$buffer[$path] = $canonicalPath = $root.implode('/', $canonicalParts); + ++self::$bufferSize; + + // Clean up regularly to prevent memory leaks + if (self::$bufferSize > self::CLEANUP_THRESHOLD) { + self::$buffer = \array_slice(self::$buffer, -self::CLEANUP_SIZE, null, true); + self::$bufferSize = self::CLEANUP_SIZE; + } + + return $canonicalPath; + } + + /** + * Normalizes the given path. + * + * During normalization, all slashes are replaced by forward slashes ("/"). + * Contrary to {@link canonicalize()}, this method does not remove invalid + * or dot path segments. Consequently, it is much more efficient and should + * be used whenever the given path is known to be a valid, absolute system + * path. + * + * This method is able to deal with both UNIX and Windows paths. + */ + public static function normalize(string $path): string + { + return str_replace('\\', '/', $path); + } + + /** + * Returns the directory part of the path. + * + * This method is similar to PHP's dirname(), but handles various cases + * where dirname() returns a weird result: + * + * - dirname() does not accept backslashes on UNIX + * - dirname("C:/symfony") returns "C:", not "C:/" + * - dirname("C:/") returns ".", not "C:/" + * - dirname("C:") returns ".", not "C:/" + * - dirname("symfony") returns ".", not "" + * - dirname() does not canonicalize the result + * + * This method fixes these shortcomings and behaves like dirname() + * otherwise. + * + * The result is a canonical path. + * + * @return string The canonical directory part. Returns the root directory + * if the root directory is passed. Returns an empty string + * if a relative path is passed that contains no slashes. + * Returns an empty string if an empty string is passed. + */ + public static function getDirectory(string $path): string + { + if ('' === $path) { + return ''; + } + + $path = self::canonicalize($path); + + // Maintain scheme + if (false !== $schemeSeparatorPosition = strpos($path, '://')) { + $scheme = substr($path, 0, $schemeSeparatorPosition + 3); + $path = substr($path, $schemeSeparatorPosition + 3); + } else { + $scheme = ''; + } + + if (false === $dirSeparatorPosition = strrpos($path, '/')) { + return ''; + } + + // Directory equals root directory "/" + if (0 === $dirSeparatorPosition) { + return $scheme.'/'; + } + + // Directory equals Windows root "C:/" + if (2 === $dirSeparatorPosition && ctype_alpha($path[0]) && ':' === $path[1]) { + return $scheme.substr($path, 0, 3); + } + + return $scheme.substr($path, 0, $dirSeparatorPosition); + } + + /** + * Returns canonical path of the user's home directory. + * + * Supported operating systems: + * + * - UNIX + * - Windows8 and upper + * + * If your operating system or environment isn't supported, an exception is thrown. + * + * The result is a canonical path. + * + * @throws RuntimeException If your operating system or environment isn't supported + */ + public static function getHomeDirectory(): string + { + // For UNIX support + if (getenv('HOME')) { + return self::canonicalize(getenv('HOME')); + } + + // For >= Windows8 support + if (getenv('HOMEDRIVE') && getenv('HOMEPATH')) { + return self::canonicalize(getenv('HOMEDRIVE').getenv('HOMEPATH')); + } + + throw new RuntimeException("Cannot find the home directory path: Your environment or operating system isn't supported."); + } + + /** + * Returns the root directory of a path. + * + * The result is a canonical path. + * + * @return string The canonical root directory. Returns an empty string if + * the given path is relative or empty. + */ + public static function getRoot(string $path): string + { + if ('' === $path) { + return ''; + } + + // Maintain scheme + if (false !== $schemeSeparatorPosition = strpos($path, '://')) { + $scheme = substr($path, 0, $schemeSeparatorPosition + 3); + $path = substr($path, $schemeSeparatorPosition + 3); + } else { + $scheme = ''; + } + + $firstCharacter = $path[0]; + + // UNIX root "/" or "\" (Windows style) + if ('/' === $firstCharacter || '\\' === $firstCharacter) { + return $scheme.'/'; + } + + $length = \strlen($path); + + // Windows root + if ($length > 1 && ':' === $path[1] && ctype_alpha($firstCharacter)) { + // Special case: "C:" + if (2 === $length) { + return $scheme.$path.'/'; + } + + // Normal case: "C:/ or "C:\" + if ('/' === $path[2] || '\\' === $path[2]) { + return $scheme.$firstCharacter.$path[1].'/'; + } + } + + return ''; + } + + /** + * Returns the file name without the extension from a file path. + * + * @param string|null $extension if specified, only that extension is cut + * off (may contain leading dot) + */ + public static function getFilenameWithoutExtension(string $path, string $extension = null): string + { + if ('' === $path) { + return ''; + } + + if (null !== $extension) { + // remove extension and trailing dot + return rtrim(basename($path, $extension), '.'); + } + + return pathinfo($path, \PATHINFO_FILENAME); + } + + /** + * Returns the extension from a file path (without leading dot). + * + * @param bool $forceLowerCase forces the extension to be lower-case + */ + public static function getExtension(string $path, bool $forceLowerCase = false): string + { + if ('' === $path) { + return ''; + } + + $extension = pathinfo($path, \PATHINFO_EXTENSION); + + if ($forceLowerCase) { + $extension = self::toLower($extension); + } + + return $extension; + } + + /** + * Returns whether the path has an (or the specified) extension. + * + * @param string $path the path string + * @param string|string[]|null $extensions if null or not provided, checks if + * an extension exists, otherwise + * checks for the specified extension + * or array of extensions (with or + * without leading dot) + * @param bool $ignoreCase whether to ignore case-sensitivity + */ + public static function hasExtension(string $path, $extensions = null, bool $ignoreCase = false): bool + { + if ('' === $path) { + return false; + } + + $actualExtension = self::getExtension($path, $ignoreCase); + + // Only check if path has any extension + if ([] === $extensions || null === $extensions) { + return '' !== $actualExtension; + } + + if (\is_string($extensions)) { + $extensions = [$extensions]; + } + + foreach ($extensions as $key => $extension) { + if ($ignoreCase) { + $extension = self::toLower($extension); + } + + // remove leading '.' in extensions array + $extensions[$key] = ltrim($extension, '.'); + } + + return \in_array($actualExtension, $extensions, true); + } + + /** + * Changes the extension of a path string. + * + * @param string $path The path string with filename.ext to change. + * @param string $extension new extension (with or without leading dot) + * + * @return string the path string with new file extension + */ + public static function changeExtension(string $path, string $extension): string + { + if ('' === $path) { + return ''; + } + + $actualExtension = self::getExtension($path); + $extension = ltrim($extension, '.'); + + // No extension for paths + if ('/' === substr($path, -1)) { + return $path; + } + + // No actual extension in path + if (empty($actualExtension)) { + return $path.('.' === substr($path, -1) ? '' : '.').$extension; + } + + return substr($path, 0, -\strlen($actualExtension)).$extension; + } + + public static function isAbsolute(string $path): bool + { + if ('' === $path) { + return false; + } + + // Strip scheme + if (false !== $schemeSeparatorPosition = strpos($path, '://')) { + $path = substr($path, $schemeSeparatorPosition + 3); + } + + $firstCharacter = $path[0]; + + // UNIX root "/" or "\" (Windows style) + if ('/' === $firstCharacter || '\\' === $firstCharacter) { + return true; + } + + // Windows root + if (\strlen($path) > 1 && ctype_alpha($firstCharacter) && ':' === $path[1]) { + // Special case: "C:" + if (2 === \strlen($path)) { + return true; + } + + // Normal case: "C:/ or "C:\" + if ('/' === $path[2] || '\\' === $path[2]) { + return true; + } + } + + return false; + } + + public static function isRelative(string $path): bool + { + return !self::isAbsolute($path); + } + + /** + * Turns a relative path into an absolute path in canonical form. + * + * Usually, the relative path is appended to the given base path. Dot + * segments ("." and "..") are removed/collapsed and all slashes turned + * into forward slashes. + * + * ```php + * echo Path::makeAbsolute("../style.css", "/symfony/puli/css"); + * // => /symfony/puli/style.css + * ``` + * + * If an absolute path is passed, that path is returned unless its root + * directory is different than the one of the base path. In that case, an + * exception is thrown. + * + * ```php + * Path::makeAbsolute("/style.css", "/symfony/puli/css"); + * // => /style.css + * + * Path::makeAbsolute("C:/style.css", "C:/symfony/puli/css"); + * // => C:/style.css + * + * Path::makeAbsolute("C:/style.css", "/symfony/puli/css"); + * // InvalidArgumentException + * ``` + * + * If the base path is not an absolute path, an exception is thrown. + * + * The result is a canonical path. + * + * @param string $basePath an absolute base path + * + * @throws InvalidArgumentException if the base path is not absolute or if + * the given path is an absolute path with + * a different root than the base path + */ + public static function makeAbsolute(string $path, string $basePath): string + { + if ('' === $basePath) { + throw new InvalidArgumentException(sprintf('The base path must be a non-empty string. Got: "%s".', $basePath)); + } + + if (!self::isAbsolute($basePath)) { + throw new InvalidArgumentException(sprintf('The base path "%s" is not an absolute path.', $basePath)); + } + + if (self::isAbsolute($path)) { + return self::canonicalize($path); + } + + if (false !== $schemeSeparatorPosition = strpos($basePath, '://')) { + $scheme = substr($basePath, 0, $schemeSeparatorPosition + 3); + $basePath = substr($basePath, $schemeSeparatorPosition + 3); + } else { + $scheme = ''; + } + + return $scheme.self::canonicalize(rtrim($basePath, '/\\').'/'.$path); + } + + /** + * Turns a path into a relative path. + * + * The relative path is created relative to the given base path: + * + * ```php + * echo Path::makeRelative("/symfony/style.css", "/symfony/puli"); + * // => ../style.css + * ``` + * + * If a relative path is passed and the base path is absolute, the relative + * path is returned unchanged: + * + * ```php + * Path::makeRelative("style.css", "/symfony/puli/css"); + * // => style.css + * ``` + * + * If both paths are relative, the relative path is created with the + * assumption that both paths are relative to the same directory: + * + * ```php + * Path::makeRelative("style.css", "symfony/puli/css"); + * // => ../../../style.css + * ``` + * + * If both paths are absolute, their root directory must be the same, + * otherwise an exception is thrown: + * + * ```php + * Path::makeRelative("C:/symfony/style.css", "/symfony/puli"); + * // InvalidArgumentException + * ``` + * + * If the passed path is absolute, but the base path is not, an exception + * is thrown as well: + * + * ```php + * Path::makeRelative("/symfony/style.css", "symfony/puli"); + * // InvalidArgumentException + * ``` + * + * If the base path is not an absolute path, an exception is thrown. + * + * The result is a canonical path. + * + * @throws InvalidArgumentException if the base path is not absolute or if + * the given path has a different root + * than the base path + */ + public static function makeRelative(string $path, string $basePath): string + { + $path = self::canonicalize($path); + $basePath = self::canonicalize($basePath); + + [$root, $relativePath] = self::split($path); + [$baseRoot, $relativeBasePath] = self::split($basePath); + + // If the base path is given as absolute path and the path is already + // relative, consider it to be relative to the given absolute path + // already + if ('' === $root && '' !== $baseRoot) { + // If base path is already in its root + if ('' === $relativeBasePath) { + $relativePath = ltrim($relativePath, './\\'); + } + + return $relativePath; + } + + // If the passed path is absolute, but the base path is not, we + // cannot generate a relative path + if ('' !== $root && '' === $baseRoot) { + throw new InvalidArgumentException(sprintf('The absolute path "%s" cannot be made relative to the relative path "%s". You should provide an absolute base path instead.', $path, $basePath)); + } + + // Fail if the roots of the two paths are different + if ($baseRoot && $root !== $baseRoot) { + throw new InvalidArgumentException(sprintf('The path "%s" cannot be made relative to "%s", because they have different roots ("%s" and "%s").', $path, $basePath, $root, $baseRoot)); + } + + if ('' === $relativeBasePath) { + return $relativePath; + } + + // Build a "../../" prefix with as many "../" parts as necessary + $parts = explode('/', $relativePath); + $baseParts = explode('/', $relativeBasePath); + $dotDotPrefix = ''; + + // Once we found a non-matching part in the prefix, we need to add + // "../" parts for all remaining parts + $match = true; + + foreach ($baseParts as $index => $basePart) { + if ($match && isset($parts[$index]) && $basePart === $parts[$index]) { + unset($parts[$index]); + + continue; + } + + $match = false; + $dotDotPrefix .= '../'; + } + + return rtrim($dotDotPrefix.implode('/', $parts), '/'); + } + + /** + * Returns whether the given path is on the local filesystem. + */ + public static function isLocal(string $path): bool + { + return '' !== $path && false === strpos($path, '://'); + } + + /** + * Returns the longest common base path in canonical form of a set of paths or + * `null` if the paths are on different Windows partitions. + * + * Dot segments ("." and "..") are removed/collapsed and all slashes turned + * into forward slashes. + * + * ```php + * $basePath = Path::getLongestCommonBasePath( + * '/symfony/css/style.css', + * '/symfony/css/..' + * ); + * // => /symfony + * ``` + * + * The root is returned if no common base path can be found: + * + * ```php + * $basePath = Path::getLongestCommonBasePath( + * '/symfony/css/style.css', + * '/puli/css/..' + * ); + * // => / + * ``` + * + * If the paths are located on different Windows partitions, `null` is + * returned. + * + * ```php + * $basePath = Path::getLongestCommonBasePath( + * 'C:/symfony/css/style.css', + * 'D:/symfony/css/..' + * ); + * // => null + * ``` + */ + public static function getLongestCommonBasePath(string ...$paths): ?string + { + [$bpRoot, $basePath] = self::split(self::canonicalize(reset($paths))); + + for (next($paths); null !== key($paths) && '' !== $basePath; next($paths)) { + [$root, $path] = self::split(self::canonicalize(current($paths))); + + // If we deal with different roots (e.g. C:/ vs. D:/), it's time + // to quit + if ($root !== $bpRoot) { + return null; + } + + // Make the base path shorter until it fits into path + while (true) { + if ('.' === $basePath) { + // No more base paths + $basePath = ''; + + // next path + continue 2; + } + + // Prevent false positives for common prefixes + // see isBasePath() + if (0 === strpos($path.'/', $basePath.'/')) { + // next path + continue 2; + } + + $basePath = \dirname($basePath); + } + } + + return $bpRoot.$basePath; + } + + /** + * Joins two or more path strings into a canonical path. + */ + public static function join(string ...$paths): string + { + $finalPath = null; + $wasScheme = false; + + foreach ($paths as $path) { + if ('' === $path) { + continue; + } + + if (null === $finalPath) { + // For first part we keep slashes, like '/top', 'C:\' or 'phar://' + $finalPath = $path; + $wasScheme = (false !== strpos($path, '://')); + continue; + } + + // Only add slash if previous part didn't end with '/' or '\' + if (!\in_array(substr($finalPath, -1), ['/', '\\'])) { + $finalPath .= '/'; + } + + // If first part included a scheme like 'phar://' we allow \current part to start with '/', otherwise trim + $finalPath .= $wasScheme ? $path : ltrim($path, '/'); + $wasScheme = false; + } + + if (null === $finalPath) { + return ''; + } + + return self::canonicalize($finalPath); + } + + /** + * Returns whether a path is a base path of another path. + * + * Dot segments ("." and "..") are removed/collapsed and all slashes turned + * into forward slashes. + * + * ```php + * Path::isBasePath('/symfony', '/symfony/css'); + * // => true + * + * Path::isBasePath('/symfony', '/symfony'); + * // => true + * + * Path::isBasePath('/symfony', '/symfony/..'); + * // => false + * + * Path::isBasePath('/symfony', '/puli'); + * // => false + * ``` + */ + public static function isBasePath(string $basePath, string $ofPath): bool + { + $basePath = self::canonicalize($basePath); + $ofPath = self::canonicalize($ofPath); + + // Append slashes to prevent false positives when two paths have + // a common prefix, for example /base/foo and /base/foobar. + // Don't append a slash for the root "/", because then that root + // won't be discovered as common prefix ("//" is not a prefix of + // "/foobar/"). + return 0 === strpos($ofPath.'/', rtrim($basePath, '/').'/'); + } + + /** + * @return string[] + */ + private static function findCanonicalParts(string $root, string $pathWithoutRoot): array + { + $parts = explode('/', $pathWithoutRoot); + + $canonicalParts = []; + + // Collapse "." and "..", if possible + foreach ($parts as $part) { + if ('.' === $part || '' === $part) { + continue; + } + + // Collapse ".." with the previous part, if one exists + // Don't collapse ".." if the previous part is also ".." + if ('..' === $part && \count($canonicalParts) > 0 && '..' !== $canonicalParts[\count($canonicalParts) - 1]) { + array_pop($canonicalParts); + + continue; + } + + // Only add ".." prefixes for relative paths + if ('..' !== $part || '' === $root) { + $canonicalParts[] = $part; + } + } + + return $canonicalParts; + } + + /** + * Splits a canonical path into its root directory and the remainder. + * + * If the path has no root directory, an empty root directory will be + * returned. + * + * If the root directory is a Windows style partition, the resulting root + * will always contain a trailing slash. + * + * list ($root, $path) = Path::split("C:/symfony") + * // => ["C:/", "symfony"] + * + * list ($root, $path) = Path::split("C:") + * // => ["C:/", ""] + * + * @return array{string, string} an array with the root directory and the remaining relative path + */ + private static function split(string $path): array + { + if ('' === $path) { + return ['', '']; + } + + // Remember scheme as part of the root, if any + if (false !== $schemeSeparatorPosition = strpos($path, '://')) { + $root = substr($path, 0, $schemeSeparatorPosition + 3); + $path = substr($path, $schemeSeparatorPosition + 3); + } else { + $root = ''; + } + + $length = \strlen($path); + + // Remove and remember root directory + if (0 === strpos($path, '/')) { + $root .= '/'; + $path = $length > 1 ? substr($path, 1) : ''; + } elseif ($length > 1 && ctype_alpha($path[0]) && ':' === $path[1]) { + if (2 === $length) { + // Windows special case: "C:" + $root .= $path.'/'; + $path = ''; + } elseif ('/' === $path[2]) { + // Windows normal case: "C:/".. + $root .= substr($path, 0, 3); + $path = $length > 3 ? substr($path, 3) : ''; + } + } + + return [$root, $path]; + } + + private static function toLower(string $string): string + { + if (false !== $encoding = mb_detect_encoding($string, null, true)) { + return mb_strtolower($string, $encoding); + } + + return strtolower($string); + } + + private function __construct() + { + } +} diff --git a/vendor/symfony/filesystem/README.md b/vendor/symfony/filesystem/README.md index cb03d43c..f2f6d45f 100644 --- a/vendor/symfony/filesystem/README.md +++ b/vendor/symfony/filesystem/README.md @@ -6,8 +6,8 @@ The Filesystem component provides basic utilities for the filesystem. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/filesystem.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Documentation](https://symfony.com/doc/current/components/filesystem.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/filesystem/Tests/ExceptionTest.php b/vendor/symfony/filesystem/Tests/ExceptionTest.php deleted file mode 100644 index 300acf10..00000000 --- a/vendor/symfony/filesystem/Tests/ExceptionTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Filesystem\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Filesystem\Exception\FileNotFoundException; -use Symfony\Component\Filesystem\Exception\IOException; - -/** - * Test class for Filesystem. - */ -class ExceptionTest extends TestCase -{ - public function testGetPath() - { - $e = new IOException('', 0, null, '/foo'); - $this->assertEquals('/foo', $e->getPath(), 'The pass should be returned.'); - } - - public function testGeneratedMessage() - { - $e = new FileNotFoundException(null, 0, null, '/foo'); - $this->assertEquals('/foo', $e->getPath()); - $this->assertEquals('File "/foo" could not be found.', $e->getMessage(), 'A message should be generated.'); - } - - public function testGeneratedMessageWithoutPath() - { - $e = new FileNotFoundException(); - $this->assertEquals('File could not be found.', $e->getMessage(), 'A message should be generated.'); - } - - public function testCustomMessage() - { - $e = new FileNotFoundException('bar', 0, null, '/foo'); - $this->assertEquals('bar', $e->getMessage(), 'A custom message should be possible still.'); - } -} diff --git a/vendor/symfony/filesystem/Tests/FilesystemTest.php b/vendor/symfony/filesystem/Tests/FilesystemTest.php deleted file mode 100644 index b157cc4e..00000000 --- a/vendor/symfony/filesystem/Tests/FilesystemTest.php +++ /dev/null @@ -1,1684 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Filesystem\Tests; - -use Symfony\Component\Filesystem\Exception\IOException; - -/** - * Test class for Filesystem. - */ -class FilesystemTest extends FilesystemTestCase -{ - public function testCopyCreatesNewFile() - { - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - - $this->assertFileExists($targetFilePath); - $this->assertStringEqualsFile($targetFilePath, 'SOURCE FILE'); - } - - public function testCopyFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - } - - public function testCopyUnreadableFileFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - // skip test on Windows; PHP can't easily set file as unreadable on Windows - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('This test cannot run on Windows.'); - } - - if (!getenv('USER') || 'root' === getenv('USER')) { - $this->markTestSkipped('This test will fail if run under superuser'); - } - - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - - // make sure target cannot be read - $this->filesystem->chmod($sourceFilePath, 0222); - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - } - - public function testCopyOverridesExistingFileIfModified() - { - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - file_put_contents($targetFilePath, 'TARGET FILE'); - touch($targetFilePath, time() - 1000); - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - - $this->assertFileExists($targetFilePath); - $this->assertStringEqualsFile($targetFilePath, 'SOURCE FILE'); - } - - public function testCopyDoesNotOverrideExistingFileByDefault() - { - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - file_put_contents($targetFilePath, 'TARGET FILE'); - - // make sure both files have the same modification time - $modificationTime = time() - 1000; - touch($sourceFilePath, $modificationTime); - touch($targetFilePath, $modificationTime); - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - - $this->assertFileExists($targetFilePath); - $this->assertStringEqualsFile($targetFilePath, 'TARGET FILE'); - } - - public function testCopyOverridesExistingFileIfForced() - { - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - file_put_contents($targetFilePath, 'TARGET FILE'); - - // make sure both files have the same modification time - $modificationTime = time() - 1000; - touch($sourceFilePath, $modificationTime); - touch($targetFilePath, $modificationTime); - - $this->filesystem->copy($sourceFilePath, $targetFilePath, true); - - $this->assertFileExists($targetFilePath); - $this->assertStringEqualsFile($targetFilePath, 'SOURCE FILE'); - } - - public function testCopyWithOverrideWithReadOnlyTargetFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - // skip test on Windows; PHP can't easily set file as unwritable on Windows - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('This test cannot run on Windows.'); - } - - if (!getenv('USER') || 'root' === getenv('USER')) { - $this->markTestSkipped('This test will fail if run under superuser'); - } - - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - file_put_contents($targetFilePath, 'TARGET FILE'); - - // make sure both files have the same modification time - $modificationTime = time() - 1000; - touch($sourceFilePath, $modificationTime); - touch($targetFilePath, $modificationTime); - - // make sure target is read-only - $this->filesystem->chmod($targetFilePath, 0444); - - $this->filesystem->copy($sourceFilePath, $targetFilePath, true); - } - - public function testCopyCreatesTargetDirectoryIfItDoesNotExist() - { - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFileDirectory = $this->workspace.\DIRECTORY_SEPARATOR.'directory'; - $targetFilePath = $targetFileDirectory.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - - $this->assertDirectoryExists($targetFileDirectory); - $this->assertFileExists($targetFilePath); - $this->assertStringEqualsFile($targetFilePath, 'SOURCE FILE'); - } - - /** - * @group network - */ - public function testCopyForOriginUrlsAndExistingLocalFileDefaultsToCopy() - { - if (!\in_array('https', stream_get_wrappers())) { - $this->markTestSkipped('"https" stream wrapper is not enabled.'); - } - $sourceFilePath = 'https://symfony.com/images/common/logo/logo_symfony_header.png'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($targetFilePath, 'TARGET FILE'); - - $this->filesystem->copy($sourceFilePath, $targetFilePath, false); - - $this->assertFileExists($targetFilePath); - $this->assertEquals(file_get_contents($sourceFilePath), file_get_contents($targetFilePath)); - } - - public function testMkdirCreatesDirectoriesRecursively() - { - $directory = $this->workspace - .\DIRECTORY_SEPARATOR.'directory' - .\DIRECTORY_SEPARATOR.'sub_directory'; - - $this->filesystem->mkdir($directory); - - $this->assertDirectoryExists($directory); - } - - public function testMkdirCreatesDirectoriesFromArray() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - $directories = [ - $basePath.'1', $basePath.'2', $basePath.'3', - ]; - - $this->filesystem->mkdir($directories); - - $this->assertDirectoryExists($basePath.'1'); - $this->assertDirectoryExists($basePath.'2'); - $this->assertDirectoryExists($basePath.'3'); - } - - public function testMkdirCreatesDirectoriesFromTraversableObject() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - $directories = new \ArrayObject([ - $basePath.'1', $basePath.'2', $basePath.'3', - ]); - - $this->filesystem->mkdir($directories); - - $this->assertDirectoryExists($basePath.'1'); - $this->assertDirectoryExists($basePath.'2'); - $this->assertDirectoryExists($basePath.'3'); - } - - public function testMkdirCreatesDirectoriesFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - $dir = $basePath.'2'; - - file_put_contents($dir, ''); - - $this->filesystem->mkdir($dir); - } - - public function testTouchCreatesEmptyFile() - { - $file = $this->workspace.\DIRECTORY_SEPARATOR.'1'; - - $this->filesystem->touch($file); - - $this->assertFileExists($file); - } - - public function testTouchFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $file = $this->workspace.\DIRECTORY_SEPARATOR.'1'.\DIRECTORY_SEPARATOR.'2'; - - $this->filesystem->touch($file); - } - - public function testTouchCreatesEmptyFilesFromArray() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - $files = [ - $basePath.'1', $basePath.'2', $basePath.'3', - ]; - - $this->filesystem->touch($files); - - $this->assertFileExists($basePath.'1'); - $this->assertFileExists($basePath.'2'); - $this->assertFileExists($basePath.'3'); - } - - public function testTouchCreatesEmptyFilesFromTraversableObject() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - $files = new \ArrayObject([ - $basePath.'1', $basePath.'2', $basePath.'3', - ]); - - $this->filesystem->touch($files); - - $this->assertFileExists($basePath.'1'); - $this->assertFileExists($basePath.'2'); - $this->assertFileExists($basePath.'3'); - } - - public function testRemoveCleansFilesAndDirectoriesIteratively() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR.'directory'.\DIRECTORY_SEPARATOR; - - mkdir($basePath); - mkdir($basePath.'dir'); - touch($basePath.'file'); - - $this->filesystem->remove($basePath); - - $this->assertFileDoesNotExist($basePath); - } - - public function testRemoveCleansArrayOfFilesAndDirectories() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - - mkdir($basePath.'dir'); - touch($basePath.'file'); - - $files = [ - $basePath.'dir', $basePath.'file', - ]; - - $this->filesystem->remove($files); - - $this->assertFileDoesNotExist($basePath.'dir'); - $this->assertFileDoesNotExist($basePath.'file'); - } - - public function testRemoveCleansTraversableObjectOfFilesAndDirectories() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - - mkdir($basePath.'dir'); - touch($basePath.'file'); - - $files = new \ArrayObject([ - $basePath.'dir', $basePath.'file', - ]); - - $this->filesystem->remove($files); - - $this->assertFileDoesNotExist($basePath.'dir'); - $this->assertFileDoesNotExist($basePath.'file'); - } - - public function testRemoveIgnoresNonExistingFiles() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - - mkdir($basePath.'dir'); - - $files = [ - $basePath.'dir', $basePath.'file', - ]; - - $this->filesystem->remove($files); - - $this->assertFileDoesNotExist($basePath.'dir'); - } - - public function testRemoveThrowsExceptionOnPermissionDenied() - { - $this->markAsSkippedIfChmodIsMissing(); - - $basePath = $this->workspace.\DIRECTORY_SEPARATOR.'dir_permissions'; - mkdir($basePath); - $file = $basePath.\DIRECTORY_SEPARATOR.'file'; - touch($file); - chmod($basePath, 0400); - - try { - $this->filesystem->remove($file); - $this->fail('Filesystem::remove() should throw an exception'); - } catch (IOException $e) { - $this->assertStringContainsString('Failed to remove file "'.$file.'"', $e->getMessage()); - $this->assertStringContainsString('Permission denied', $e->getMessage()); - } finally { - // Make sure we can clean up this file - chmod($basePath, 0777); - } - } - - public function testRemoveCleansInvalidLinks() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $basePath = $this->workspace.\DIRECTORY_SEPARATOR.'directory'.\DIRECTORY_SEPARATOR; - - mkdir($basePath); - mkdir($basePath.'dir'); - // create symlink to nonexistent file - @symlink($basePath.'file', $basePath.'file-link'); - - // create symlink to dir using trailing forward slash - $this->filesystem->symlink($basePath.'dir/', $basePath.'dir-link'); - $this->assertDirectoryExists($basePath.'dir-link'); - - // create symlink to nonexistent dir - rmdir($basePath.'dir'); - $this->assertFalse('\\' === \DIRECTORY_SEPARATOR ? @readlink($basePath.'dir-link') : is_dir($basePath.'dir-link')); - - $this->filesystem->remove($basePath); - - $this->assertFileDoesNotExist($basePath); - } - - public function testFilesExists() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR.'directory'.\DIRECTORY_SEPARATOR; - - mkdir($basePath); - touch($basePath.'file1'); - mkdir($basePath.'folder'); - - $this->assertTrue($this->filesystem->exists($basePath.'file1')); - $this->assertTrue($this->filesystem->exists($basePath.'folder')); - } - - public function testFilesExistsFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - if ('\\' !== \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Long file names are an issue on Windows'); - } - $basePath = $this->workspace.'\\directory\\'; - $maxPathLength = \PHP_MAXPATHLEN - 2; - - $oldPath = getcwd(); - mkdir($basePath); - chdir($basePath); - $file = str_repeat('T', $maxPathLength - \strlen($basePath) + 1); - $path = $basePath.$file; - exec('TYPE NUL >>'.$file); // equivalent of touch, we can not use the php touch() here because it suffers from the same limitation - $this->longPathNamesWindows[] = $path; // save this so we can clean up later - chdir($oldPath); - $this->filesystem->exists($path); - } - - public function testFilesExistsTraversableObjectOfFilesAndDirectories() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - - mkdir($basePath.'dir'); - touch($basePath.'file'); - - $files = new \ArrayObject([ - $basePath.'dir', $basePath.'file', - ]); - - $this->assertTrue($this->filesystem->exists($files)); - } - - public function testFilesNotExistsTraversableObjectOfFilesAndDirectories() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR; - - mkdir($basePath.'dir'); - touch($basePath.'file'); - touch($basePath.'file2'); - - $files = new \ArrayObject([ - $basePath.'dir', $basePath.'file', $basePath.'file2', - ]); - - unlink($basePath.'file'); - - $this->assertFalse($this->filesystem->exists($files)); - } - - public function testInvalidFileNotExists() - { - $basePath = $this->workspace.\DIRECTORY_SEPARATOR.'directory'.\DIRECTORY_SEPARATOR; - - $this->assertFalse($this->filesystem->exists($basePath.time())); - } - - public function testChmodChangesFileMode() - { - $this->markAsSkippedIfChmodIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - $file = $dir.\DIRECTORY_SEPARATOR.'file'; - touch($file); - - $this->filesystem->chmod($file, 0400); - $this->filesystem->chmod($dir, 0753); - - $this->assertFilePermissions(753, $dir); - $this->assertFilePermissions(400, $file); - } - - public function testChmodWithWrongModLeavesPreviousPermissionsUntouched() - { - $this->markAsSkippedIfChmodIsMissing(); - - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('chmod() changes permissions even when passing invalid modes on HHVM'); - } - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - touch($dir); - - $permissions = fileperms($dir); - - $this->filesystem->chmod($dir, 'Wrongmode'); - - $this->assertSame($permissions, fileperms($dir)); - } - - public function testChmodRecursive() - { - $this->markAsSkippedIfChmodIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - $file = $dir.\DIRECTORY_SEPARATOR.'file'; - touch($file); - - $this->filesystem->chmod($file, 0400, 0000, true); - $this->filesystem->chmod($dir, 0753, 0000, true); - - $this->assertFilePermissions(753, $dir); - $this->assertFilePermissions(753, $file); - } - - public function testChmodAppliesUmask() - { - $this->markAsSkippedIfChmodIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - touch($file); - - $this->filesystem->chmod($file, 0770, 0022); - $this->assertFilePermissions(750, $file); - } - - public function testChmodChangesModeOfArrayOfFiles() - { - $this->markAsSkippedIfChmodIsMissing(); - - $directory = $this->workspace.\DIRECTORY_SEPARATOR.'directory'; - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $files = [$directory, $file]; - - mkdir($directory); - touch($file); - - $this->filesystem->chmod($files, 0753); - - $this->assertFilePermissions(753, $file); - $this->assertFilePermissions(753, $directory); - } - - public function testChmodChangesModeOfTraversableFileObject() - { - $this->markAsSkippedIfChmodIsMissing(); - - $directory = $this->workspace.\DIRECTORY_SEPARATOR.'directory'; - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $files = new \ArrayObject([$directory, $file]); - - mkdir($directory); - touch($file); - - $this->filesystem->chmod($files, 0753); - - $this->assertFilePermissions(753, $file); - $this->assertFilePermissions(753, $directory); - } - - public function testChmodChangesZeroModeOnSubdirectoriesOnRecursive() - { - $this->markAsSkippedIfChmodIsMissing(); - - $directory = $this->workspace.\DIRECTORY_SEPARATOR.'directory'; - $subdirectory = $directory.\DIRECTORY_SEPARATOR.'subdirectory'; - - mkdir($directory); - mkdir($subdirectory); - chmod($subdirectory, 0000); - - $this->filesystem->chmod($directory, 0753, 0000, true); - - $this->assertFilePermissions(753, $subdirectory); - } - - public function testChown() - { - $this->markAsSkippedIfPosixIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - - $owner = $this->getFileOwner($dir); - $this->filesystem->chown($dir, $owner); - - $this->assertSame($owner, $this->getFileOwner($dir)); - } - - public function testChownRecursive() - { - $this->markAsSkippedIfPosixIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - $file = $dir.\DIRECTORY_SEPARATOR.'file'; - touch($file); - - $owner = $this->getFileOwner($dir); - $this->filesystem->chown($dir, $owner, true); - - $this->assertSame($owner, $this->getFileOwner($file)); - } - - public function testChownSymlink() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->symlink($file, $link); - - $owner = $this->getFileOwner($link); - $this->filesystem->chown($link, $owner); - - $this->assertSame($owner, $this->getFileOwner($link)); - } - - public function testChownLink() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->hardlink($file, $link); - - $owner = $this->getFileOwner($link); - $this->filesystem->chown($link, $owner); - - $this->assertSame($owner, $this->getFileOwner($link)); - } - - public function testChownSymlinkFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->symlink($file, $link); - - $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999)); - } - - public function testChownLinkFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->hardlink($file, $link); - - $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999)); - } - - public function testChownFail() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->markAsSkippedIfPosixIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - - $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999)); - } - - public function testChgrp() - { - $this->markAsSkippedIfPosixIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - - $group = $this->getFileGroup($dir); - $this->filesystem->chgrp($dir, $group); - - $this->assertSame($group, $this->getFileGroup($dir)); - } - - public function testChgrpRecursive() - { - $this->markAsSkippedIfPosixIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - $file = $dir.\DIRECTORY_SEPARATOR.'file'; - touch($file); - - $group = $this->getFileGroup($dir); - $this->filesystem->chgrp($dir, $group, true); - - $this->assertSame($group, $this->getFileGroup($file)); - } - - public function testChgrpSymlink() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->symlink($file, $link); - - $group = $this->getFileGroup($link); - $this->filesystem->chgrp($link, $group); - - $this->assertSame($group, $this->getFileGroup($link)); - } - - public function testChgrpLink() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->hardlink($file, $link); - - $group = $this->getFileGroup($link); - $this->filesystem->chgrp($link, $group); - - $this->assertSame($group, $this->getFileGroup($link)); - } - - public function testChgrpSymlinkFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->symlink($file, $link); - - $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999)); - } - - public function testChgrpLinkFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->hardlink($file, $link); - - $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999)); - } - - public function testChgrpFail() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->markAsSkippedIfPosixIsMissing(); - - $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; - mkdir($dir); - - $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999)); - } - - public function testRename() - { - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $newPath = $this->workspace.\DIRECTORY_SEPARATOR.'new_file'; - touch($file); - - $this->filesystem->rename($file, $newPath); - - $this->assertFileDoesNotExist($file); - $this->assertFileExists($newPath); - } - - public function testRenameThrowsExceptionIfTargetAlreadyExists() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $newPath = $this->workspace.\DIRECTORY_SEPARATOR.'new_file'; - - touch($file); - touch($newPath); - - $this->filesystem->rename($file, $newPath); - } - - public function testRenameOverwritesTheTargetIfItAlreadyExists() - { - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $newPath = $this->workspace.\DIRECTORY_SEPARATOR.'new_file'; - - touch($file); - touch($newPath); - - $this->filesystem->rename($file, $newPath, true); - - $this->assertFileDoesNotExist($file); - $this->assertFileExists($newPath); - } - - public function testRenameThrowsExceptionOnError() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $file = $this->workspace.\DIRECTORY_SEPARATOR.uniqid('fs_test_', true); - $newPath = $this->workspace.\DIRECTORY_SEPARATOR.'new_file'; - - $this->filesystem->rename($file, $newPath); - } - - public function testSymlink() - { - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Windows does not support creating "broken" symlinks'); - } - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - // $file does not exist right now: creating "broken" links is a wanted feature - $this->filesystem->symlink($file, $link); - - $this->assertTrue(is_link($link)); - - // Create the linked file AFTER creating the link - touch($file); - - $this->assertEquals($file, readlink($link)); - } - - /** - * @depends testSymlink - */ - public function testRemoveSymlink() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - $this->filesystem->remove($link); - - $this->assertFalse(is_link($link)); - $this->assertFalse(is_file($link)); - $this->assertDirectoryDoesNotExist($link); - } - - public function testSymlinkIsOverwrittenIfPointsToDifferentTarget() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - symlink($this->workspace, $link); - - $this->filesystem->symlink($file, $link); - - $this->assertTrue(is_link($link)); - $this->assertEquals($file, readlink($link)); - } - - public function testSymlinkIsNotOverwrittenIfAlreadyCreated() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - symlink($file, $link); - - $this->filesystem->symlink($file, $link); - - $this->assertTrue(is_link($link)); - $this->assertEquals($file, readlink($link)); - } - - public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link1 = $this->workspace.\DIRECTORY_SEPARATOR.'dir'.\DIRECTORY_SEPARATOR.'link'; - $link2 = $this->workspace.\DIRECTORY_SEPARATOR.'dir'.\DIRECTORY_SEPARATOR.'subdir'.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - $this->filesystem->symlink($file, $link1); - $this->filesystem->symlink($file, $link2); - - $this->assertTrue(is_link($link1)); - $this->assertEquals($file, readlink($link1)); - $this->assertTrue(is_link($link2)); - $this->assertEquals($file, readlink($link2)); - } - - public function testLink() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - $this->filesystem->hardlink($file, $link); - - $this->assertTrue(is_file($link)); - $this->assertEquals(fileinode($file), fileinode($link)); - } - - /** - * @depends testLink - */ - public function testRemoveLink() - { - $this->markAsSkippedIfLinkIsMissing(); - - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - $this->filesystem->remove($link); - - $this->assertTrue(!is_file($link)); - } - - public function testLinkIsOverwrittenIfPointsToDifferentTarget() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $file2 = $this->workspace.\DIRECTORY_SEPARATOR.'file2'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - touch($file2); - link($file2, $link); - - $this->filesystem->hardlink($file, $link); - - $this->assertTrue(is_file($link)); - $this->assertEquals(fileinode($file), fileinode($link)); - } - - public function testLinkIsNotOverwrittenIfAlreadyCreated() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - link($file, $link); - - $this->filesystem->hardlink($file, $link); - - $this->assertTrue(is_file($link)); - $this->assertEquals(fileinode($file), fileinode($link)); - } - - public function testLinkWithSeveralTargets() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link1 = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - $link2 = $this->workspace.\DIRECTORY_SEPARATOR.'link2'; - - touch($file); - - $this->filesystem->hardlink($file, [$link1, $link2]); - - $this->assertTrue(is_file($link1)); - $this->assertEquals(fileinode($file), fileinode($link1)); - $this->assertTrue(is_file($link2)); - $this->assertEquals(fileinode($file), fileinode($link2)); - } - - public function testLinkWithSameTarget() - { - $this->markAsSkippedIfLinkIsMissing(); - - $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; - $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - - touch($file); - - // practically same as testLinkIsNotOverwrittenIfAlreadyCreated - $this->filesystem->hardlink($file, [$link, $link]); - - $this->assertTrue(is_file($link)); - $this->assertEquals(fileinode($file), fileinode($link)); - } - - public function testReadRelativeLink() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Relative symbolic links are not supported on Windows'); - } - - $file = $this->workspace.'/file'; - $link1 = $this->workspace.'/dir/link'; - $link2 = $this->workspace.'/dir/link2'; - touch($file); - - $this->filesystem->symlink('../file', $link1); - $this->filesystem->symlink('link', $link2); - - $this->assertEquals($this->normalize('../file'), $this->filesystem->readlink($link1)); - $this->assertEquals('link', $this->filesystem->readlink($link2)); - $this->assertEquals($file, $this->filesystem->readlink($link1, true)); - $this->assertEquals($file, $this->filesystem->readlink($link2, true)); - $this->assertEquals($file, $this->filesystem->readlink($file, true)); - } - - public function testReadAbsoluteLink() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->normalize($this->workspace.'/file'); - $link1 = $this->normalize($this->workspace.'/dir/link'); - $link2 = $this->normalize($this->workspace.'/dir/link2'); - touch($file); - - $this->filesystem->symlink($file, $link1); - $this->filesystem->symlink($link1, $link2); - - $this->assertEquals($file, $this->filesystem->readlink($link1)); - $this->assertEquals($link1, $this->filesystem->readlink($link2)); - $this->assertEquals($file, $this->filesystem->readlink($link1, true)); - $this->assertEquals($file, $this->filesystem->readlink($link2, true)); - $this->assertEquals($file, $this->filesystem->readlink($file, true)); - } - - public function testReadBrokenLink() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Windows does not support creating "broken" symlinks'); - } - - $file = $this->workspace.'/file'; - $link = $this->workspace.'/link'; - - $this->filesystem->symlink($file, $link); - - $this->assertEquals($file, $this->filesystem->readlink($link)); - $this->assertNull($this->filesystem->readlink($link, true)); - - touch($file); - $this->assertEquals($file, $this->filesystem->readlink($link, true)); - } - - public function testReadLinkDefaultPathDoesNotExist() - { - $this->assertNull($this->filesystem->readlink($this->normalize($this->workspace.'/invalid'))); - } - - public function testReadLinkDefaultPathNotLink() - { - $file = $this->normalize($this->workspace.'/file'); - touch($file); - - $this->assertNull($this->filesystem->readlink($file)); - } - - public function testReadLinkCanonicalizePath() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $file = $this->normalize($this->workspace.'/file'); - mkdir($this->normalize($this->workspace.'/dir')); - touch($file); - - $this->assertEquals($file, $this->filesystem->readlink($this->normalize($this->workspace.'/dir/../file'), true)); - } - - public function testReadLinkCanonicalizedPathDoesNotExist() - { - $this->assertNull($this->filesystem->readlink($this->normalize($this->workspace.'invalid'), true)); - } - - /** - * @dataProvider providePathsForMakePathRelative - */ - public function testMakePathRelative($endPath, $startPath, $expectedPath) - { - $path = $this->filesystem->makePathRelative($endPath, $startPath); - - $this->assertEquals($expectedPath, $path); - } - - public function providePathsForMakePathRelative() - { - $paths = [ - ['/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'], - ['/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'], - ['/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'], - ['/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'], - ['/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'], - ['/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'], - ['/aa/bb', '/aa/bb', './'], - ['/aa/bb', '/aa/bb/', './'], - ['/aa/bb/', '/aa/bb', './'], - ['/aa/bb/', '/aa/bb/', './'], - ['/aa/bb/cc', '/aa/bb/cc/dd', '../'], - ['/aa/bb/cc', '/aa/bb/cc/dd/', '../'], - ['/aa/bb/cc/', '/aa/bb/cc/dd', '../'], - ['/aa/bb/cc/', '/aa/bb/cc/dd/', '../'], - ['/aa/bb/cc', '/aa', 'bb/cc/'], - ['/aa/bb/cc', '/aa/', 'bb/cc/'], - ['/aa/bb/cc/', '/aa', 'bb/cc/'], - ['/aa/bb/cc/', '/aa/', 'bb/cc/'], - ['/a/aab/bb', '/a/aa', '../aab/bb/'], - ['/a/aab/bb', '/a/aa/', '../aab/bb/'], - ['/a/aab/bb/', '/a/aa', '../aab/bb/'], - ['/a/aab/bb/', '/a/aa/', '../aab/bb/'], - ['/a/aab/bb/', '/', 'a/aab/bb/'], - ['/a/aab/bb/', '/b/aab', '../../a/aab/bb/'], - ['/aab/bb', '/aa', '../aab/bb/'], - ['/aab', '/aa', '../aab/'], - ['/aa/bb/cc', '/aa/dd/..', 'bb/cc/'], - ['/aa/../bb/cc', '/aa/dd/..', '../bb/cc/'], - ['/aa/bb/../../cc', '/aa/../dd/..', 'cc/'], - ['/../aa/bb/cc', '/aa/dd/..', 'bb/cc/'], - ['/../../aa/../bb/cc', '/aa/dd/..', '../bb/cc/'], - ['C:/aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'], - ['C:/aa/bb/cc', 'c:/aa/dd/..', 'bb/cc/'], - ['c:/aa/../bb/cc', 'c:/aa/dd/..', '../bb/cc/'], - ['C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'], - ['C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'], - ['C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'], - ['D:/', 'C:/aa/../bb/cc', 'D:/'], - ['D:/aa/bb', 'C:/aa', 'D:/aa/bb/'], - ['D:/../../aa/../bb/cc', 'C:/aa/dd/..', 'D:/bb/cc/'], - ]; - - if ('\\' === \DIRECTORY_SEPARATOR) { - $paths[] = ['c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/']; - } - - return $paths; - } - - /** - * @group legacy - * @dataProvider provideLegacyPathsForMakePathRelativeWithRelativePaths - * @expectedDeprecation Support for passing relative paths to Symfony\Component\Filesystem\Filesystem::makePathRelative() is deprecated since Symfony 3.4 and will be removed in 4.0. - */ - public function testMakePathRelativeWithRelativePaths($endPath, $startPath, $expectedPath) - { - $path = $this->filesystem->makePathRelative($endPath, $startPath); - - $this->assertEquals($expectedPath, $path); - } - - public function provideLegacyPathsForMakePathRelativeWithRelativePaths() - { - return [ - ['usr/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'], - ['aa/bb', 'aa/cc', '../bb/'], - ['aa/cc', 'bb/cc', '../../aa/cc/'], - ['aa/bb', 'aa/./cc', '../bb/'], - ['aa/./bb', 'aa/cc', '../bb/'], - ['aa/./bb', 'aa/./cc', '../bb/'], - ['../../', '../../', './'], - ['../aa/bb/', 'aa/bb/', '../../../aa/bb/'], - ['../../../', '../../', '../'], - ['', '', './'], - ['', 'aa/', '../'], - ['aa/', '', 'aa/'], - ]; - } - - public function testMirrorCopiesFilesAndDirectoriesRecursively() - { - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - $directory = $sourcePath.'directory'.\DIRECTORY_SEPARATOR; - $file1 = $directory.'file1'; - $file2 = $sourcePath.'file2'; - - mkdir($sourcePath); - mkdir($directory); - file_put_contents($file1, 'FILE1'); - file_put_contents($file2, 'FILE2'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $this->filesystem->mirror($sourcePath, $targetPath); - - $this->assertDirectoryExists($targetPath); - $this->assertDirectoryExists($targetPath.'directory'); - $this->assertFileEquals($file1, $targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1'); - $this->assertFileEquals($file2, $targetPath.'file2'); - - $this->filesystem->remove($file1); - - $this->filesystem->mirror($sourcePath, $targetPath, null, ['delete' => false]); - $this->assertTrue($this->filesystem->exists($targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1')); - - $this->filesystem->mirror($sourcePath, $targetPath, null, ['delete' => true]); - $this->assertFalse($this->filesystem->exists($targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1')); - - file_put_contents($file1, 'FILE1'); - - $this->filesystem->mirror($sourcePath, $targetPath, null, ['delete' => true]); - $this->assertTrue($this->filesystem->exists($targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1')); - - $this->filesystem->remove($directory); - $this->filesystem->mirror($sourcePath, $targetPath, null, ['delete' => true]); - $this->assertFalse($this->filesystem->exists($targetPath.'directory')); - $this->assertFalse($this->filesystem->exists($targetPath.'directory'.\DIRECTORY_SEPARATOR.'file1')); - } - - public function testMirrorCreatesEmptyDirectory() - { - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - - mkdir($sourcePath); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $this->filesystem->mirror($sourcePath, $targetPath); - - $this->assertDirectoryExists($targetPath); - - $this->filesystem->remove($sourcePath); - } - - public function testMirrorCopiesLinks() - { - $this->markAsSkippedIfSymlinkIsMissing(); - - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - - mkdir($sourcePath); - file_put_contents($sourcePath.'file1', 'FILE1'); - symlink($sourcePath.'file1', $sourcePath.'link1'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $this->filesystem->mirror($sourcePath, $targetPath); - - $this->assertDirectoryExists($targetPath); - $this->assertFileEquals($sourcePath.'file1', $targetPath.'link1'); - $this->assertTrue(is_link($targetPath.\DIRECTORY_SEPARATOR.'link1')); - } - - public function testMirrorCopiesLinkedDirectoryContents() - { - $this->markAsSkippedIfSymlinkIsMissing(true); - - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - - mkdir($sourcePath.'nested/', 0777, true); - file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1'); - // Note: We symlink directory, not file - symlink($sourcePath.'nested', $sourcePath.'link1'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $this->filesystem->mirror($sourcePath, $targetPath); - - $this->assertDirectoryExists($targetPath); - $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.'link1/file1.txt'); - $this->assertTrue(is_link($targetPath.\DIRECTORY_SEPARATOR.'link1')); - } - - public function testMirrorCopiesRelativeLinkedContents() - { - $this->markAsSkippedIfSymlinkIsMissing(true); - - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - $oldPath = getcwd(); - - mkdir($sourcePath.'nested/', 0777, true); - file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1'); - // Note: Create relative symlink - chdir($sourcePath); - symlink('nested', 'link1'); - - chdir($oldPath); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $this->filesystem->mirror($sourcePath, $targetPath); - - $this->assertDirectoryExists($targetPath); - $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.'link1/file1.txt'); - $this->assertTrue(is_link($targetPath.\DIRECTORY_SEPARATOR.'link1')); - $this->assertEquals('\\' === \DIRECTORY_SEPARATOR ? realpath($sourcePath.'\nested') : 'nested', readlink($targetPath.\DIRECTORY_SEPARATOR.'link1')); - } - - public function testMirrorContentsWithSameNameAsSourceOrTargetWithoutDeleteOption() - { - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - - mkdir($sourcePath); - touch($sourcePath.'source'); - touch($sourcePath.'target'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - $oldPath = getcwd(); - chdir($this->workspace); - - $this->filesystem->mirror('source', $targetPath); - - chdir($oldPath); - - $this->assertDirectoryExists($targetPath); - $this->assertFileExists($targetPath.'source'); - $this->assertFileExists($targetPath.'target'); - } - - public function testMirrorContentsWithSameNameAsSourceOrTargetWithDeleteOption() - { - $sourcePath = $this->workspace.\DIRECTORY_SEPARATOR.'source'.\DIRECTORY_SEPARATOR; - - mkdir($sourcePath); - touch($sourcePath.'source'); - - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'target'.\DIRECTORY_SEPARATOR; - - mkdir($targetPath); - touch($targetPath.'source'); - touch($targetPath.'target'); - - $oldPath = getcwd(); - chdir($this->workspace); - - $this->filesystem->mirror('source', 'target', null, ['delete' => true]); - - chdir($oldPath); - - $this->assertDirectoryExists($targetPath); - $this->assertFileExists($targetPath.'source'); - $this->assertFileDoesNotExist($targetPath.'target'); - } - - public function testMirrorFromSubdirectoryInToParentDirectory() - { - $targetPath = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR; - $sourcePath = $targetPath.'bar'.\DIRECTORY_SEPARATOR; - $file1 = $sourcePath.'file1'; - $file2 = $sourcePath.'file2'; - - $this->filesystem->mkdir($sourcePath); - file_put_contents($file1, 'FILE1'); - file_put_contents($file2, 'FILE2'); - - $this->filesystem->mirror($sourcePath, $targetPath); - - $this->assertFileEquals($file1, $targetPath.'file1'); - } - - /** - * @dataProvider providePathsForIsAbsolutePath - */ - public function testIsAbsolutePath($path, $expectedResult) - { - $result = $this->filesystem->isAbsolutePath($path); - - $this->assertEquals($expectedResult, $result); - } - - public function providePathsForIsAbsolutePath() - { - return [ - ['/var/lib', true], - ['c:\\\\var\\lib', true], - ['\\var\\lib', true], - ['var/lib', false], - ['../var/lib', false], - ['', false], - [null, false], - ]; - } - - public function testTempnam() - { - $dirname = $this->workspace; - - $filename = $this->filesystem->tempnam($dirname, 'foo'); - - $this->assertFileExists($filename); - } - - public function testTempnamWithFileScheme() - { - $scheme = 'file://'; - $dirname = $scheme.$this->workspace; - - $filename = $this->filesystem->tempnam($dirname, 'foo'); - - $this->assertStringStartsWith($scheme, $filename); - $this->assertFileExists($filename); - } - - public function testTempnamWithMockScheme() - { - stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream'); - - $scheme = 'mock://'; - $dirname = $scheme.$this->workspace; - - $filename = $this->filesystem->tempnam($dirname, 'foo'); - - $this->assertStringStartsWith($scheme, $filename); - $this->assertFileExists($filename); - } - - public function testTempnamWithZlibSchemeFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $scheme = 'compress.zlib://'; - $dirname = $scheme.$this->workspace; - - // The compress.zlib:// stream does not support mode x: creates the file, errors "failed to open stream: operation failed" and returns false - $this->filesystem->tempnam($dirname, 'bar'); - } - - public function testTempnamWithPHPTempSchemeFails() - { - $scheme = 'php://temp'; - $dirname = $scheme; - - $filename = $this->filesystem->tempnam($dirname, 'bar'); - - $this->assertStringStartsWith($scheme, $filename); - - // The php://temp stream deletes the file after close - $this->assertFileDoesNotExist($filename); - } - - public function testTempnamWithPharSchemeFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - // Skip test if Phar disabled phar.readonly must be 0 in php.ini - if (!\Phar::canWrite()) { - $this->markTestSkipped('This test cannot run when phar.readonly is 1.'); - } - - $scheme = 'phar://'; - $dirname = $scheme.$this->workspace; - $pharname = 'foo.phar'; - - new \Phar($this->workspace.'/'.$pharname, 0, $pharname); - // The phar:// stream does not support mode x: fails to create file, errors "failed to open stream: phar error: "$filename" is not a file in phar "$pharname"" and returns false - $this->filesystem->tempnam($dirname, $pharname.'/bar'); - } - - public function testTempnamWithHTTPSchemeFails() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $scheme = 'http://'; - $dirname = $scheme.$this->workspace; - - // The http:// scheme is read-only - $this->filesystem->tempnam($dirname, 'bar'); - } - - public function testTempnamOnUnwritableFallsBackToSysTmp() - { - $scheme = 'file://'; - $dirname = $scheme.$this->workspace.\DIRECTORY_SEPARATOR.'does_not_exist'; - - $filename = $this->filesystem->tempnam($dirname, 'bar'); - $realTempDir = realpath(sys_get_temp_dir()); - $this->assertStringStartsWith(rtrim($scheme.$realTempDir, \DIRECTORY_SEPARATOR), $filename); - $this->assertFileExists($filename); - - // Tear down - @unlink($filename); - } - - public function testDumpFile() - { - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - - // skip mode check on Windows - if ('\\' !== \DIRECTORY_SEPARATOR) { - $oldMask = umask(0002); - } - - $this->filesystem->dumpFile($filename, 'bar'); - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'bar'); - - // skip mode check on Windows - if ('\\' !== \DIRECTORY_SEPARATOR) { - $this->assertFilePermissions(664, $filename); - umask($oldMask); - } - } - - public function testDumpFileWithArray() - { - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - - $this->filesystem->dumpFile($filename, ['bar']); - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'bar'); - } - - public function testDumpFileWithResource() - { - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - - $resource = fopen('php://memory', 'rw'); - fwrite($resource, 'bar'); - fseek($resource, 0); - - $this->filesystem->dumpFile($filename, $resource); - - fclose($resource); - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'bar'); - } - - public function testDumpFileOverwritesAnExistingFile() - { - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo.txt'; - file_put_contents($filename, 'FOO BAR'); - - $this->filesystem->dumpFile($filename, 'bar'); - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'bar'); - } - - public function testDumpFileWithFileScheme() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM does not handle the file:// scheme correctly'); - } - - $scheme = 'file://'; - $filename = $scheme.$this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - - $this->filesystem->dumpFile($filename, 'bar'); - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'bar'); - } - - public function testDumpFileWithZlibScheme() - { - $scheme = 'compress.zlib://'; - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - - $this->filesystem->dumpFile($filename, 'bar'); - - // Zlib stat uses file:// wrapper so remove scheme - $this->assertFileExists(str_replace($scheme, '', $filename)); - $this->assertStringEqualsFile($filename, 'bar'); - } - - public function testAppendToFile() - { - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'bar.txt'; - - // skip mode check on Windows - if ('\\' !== \DIRECTORY_SEPARATOR) { - $oldMask = umask(0002); - } - - $this->filesystem->dumpFile($filename, 'foo'); - - $this->filesystem->appendToFile($filename, 'bar'); - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'foobar'); - - // skip mode check on Windows - if ('\\' !== \DIRECTORY_SEPARATOR) { - $this->assertFilePermissions(664, $filename); - umask($oldMask); - } - } - - public function testAppendToFileWithScheme() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM does not handle the file:// scheme correctly'); - } - - $scheme = 'file://'; - $filename = $scheme.$this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - $this->filesystem->dumpFile($filename, 'foo'); - - $this->filesystem->appendToFile($filename, 'bar'); - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'foobar'); - } - - public function testAppendToFileWithZlibScheme() - { - $scheme = 'compress.zlib://'; - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'baz.txt'; - $this->filesystem->dumpFile($filename, 'foo'); - - // Zlib stat uses file:// wrapper so remove it - $this->assertStringEqualsFile(str_replace($scheme, '', $filename), 'foo'); - - $this->filesystem->appendToFile($filename, 'bar'); - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'foobar'); - } - - public function testAppendToFileCreateTheFileIfNotExists() - { - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo'.\DIRECTORY_SEPARATOR.'bar.txt'; - - // skip mode check on Windows - if ('\\' !== \DIRECTORY_SEPARATOR) { - $oldMask = umask(0002); - } - - $this->filesystem->appendToFile($filename, 'bar'); - - // skip mode check on Windows - if ('\\' !== \DIRECTORY_SEPARATOR) { - $this->assertFilePermissions(664, $filename); - umask($oldMask); - } - - $this->assertFileExists($filename); - $this->assertStringEqualsFile($filename, 'bar'); - } - - public function testDumpKeepsExistingPermissionsWhenOverwritingAnExistingFile() - { - $this->markAsSkippedIfChmodIsMissing(); - - $filename = $this->workspace.\DIRECTORY_SEPARATOR.'foo.txt'; - file_put_contents($filename, 'FOO BAR'); - chmod($filename, 0745); - - $this->filesystem->dumpFile($filename, 'bar', null); - - $this->assertFilePermissions(745, $filename); - } - - public function testCopyShouldKeepExecutionPermission() - { - $this->markAsSkippedIfChmodIsMissing(); - - $sourceFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_source_file'; - $targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file'; - - file_put_contents($sourceFilePath, 'SOURCE FILE'); - chmod($sourceFilePath, 0745); - - $this->filesystem->copy($sourceFilePath, $targetFilePath); - - $this->assertFilePermissions(767, $targetFilePath); - } - - /** - * Normalize the given path (transform each blackslash into a real directory separator). - * - * @param string $path - * - * @return string - */ - private function normalize($path) - { - return str_replace('/', \DIRECTORY_SEPARATOR, $path); - } -} diff --git a/vendor/symfony/filesystem/Tests/FilesystemTestCase.php b/vendor/symfony/filesystem/Tests/FilesystemTestCase.php deleted file mode 100644 index b7038550..00000000 --- a/vendor/symfony/filesystem/Tests/FilesystemTestCase.php +++ /dev/null @@ -1,165 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Filesystem\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Filesystem\Filesystem; - -class FilesystemTestCase extends TestCase -{ - private $umask; - - protected $longPathNamesWindows = []; - - /** - * @var Filesystem - */ - protected $filesystem = null; - - /** - * @var string - */ - protected $workspace = null; - - /** - * @var bool|null Flag for hard links on Windows - */ - private static $linkOnWindows = null; - - /** - * @var bool|null Flag for symbolic links on Windows - */ - private static $symlinkOnWindows = null; - - public static function setUpBeforeClass() - { - if ('\\' === \DIRECTORY_SEPARATOR) { - self::$linkOnWindows = true; - $originFile = tempnam(sys_get_temp_dir(), 'li'); - $targetFile = tempnam(sys_get_temp_dir(), 'li'); - if (true !== @link($originFile, $targetFile)) { - $report = error_get_last(); - if (\is_array($report) && false !== strpos($report['message'], 'error code(1314)')) { - self::$linkOnWindows = false; - } - } else { - @unlink($targetFile); - } - - self::$symlinkOnWindows = true; - $originDir = tempnam(sys_get_temp_dir(), 'sl'); - $targetDir = tempnam(sys_get_temp_dir(), 'sl'); - if (true !== @symlink($originDir, $targetDir)) { - $report = error_get_last(); - if (\is_array($report) && false !== strpos($report['message'], 'error code(1314)')) { - self::$symlinkOnWindows = false; - } - } else { - @unlink($targetDir); - } - } - } - - protected function setUp() - { - $this->umask = umask(0); - $this->filesystem = new Filesystem(); - $this->workspace = sys_get_temp_dir().'/'.microtime(true).'.'.mt_rand(); - mkdir($this->workspace, 0777, true); - $this->workspace = realpath($this->workspace); - } - - protected function tearDown() - { - if (!empty($this->longPathNamesWindows)) { - foreach ($this->longPathNamesWindows as $path) { - exec('DEL '.$path); - } - $this->longPathNamesWindows = []; - } - - $this->filesystem->remove($this->workspace); - umask($this->umask); - } - - /** - * @param int $expectedFilePerms Expected file permissions as three digits (i.e. 755) - * @param string $filePath - */ - protected function assertFilePermissions($expectedFilePerms, $filePath) - { - $actualFilePerms = (int) substr(sprintf('%o', fileperms($filePath)), -3); - $this->assertEquals( - $expectedFilePerms, - $actualFilePerms, - sprintf('File permissions for %s must be %s. Actual %s', $filePath, $expectedFilePerms, $actualFilePerms) - ); - } - - protected function getFileOwner($filepath) - { - $this->markAsSkippedIfPosixIsMissing(); - - $infos = stat($filepath); - - return ($datas = posix_getpwuid($infos['uid'])) ? $datas['name'] : null; - } - - protected function getFileGroup($filepath) - { - $this->markAsSkippedIfPosixIsMissing(); - - $infos = stat($filepath); - if ($datas = posix_getgrgid($infos['gid'])) { - return $datas['name']; - } - - $this->markTestSkipped('Unable to retrieve file group name'); - } - - protected function markAsSkippedIfLinkIsMissing() - { - if (!\function_exists('link')) { - $this->markTestSkipped('link is not supported'); - } - - if ('\\' === \DIRECTORY_SEPARATOR && false === self::$linkOnWindows) { - $this->markTestSkipped('link requires "Create hard links" privilege on windows'); - } - } - - protected function markAsSkippedIfSymlinkIsMissing($relative = false) - { - if ('\\' === \DIRECTORY_SEPARATOR && false === self::$symlinkOnWindows) { - $this->markTestSkipped('symlink requires "Create symbolic links" privilege on Windows'); - } - - // https://bugs.php.net/69473 - if ($relative && '\\' === \DIRECTORY_SEPARATOR && 1 === \PHP_ZTS) { - $this->markTestSkipped('symlink does not support relative paths on thread safe Windows PHP versions'); - } - } - - protected function markAsSkippedIfChmodIsMissing() - { - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('chmod is not supported on Windows'); - } - } - - protected function markAsSkippedIfPosixIsMissing() - { - if (!\function_exists('posix_isatty')) { - $this->markTestSkipped('Function posix_isatty is required.'); - } - } -} diff --git a/vendor/symfony/filesystem/Tests/Fixtures/MockStream/MockStream.php b/vendor/symfony/filesystem/Tests/Fixtures/MockStream/MockStream.php deleted file mode 100644 index 3d80a905..00000000 --- a/vendor/symfony/filesystem/Tests/Fixtures/MockStream/MockStream.php +++ /dev/null @@ -1,46 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Filesystem\Tests\Fixtures\MockStream; - -/** - * Mock stream class to be used with stream_wrapper_register. - * stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream'). - */ -class MockStream -{ - /** - * Opens file or URL. - * - * @param string $path Specifies the URL that was passed to the original function - * @param string $mode The mode used to open the file, as detailed for fopen() - * @param int $options Holds additional flags set by the streams API - * @param string $opened_path If the path is opened successfully, and STREAM_USE_PATH is set in options, - * opened_path should be set to the full path of the file/resource that was actually opened - * - * @return bool - */ - public function stream_open($path, $mode, $options, &$opened_path) - { - return true; - } - - /** - * @param string $path The file path or URL to stat - * @param array $flags Holds additional flags set by the streams API - * - * @return array File stats - */ - public function url_stat($path, $flags) - { - return []; - } -} diff --git a/vendor/symfony/filesystem/Tests/LockHandlerTest.php b/vendor/symfony/filesystem/Tests/LockHandlerTest.php deleted file mode 100644 index b63e0c22..00000000 --- a/vendor/symfony/filesystem/Tests/LockHandlerTest.php +++ /dev/null @@ -1,144 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Filesystem\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Filesystem\Exception\IOException; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\Filesystem\LockHandler; - -/** - * @group legacy - */ -class LockHandlerTest extends TestCase -{ - public function testConstructWhenRepositoryDoesNotExist() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->expectExceptionMessage('Failed to create "/a/b/c/d/e": mkdir(): Permission denied'); - if (!getenv('USER') || 'root' === getenv('USER')) { - $this->markTestSkipped('This test will fail if run under superuser'); - } - new LockHandler('lock', '/a/b/c/d/e'); - } - - public function testConstructWhenRepositoryIsNotWriteable() - { - $this->expectException('Symfony\Component\Filesystem\Exception\IOException'); - $this->expectExceptionMessage('The directory "/" is not writable.'); - if (!getenv('USER') || 'root' === getenv('USER')) { - $this->markTestSkipped('This test will fail if run under superuser'); - } - new LockHandler('lock', '/'); - } - - public function testErrorHandlingInLockIfLockPathBecomesUnwritable() - { - // skip test on Windows; PHP can't easily set file as unreadable on Windows - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('This test cannot run on Windows.'); - } - - if (!getenv('USER') || 'root' === getenv('USER')) { - $this->markTestSkipped('This test will fail if run under superuser'); - } - - $lockPath = sys_get_temp_dir().'/'.uniqid('', true); - $e = null; - $wrongMessage = null; - - try { - mkdir($lockPath); - - $lockHandler = new LockHandler('lock', $lockPath); - - chmod($lockPath, 0444); - - $lockHandler->lock(); - } catch (IOException $e) { - if (false === strpos($e->getMessage(), 'Permission denied')) { - $wrongMessage = $e->getMessage(); - } else { - $this->addToAssertionCount(1); - } - } catch (\Exception $e) { - } catch (\Throwable $e) { - } - - if (is_dir($lockPath)) { - $fs = new Filesystem(); - $fs->remove($lockPath); - } - - $this->assertInstanceOf('Symfony\Component\Filesystem\Exception\IOException', $e, sprintf('Expected IOException to be thrown, got %s instead.', \get_class($e))); - $this->assertNull($wrongMessage, sprintf('Expected exception message to contain "Permission denied", got "%s" instead.', $wrongMessage)); - } - - public function testConstructSanitizeName() - { - $lock = new LockHandler(''); - - $file = sprintf('%s/sf.-php-echo-hello-word-.4b3d9d0d27ddef3a78a64685dda3a963e478659a9e5240feaf7b4173a8f28d5f.lock', sys_get_temp_dir()); - // ensure the file does not exist before the lock - @unlink($file); - - $lock->lock(); - - $this->assertFileExists($file); - - $lock->release(); - } - - public function testLockRelease() - { - $name = 'symfony-test-filesystem.lock'; - - $l1 = new LockHandler($name); - $l2 = new LockHandler($name); - - $this->assertTrue($l1->lock()); - $this->assertFalse($l2->lock()); - - $l1->release(); - - $this->assertTrue($l2->lock()); - $l2->release(); - } - - public function testLockTwice() - { - $name = 'symfony-test-filesystem.lock'; - - $lockHandler = new LockHandler($name); - - $this->assertTrue($lockHandler->lock()); - $this->assertTrue($lockHandler->lock()); - - $lockHandler->release(); - } - - public function testLockIsReleased() - { - $name = 'symfony-test-filesystem.lock'; - - $l1 = new LockHandler($name); - $l2 = new LockHandler($name); - - $this->assertTrue($l1->lock()); - $this->assertFalse($l2->lock()); - - $l1 = null; - - $this->assertTrue($l2->lock()); - $l2->release(); - } -} diff --git a/vendor/symfony/filesystem/composer.json b/vendor/symfony/filesystem/composer.json index ee48b0b2..e756104c 100644 --- a/vendor/symfony/filesystem/composer.json +++ b/vendor/symfony/filesystem/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/filesystem", "type": "library", - "description": "Symfony Filesystem Component", + "description": "Provides basic utilities for the filesystem", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,8 +16,10 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-ctype": "~1.8" + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" }, "autoload": { "psr-4": { "Symfony\\Component\\Filesystem\\": "" }, diff --git a/vendor/symfony/filesystem/phpunit.xml.dist b/vendor/symfony/filesystem/phpunit.xml.dist deleted file mode 100644 index 5515fff1..00000000 --- a/vendor/symfony/filesystem/phpunit.xml.dist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/event-dispatcher/.gitignore b/vendor/symfony/http-client-contracts/.gitignore similarity index 100% rename from vendor/symfony/event-dispatcher/.gitignore rename to vendor/symfony/http-client-contracts/.gitignore diff --git a/vendor/symfony/http-client-contracts/CHANGELOG.md b/vendor/symfony/http-client-contracts/CHANGELOG.md new file mode 100644 index 00000000..7932e261 --- /dev/null +++ b/vendor/symfony/http-client-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/vendor/symfony/http-client-contracts/ChunkInterface.php b/vendor/symfony/http-client-contracts/ChunkInterface.php new file mode 100644 index 00000000..0800cb36 --- /dev/null +++ b/vendor/symfony/http-client-contracts/ChunkInterface.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * The interface of chunks returned by ResponseStreamInterface::current(). + * + * When the chunk is first, last or timeout, the content MUST be empty. + * When an unchecked timeout or a network error occurs, a TransportExceptionInterface + * MUST be thrown by the destructor unless one was already thrown by another method. + * + * @author Nicolas Grekas + */ +interface ChunkInterface +{ + /** + * Tells when the idle timeout has been reached. + * + * @throws TransportExceptionInterface on a network error + */ + public function isTimeout(): bool; + + /** + * Tells when headers just arrived. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function isFirst(): bool; + + /** + * Tells when the body just completed. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function isLast(): bool; + + /** + * Returns a [status code, headers] tuple when a 1xx status code was just received. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function getInformationalStatus(): ?array; + + /** + * Returns the content of the response chunk. + * + * @throws TransportExceptionInterface on a network error or when the idle timeout is reached + */ + public function getContent(): string; + + /** + * Returns the offset of the chunk in the response body. + */ + public function getOffset(): int; + + /** + * In case of error, returns the message that describes it. + */ + public function getError(): ?string; +} diff --git a/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php new file mode 100644 index 00000000..22d2b456 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/ClientExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 4xx response is returned. + * + * @author Nicolas Grekas + */ +interface ClientExceptionInterface extends HttpExceptionInterface +{ +} diff --git a/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php new file mode 100644 index 00000000..971a7a29 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/DecodingExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a content-type cannot be decoded to the expected representation. + * + * @author Nicolas Grekas + */ +interface DecodingExceptionInterface extends ExceptionInterface +{ +} diff --git a/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php new file mode 100644 index 00000000..e553b47a --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/ExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * The base interface for all exceptions in the contract. + * + * @author Nicolas Grekas + */ +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php new file mode 100644 index 00000000..17865ed3 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/HttpExceptionInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +use Symfony\Contracts\HttpClient\ResponseInterface; + +/** + * Base interface for HTTP-related exceptions. + * + * @author Anton Chernikov + */ +interface HttpExceptionInterface extends ExceptionInterface +{ + public function getResponse(): ResponseInterface; +} diff --git a/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php new file mode 100644 index 00000000..edd9b8a9 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/RedirectionExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 3xx response is returned and the "max_redirects" option has been reached. + * + * @author Nicolas Grekas + */ +interface RedirectionExceptionInterface extends HttpExceptionInterface +{ +} diff --git a/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php new file mode 100644 index 00000000..9bfe1354 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/ServerExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When a 5xx response is returned. + * + * @author Nicolas Grekas + */ +interface ServerExceptionInterface extends HttpExceptionInterface +{ +} diff --git a/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php new file mode 100644 index 00000000..08acf9fb --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/TimeoutExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When an idle timeout occurs. + * + * @author Nicolas Grekas + */ +interface TimeoutExceptionInterface extends TransportExceptionInterface +{ +} diff --git a/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php b/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php new file mode 100644 index 00000000..0c8d131a --- /dev/null +++ b/vendor/symfony/http-client-contracts/Exception/TransportExceptionInterface.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Exception; + +/** + * When any error happens at the transport level. + * + * @author Nicolas Grekas + */ +interface TransportExceptionInterface extends ExceptionInterface +{ +} diff --git a/vendor/symfony/http-client-contracts/HttpClientInterface.php b/vendor/symfony/http-client-contracts/HttpClientInterface.php new file mode 100644 index 00000000..158c1a7d --- /dev/null +++ b/vendor/symfony/http-client-contracts/HttpClientInterface.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\Test\HttpClientTestCase; + +/** + * Provides flexible methods for requesting HTTP resources synchronously or asynchronously. + * + * @see HttpClientTestCase for a reference test suite + * + * @method static withOptions(array $options) Returns a new instance of the client with new default options + * + * @author Nicolas Grekas + */ +interface HttpClientInterface +{ + public const OPTIONS_DEFAULTS = [ + 'auth_basic' => null, // array|string - an array containing the username as first value, and optionally the + // password as the second one; or string like username:password - enabling HTTP Basic + // authentication (RFC 7617) + 'auth_bearer' => null, // string - a token enabling HTTP Bearer authorization (RFC 6750) + 'query' => [], // string[] - associative array of query string values to merge with the request's URL + 'headers' => [], // iterable|string[]|string[][] - headers names provided as keys or as part of values + 'body' => '', // array|string|resource|\Traversable|\Closure - the callback SHOULD yield a string + // smaller than the amount requested as argument; the empty string signals EOF; if + // an array is passed, it is meant as a form payload of field names and values + 'json' => null, // mixed - if set, implementations MUST set the "body" option to the JSON-encoded + // value and set the "content-type" header to a JSON-compatible value if it is not + // explicitly defined in the headers option - typically "application/json" + 'user_data' => null, // mixed - any extra data to attach to the request (scalar, callable, object...) that + // MUST be available via $response->getInfo('user_data') - not used internally + 'max_redirects' => 20, // int - the maximum number of redirects to follow; a value lower than or equal to 0 + // means redirects should not be followed; "Authorization" and "Cookie" headers MUST + // NOT follow except for the initial host name + 'http_version' => null, // string - defaults to the best supported version, typically 1.1 or 2.0 + 'base_uri' => null, // string - the URI to resolve relative URLs, following rules in RFC 3986, section 2 + 'buffer' => true, // bool|resource|\Closure - whether the content of the response should be buffered or not, + // or a stream resource where the response body should be written, + // or a closure telling if/where the response should be buffered based on its headers + 'on_progress' => null, // callable(int $dlNow, int $dlSize, array $info) - throwing any exceptions MUST abort + // the request; it MUST be called on DNS resolution, on arrival of headers and on + // completion; it SHOULD be called on upload/download of data and at least 1/s + 'resolve' => [], // string[] - a map of host to IP address that SHOULD replace DNS resolution + 'proxy' => null, // string - by default, the proxy-related env vars handled by curl SHOULD be honored + 'no_proxy' => null, // string - a comma separated list of hosts that do not require a proxy to be reached + 'timeout' => null, // float - the idle timeout - defaults to ini_get('default_socket_timeout') + 'max_duration' => 0, // float - the maximum execution time for the request+response as a whole; + // a value lower than or equal to 0 means it is unlimited + 'bindto' => '0', // string - the interface or the local socket to bind to + 'verify_peer' => true, // see https://php.net/context.ssl for the following options + 'verify_host' => true, + 'cafile' => null, + 'capath' => null, + 'local_cert' => null, + 'local_pk' => null, + 'passphrase' => null, + 'ciphers' => null, + 'peer_fingerprint' => null, + 'capture_peer_cert_chain' => false, + 'extra' => [], // array - additional options that can be ignored if unsupported, unlike regular options + ]; + + /** + * Requests an HTTP resource. + * + * Responses MUST be lazy, but their status code MUST be + * checked even if none of their public methods are called. + * + * Implementations are not required to support all options described above; they can also + * support more custom options; but in any case, they MUST throw a TransportExceptionInterface + * when an unsupported option is passed. + * + * @throws TransportExceptionInterface When an unsupported option is passed + */ + public function request(string $method, string $url, array $options = []): ResponseInterface; + + /** + * Yields responses chunk by chunk as they complete. + * + * @param ResponseInterface|iterable $responses One or more responses created by the current HTTP client + * @param float|null $timeout The idle timeout before yielding timeout chunks + */ + public function stream($responses, float $timeout = null): ResponseStreamInterface; +} diff --git a/vendor/symfony/http-client-contracts/LICENSE b/vendor/symfony/http-client-contracts/LICENSE new file mode 100644 index 00000000..74cdc2db --- /dev/null +++ b/vendor/symfony/http-client-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/http-client-contracts/README.md b/vendor/symfony/http-client-contracts/README.md new file mode 100644 index 00000000..03b3a69b --- /dev/null +++ b/vendor/symfony/http-client-contracts/README.md @@ -0,0 +1,9 @@ +Symfony HttpClient Contracts +============================ + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/vendor/symfony/http-client-contracts/ResponseInterface.php b/vendor/symfony/http-client-contracts/ResponseInterface.php new file mode 100644 index 00000000..df714881 --- /dev/null +++ b/vendor/symfony/http-client-contracts/ResponseInterface.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; + +/** + * A (lazily retrieved) HTTP response. + * + * @author Nicolas Grekas + */ +interface ResponseInterface +{ + /** + * Gets the HTTP status code of the response. + * + * @throws TransportExceptionInterface when a network error occurs + */ + public function getStatusCode(): int; + + /** + * Gets the HTTP headers of the response. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @return string[][] The headers of the response keyed by header names in lowercase + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function getHeaders(bool $throw = true): array; + + /** + * Gets the response body as a string. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function getContent(bool $throw = true): string; + + /** + * Gets the response body decoded as array, typically from a JSON payload. + * + * @param bool $throw Whether an exception should be thrown on 3/4/5xx status codes + * + * @throws DecodingExceptionInterface When the body cannot be decoded to an array + * @throws TransportExceptionInterface When a network error occurs + * @throws RedirectionExceptionInterface On a 3xx when $throw is true and the "max_redirects" option has been reached + * @throws ClientExceptionInterface On a 4xx when $throw is true + * @throws ServerExceptionInterface On a 5xx when $throw is true + */ + public function toArray(bool $throw = true): array; + + /** + * Closes the response stream and all related buffers. + * + * No further chunk will be yielded after this method has been called. + */ + public function cancel(): void; + + /** + * Returns info coming from the transport layer. + * + * This method SHOULD NOT throw any ExceptionInterface and SHOULD be non-blocking. + * The returned info is "live": it can be empty and can change from one call to + * another, as the request/response progresses. + * + * The following info MUST be returned: + * - canceled (bool) - true if the response was canceled using ResponseInterface::cancel(), false otherwise + * - error (string|null) - the error message when the transfer was aborted, null otherwise + * - http_code (int) - the last response code or 0 when it is not known yet + * - http_method (string) - the HTTP verb of the last request + * - redirect_count (int) - the number of redirects followed while executing the request + * - redirect_url (string|null) - the resolved location of redirect responses, null otherwise + * - response_headers (array) - an array modelled after the special $http_response_header variable + * - start_time (float) - the time when the request was sent or 0.0 when it's pending + * - url (string) - the last effective URL of the request + * - user_data (mixed) - the value of the "user_data" request option, null if not set + * + * When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain" + * attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources. + * + * Other info SHOULD be named after curl_getinfo()'s associative return value. + * + * @return mixed An array of all available info, or one of them when $type is + * provided, or null when an unsupported type is requested + */ + public function getInfo(string $type = null); +} diff --git a/vendor/symfony/http-client-contracts/ResponseStreamInterface.php b/vendor/symfony/http-client-contracts/ResponseStreamInterface.php new file mode 100644 index 00000000..fa3e5db6 --- /dev/null +++ b/vendor/symfony/http-client-contracts/ResponseStreamInterface.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient; + +/** + * Yields response chunks, returned by HttpClientInterface::stream(). + * + * @author Nicolas Grekas + * + * @extends \Iterator + */ +interface ResponseStreamInterface extends \Iterator +{ + public function key(): ResponseInterface; + + public function current(): ChunkInterface; +} diff --git a/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php b/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php new file mode 100644 index 00000000..30a70497 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php @@ -0,0 +1,192 @@ + $v) { + switch ($k) { + default: + if (0 !== strpos($k, 'HTTP_')) { + continue 2; + } + // no break + case 'SERVER_NAME': + case 'SERVER_PROTOCOL': + case 'REQUEST_URI': + case 'REQUEST_METHOD': + case 'PHP_AUTH_USER': + case 'PHP_AUTH_PW': + $vars[$k] = $v; + } +} + +$json = json_encode($vars, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + +switch ($vars['REQUEST_URI']) { + default: + exit; + + case '/head': + header('Content-Length: '.strlen($json), true); + break; + + case '/': + case '/?a=a&b=b': + case 'http://127.0.0.1:8057/': + case 'http://localhost:8057/': + ob_start('ob_gzhandler'); + break; + + case '/103': + header('HTTP/1.1 103 Early Hints'); + header('Link: ; rel=preload; as=style', false); + header('Link: ; rel=preload; as=script', false); + flush(); + usleep(1000); + echo "HTTP/1.1 200 OK\r\n"; + echo "Date: Fri, 26 May 2017 10:02:11 GMT\r\n"; + echo "Content-Length: 13\r\n"; + echo "\r\n"; + echo 'Here the body'; + exit; + + case '/404': + header('Content-Type: application/json', true, 404); + break; + + case '/404-gzipped': + header('Content-Type: text/plain', true, 404); + ob_start('ob_gzhandler'); + @ob_flush(); + flush(); + usleep(300000); + echo 'some text'; + exit; + + case '/301': + if ('Basic Zm9vOmJhcg==' === $vars['HTTP_AUTHORIZATION']) { + header('Location: http://127.0.0.1:8057/302', true, 301); + } + break; + + case '/301/bad-tld': + header('Location: http://foo.example.', true, 301); + break; + + case '/301/invalid': + header('Location: //?foo=bar', true, 301); + break; + + case '/302': + if (!isset($vars['HTTP_AUTHORIZATION'])) { + header('Location: http://localhost:8057/', true, 302); + } + break; + + case '/302/relative': + header('Location: ..', true, 302); + break; + + case '/304': + header('Content-Length: 10', true, 304); + echo '12345'; + + return; + + case '/307': + header('Location: http://localhost:8057/post', true, 307); + break; + + case '/length-broken': + header('Content-Length: 1000'); + break; + + case '/post': + $output = json_encode($_POST + ['REQUEST_METHOD' => $vars['REQUEST_METHOD']], \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE); + header('Content-Type: application/json', true); + header('Content-Length: '.strlen($output)); + echo $output; + exit; + + case '/timeout-header': + usleep(300000); + break; + + case '/timeout-body': + echo '<1>'; + @ob_flush(); + flush(); + usleep(500000); + echo '<2>'; + exit; + + case '/timeout-long': + ignore_user_abort(false); + sleep(1); + while (true) { + echo '<1>'; + @ob_flush(); + flush(); + usleep(500); + } + exit; + + case '/chunked': + header('Transfer-Encoding: chunked'); + echo "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\nesome!\r\n0\r\n\r\n"; + exit; + + case '/chunked-broken': + header('Transfer-Encoding: chunked'); + echo "8\r\nSymfony \r\n5\r\nis aw\r\n6\r\ne"; + exit; + + case '/gzip-broken': + header('Content-Encoding: gzip'); + echo str_repeat('-', 1000); + exit; + + case '/max-duration': + ignore_user_abort(false); + while (true) { + echo '<1>'; + @ob_flush(); + flush(); + usleep(500); + } + exit; + + case '/json': + header('Content-Type: application/json'); + echo json_encode([ + 'documents' => [ + ['id' => '/json/1'], + ['id' => '/json/2'], + ['id' => '/json/3'], + ], + ]); + exit; + + case '/json/1': + case '/json/2': + case '/json/3': + header('Content-Type: application/json'); + echo json_encode([ + 'title' => $vars['REQUEST_URI'], + ]); + + exit; +} + +header('Content-Type: application/json', true); + +echo $json; diff --git a/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php b/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php new file mode 100644 index 00000000..7acd6b79 --- /dev/null +++ b/vendor/symfony/http-client-contracts/Test/HttpClientTestCase.php @@ -0,0 +1,1137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Test; + +use PHPUnit\Framework\TestCase; +use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TimeoutExceptionInterface; +use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * A reference test suite for HttpClientInterface implementations. + */ +abstract class HttpClientTestCase extends TestCase +{ + public static function setUpBeforeClass(): void + { + TestHttpServer::start(); + } + + abstract protected function getHttpClient(string $testCase): HttpClientInterface; + + public function testGetRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => ['Foo' => 'baR'], + 'user_data' => $data = new \stdClass(), + ]); + + $this->assertSame([], $response->getInfo('response_headers')); + $this->assertSame($data, $response->getInfo()['user_data']); + $this->assertSame(200, $response->getStatusCode()); + + $info = $response->getInfo(); + $this->assertNull($info['error']); + $this->assertSame(0, $info['redirect_count']); + $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]); + $this->assertSame('Host: localhost:8057', $info['response_headers'][1]); + $this->assertSame('http://localhost:8057/', $info['url']); + + $headers = $response->getHeaders(); + + $this->assertSame('localhost:8057', $headers['host'][0]); + $this->assertSame(['application/json'], $headers['content-type']); + + $body = json_decode($response->getContent(), true); + $this->assertSame($body, $response->toArray()); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertSame('baR', $body['HTTP_FOO']); + + $response = $client->request('GET', 'http://localhost:8057/length-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testHeadRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('HEAD', 'http://localhost:8057/head', [ + 'headers' => ['Foo' => 'baR'], + 'user_data' => $data = new \stdClass(), + 'buffer' => false, + ]); + + $this->assertSame([], $response->getInfo('response_headers')); + $this->assertSame(200, $response->getStatusCode()); + + $info = $response->getInfo(); + $this->assertSame('HTTP/1.1 200 OK', $info['response_headers'][0]); + $this->assertSame('Host: localhost:8057', $info['response_headers'][1]); + + $headers = $response->getHeaders(); + + $this->assertSame('localhost:8057', $headers['host'][0]); + $this->assertSame(['application/json'], $headers['content-type']); + $this->assertTrue(0 < $headers['content-length'][0]); + + $this->assertSame('', $response->getContent()); + } + + public function testNonBufferedGetRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'buffer' => false, + 'headers' => ['Foo' => 'baR'], + ]); + + $body = $response->toArray(); + $this->assertSame('baR', $body['HTTP_FOO']); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testBufferSink() + { + $sink = fopen('php://temp', 'w+'); + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'buffer' => $sink, + 'headers' => ['Foo' => 'baR'], + ]); + + $body = $response->toArray(); + $this->assertSame('baR', $body['HTTP_FOO']); + + rewind($sink); + $sink = stream_get_contents($sink); + $this->assertSame($sink, $response->getContent()); + } + + public function testConditionalBuffering() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057'); + $firstContent = $response->getContent(); + $secondContent = $response->getContent(); + + $this->assertSame($firstContent, $secondContent); + + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () { return false; }]); + $response->getContent(); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testReentrantBufferCallback() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () use (&$response) { + $response->cancel(); + + return true; + }]); + + $this->assertSame(200, $response->getStatusCode()); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testThrowingBufferCallback() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057', ['buffer' => function () { + throw new \Exception('Boo.'); + }]); + + $this->assertSame(200, $response->getStatusCode()); + + $this->expectException(TransportExceptionInterface::class); + $this->expectExceptionMessage('Boo'); + $response->getContent(); + } + + public function testUnsupportedOption() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(\InvalidArgumentException::class); + $client->request('GET', 'http://localhost:8057', [ + 'capture_peer_cert' => 1.0, + ]); + } + + public function testHttpVersion() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'http_version' => 1.0, + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame('HTTP/1.0 200 OK', $response->getInfo('response_headers')[0]); + + $body = $response->toArray(); + + $this->assertSame('HTTP/1.0', $body['SERVER_PROTOCOL']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/', $body['REQUEST_URI']); + } + + public function testChunkedEncoding() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/chunked'); + + $this->assertSame(['chunked'], $response->getHeaders()['transfer-encoding']); + $this->assertSame('Symfony is awesome!', $response->getContent()); + + $response = $client->request('GET', 'http://localhost:8057/chunked-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testClientError() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + + $client->stream($response)->valid(); + + $this->assertSame(404, $response->getInfo('http_code')); + + try { + $response->getHeaders(); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + try { + $response->getContent(); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']); + $this->assertNotEmpty($response->getContent(false)); + + $response = $client->request('GET', 'http://localhost:8057/404'); + + try { + foreach ($client->stream($response) as $chunk) { + $this->assertTrue($chunk->isFirst()); + } + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + } + } + + public function testIgnoreErrors() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + + $this->assertSame(404, $response->getStatusCode()); + } + + public function testDnsError() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); + + try { + $response->getStatusCode(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + try { + $response->getStatusCode(); + $this->fail(TransportExceptionInterface::class.' still expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $response = $client->request('GET', 'http://localhost:8057/301/bad-tld'); + + try { + foreach ($client->stream($response) as $r => $chunk) { + } + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $this->assertSame($response, $r); + $this->assertNotNull($chunk->getError()); + + $this->expectException(TransportExceptionInterface::class); + foreach ($client->stream($response) as $chunk) { + } + } + + public function testInlineAuth() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://foo:bar%3Dbar@localhost:8057'); + + $body = $response->toArray(); + + $this->assertSame('foo', $body['PHP_AUTH_USER']); + $this->assertSame('bar=bar', $body['PHP_AUTH_PW']); + } + + public function testBadRequestBody() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(TransportExceptionInterface::class); + + $response = $client->request('POST', 'http://localhost:8057/', [ + 'body' => function () { yield []; }, + ]); + + $response->getStatusCode(); + } + + public function test304() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/304', [ + 'headers' => ['If-Match' => '"abc"'], + 'buffer' => false, + ]); + + $this->assertSame(304, $response->getStatusCode()); + $this->assertSame('', $response->getContent(false)); + } + + /** + * @testWith [[]] + * [["Content-Length: 7"]] + */ + public function testRedirects(array $headers = []) + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('POST', 'http://localhost:8057/301', [ + 'auth_basic' => 'foo:bar', + 'headers' => $headers, + 'body' => function () { + yield 'foo=bar'; + }, + ]); + + $body = $response->toArray(); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('Basic Zm9vOmJhcg==', $body['HTTP_AUTHORIZATION']); + $this->assertSame('http://localhost:8057/', $response->getInfo('url')); + + $this->assertSame(2, $response->getInfo('redirect_count')); + $this->assertNull($response->getInfo('redirect_url')); + + $expected = [ + 'HTTP/1.1 301 Moved Permanently', + 'Location: http://127.0.0.1:8057/302', + 'Content-Type: application/json', + 'HTTP/1.1 302 Found', + 'Location: http://localhost:8057/', + 'Content-Type: application/json', + 'HTTP/1.1 200 OK', + 'Content-Type: application/json', + ]; + + $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) { + return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true) && 'Content-Encoding: gzip' !== $h; + })); + + $this->assertSame($expected, $filteredHeaders); + } + + public function testInvalidRedirect() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/301/invalid'); + + $this->assertSame(301, $response->getStatusCode()); + $this->assertSame(['//?foo=bar'], $response->getHeaders(false)['location']); + $this->assertSame(0, $response->getInfo('redirect_count')); + $this->assertNull($response->getInfo('redirect_url')); + + $this->expectException(RedirectionExceptionInterface::class); + $response->getHeaders(); + } + + public function testRelativeRedirects() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/302/relative'); + + $body = $response->toArray(); + + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertNull($response->getInfo('redirect_url')); + + $response = $client->request('GET', 'http://localhost:8057/302/relative', [ + 'max_redirects' => 0, + ]); + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + } + + public function testRedirect307() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/307', [ + 'body' => function () { + yield 'foo=bar'; + }, + 'max_redirects' => 0, + ]); + + $this->assertSame(307, $response->getStatusCode()); + + $response = $client->request('POST', 'http://localhost:8057/307', [ + 'body' => 'foo=bar', + ]); + + $body = $response->toArray(); + + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testMaxRedirects() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/301', [ + 'max_redirects' => 1, + 'auth_basic' => 'foo:bar', + ]); + + try { + $response->getHeaders(); + $this->fail(RedirectionExceptionInterface::class.' expected'); + } catch (RedirectionExceptionInterface $e) { + } + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame(1, $response->getInfo('redirect_count')); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + + $expected = [ + 'HTTP/1.1 301 Moved Permanently', + 'Location: http://127.0.0.1:8057/302', + 'Content-Type: application/json', + 'HTTP/1.1 302 Found', + 'Location: http://localhost:8057/', + 'Content-Type: application/json', + ]; + + $filteredHeaders = array_values(array_filter($response->getInfo('response_headers'), function ($h) { + return \in_array(substr($h, 0, 4), ['HTTP', 'Loca', 'Cont'], true); + })); + + $this->assertSame($expected, $filteredHeaders); + } + + public function testStream() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057'); + $chunks = $client->stream($response); + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } elseif ($chunk->isLast()) { + $result[] = 'l'; + } elseif ($chunk->isFirst()) { + $result[] = 'f'; + } + } + + $this->assertSame($response, $r); + $this->assertSame(['f', 'l'], $result); + + $chunk = null; + $i = 0; + + foreach ($client->stream($response) as $chunk) { + ++$i; + } + + $this->assertSame(1, $i); + $this->assertTrue($chunk->isLast()); + } + + public function testAddToStream() + { + $client = $this->getHttpClient(__FUNCTION__); + + $r1 = $client->request('GET', 'http://localhost:8057'); + + $completed = []; + + $pool = [$r1]; + + while ($pool) { + $chunks = $client->stream($pool); + $pool = []; + + foreach ($chunks as $r => $chunk) { + if (!$chunk->isLast()) { + continue; + } + + if ($r1 === $r) { + $r2 = $client->request('GET', 'http://localhost:8057'); + $pool[] = $r2; + } + + $completed[] = $r; + } + } + + $this->assertSame([$r1, $r2], $completed); + } + + public function testCompleteTypeError() + { + $client = $this->getHttpClient(__FUNCTION__); + + $this->expectException(\TypeError::class); + $client->stream(123); + } + + public function testOnProgress() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'headers' => ['Content-Length' => 14], + 'body' => 'foo=0123456789', + 'on_progress' => function (...$state) use (&$steps) { $steps[] = $state; }, + ]); + + $body = $response->toArray(); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + $this->assertSame([0, 0], \array_slice($steps[0], 0, 2)); + $lastStep = \array_slice($steps, -1)[0]; + $this->assertSame([57, 57], \array_slice($lastStep, 0, 2)); + $this->assertSame('http://localhost:8057/post', $steps[0][2]['url']); + } + + public function testPostJson() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'json' => ['foo' => 'bar'], + ]); + + $body = $response->toArray(); + + $this->assertStringContainsString('json', $body['content-type']); + unset($body['content-type']); + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testPostArray() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => ['foo' => 'bar'], + ]); + + $this->assertSame(['foo' => 'bar', 'REQUEST_METHOD' => 'POST'], $response->toArray()); + } + + public function testPostResource() + { + $client = $this->getHttpClient(__FUNCTION__); + + $h = fopen('php://temp', 'w+'); + fwrite($h, 'foo=0123456789'); + rewind($h); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => $h, + ]); + + $body = $response->toArray(); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $body); + } + + public function testPostCallback() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/post', [ + 'body' => function () { + yield 'foo'; + yield ''; + yield '='; + yield '0123456789'; + }, + ]); + + $this->assertSame(['foo' => '0123456789', 'REQUEST_METHOD' => 'POST'], $response->toArray()); + } + + public function testCancel() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-header'); + + $response->cancel(); + $this->expectException(TransportExceptionInterface::class); + $response->getHeaders(); + } + + public function testInfoOnCanceledResponse() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057/timeout-header'); + + $this->assertFalse($response->getInfo('canceled')); + $response->cancel(); + $this->assertTrue($response->getInfo('canceled')); + } + + public function testCancelInStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/404'); + + foreach ($client->stream($response) as $chunk) { + $response->cancel(); + } + + $this->expectException(TransportExceptionInterface::class); + + foreach ($client->stream($response) as $chunk) { + } + } + + public function testOnProgressCancel() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'on_progress' => function ($dlNow) { + if (0 < $dlNow) { + throw new \Exception('Aborting the request.'); + } + }, + ]); + + try { + foreach ($client->stream([$response]) as $chunk) { + } + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + $this->assertSame('Aborting the request.', $e->getPrevious()->getMessage()); + } + + $this->assertNotNull($response->getInfo('error')); + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testOnProgressError() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'on_progress' => function ($dlNow) { + if (0 < $dlNow) { + throw new \Error('BUG.'); + } + }, + ]); + + try { + foreach ($client->stream([$response]) as $chunk) { + } + $this->fail('Error expected'); + } catch (\Error $e) { + $this->assertSame('BUG.', $e->getMessage()); + } + + $this->assertNotNull($response->getInfo('error')); + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testResolve() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://symfony.com:8057/', [ + 'resolve' => ['symfony.com' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + $this->assertSame(200, $client->request('GET', 'http://symfony.com:8057/')->getStatusCode()); + + $response = null; + $this->expectException(TransportExceptionInterface::class); + $client->request('GET', 'http://symfony.com:8057/', ['timeout' => 1]); + } + + public function testIdnResolve() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://0-------------------------------------------------------------0.com:8057/', [ + 'resolve' => ['0-------------------------------------------------------------0.com' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + + $response = $client->request('GET', 'http://Bücher.example:8057/', [ + 'resolve' => ['xn--bcher-kva.example' => '127.0.0.1'], + ]); + + $this->assertSame(200, $response->getStatusCode()); + } + + public function testNotATimeout() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-header', [ + 'timeout' => 0.9, + ]); + sleep(1); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testTimeoutOnAccess() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-header', [ + 'timeout' => 0.1, + ]); + + $this->expectException(TransportExceptionInterface::class); + $response->getHeaders(); + } + + public function testTimeoutIsNotAFatalError() + { + usleep(300000); // wait for the previous test to release the server + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body', [ + 'timeout' => 0.25, + ]); + + try { + $response->getContent(); + $this->fail(TimeoutExceptionInterface::class.' expected'); + } catch (TimeoutExceptionInterface $e) { + } + + for ($i = 0; $i < 10; ++$i) { + try { + $this->assertSame('<1><2>', $response->getContent()); + break; + } catch (TimeoutExceptionInterface $e) { + } + } + + if (10 === $i) { + throw $e; + } + } + + public function testTimeoutOnStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + + $this->assertSame(200, $response->getStatusCode()); + $chunks = $client->stream([$response], 0.2); + + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } else { + $result[] = $chunk->getContent(); + } + } + + $this->assertSame(['<1>', 't'], $result); + + $chunks = $client->stream([$response]); + + foreach ($chunks as $r => $chunk) { + $this->assertSame('<2>', $chunk->getContent()); + $this->assertSame('<1><2>', $r->getContent()); + + return; + } + + $this->fail('The response should have completed'); + } + + public function testUncheckedTimeoutThrows() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + $chunks = $client->stream([$response], 0.1); + + $this->expectException(TransportExceptionInterface::class); + + foreach ($chunks as $r => $chunk) { + } + } + + public function testTimeoutWithActiveConcurrentStream() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $streamingResponse = $client->request('GET', 'http://localhost:8067/max-duration'); + $blockingResponse = $client->request('GET', 'http://localhost:8077/timeout-body', [ + 'timeout' => 0.25, + ]); + + $this->assertSame(200, $streamingResponse->getStatusCode()); + $this->assertSame(200, $blockingResponse->getStatusCode()); + + $this->expectException(TransportExceptionInterface::class); + + try { + $blockingResponse->getContent(); + } finally { + $p1->stop(); + $p2->stop(); + } + } + + public function testTimeoutOnInitialize() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + foreach ($responses as $response) { + try { + $response->getContent(); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + $responses = []; + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + + public function testTimeoutOnDestruct() + { + $p1 = TestHttpServer::start(8067); + $p2 = TestHttpServer::start(8077); + + $client = $this->getHttpClient(__FUNCTION__); + $start = microtime(true); + $responses = []; + + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8067/timeout-header', ['timeout' => 0.25]); + $responses[] = $client->request('GET', 'http://localhost:8077/timeout-header', ['timeout' => 0.25]); + + try { + while ($response = array_shift($responses)) { + try { + unset($response); + $this->fail(TransportExceptionInterface::class.' expected'); + } catch (TransportExceptionInterface $e) { + } + } + + $duration = microtime(true) - $start; + + $this->assertLessThan(1.0, $duration); + } finally { + $p1->stop(); + $p2->stop(); + } + } + + public function testDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + $start = microtime(true); + $client->request('GET', 'http://localhost:8057/timeout-long'); + $client = null; + $duration = microtime(true) - $start; + + $this->assertGreaterThan(1, $duration); + $this->assertLessThan(4, $duration); + } + + public function testGetContentAfterDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/404'); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + $this->assertSame('GET', $e->getResponse()->toArray(false)['REQUEST_METHOD']); + } + } + + public function testGetEncodedContentAfterDestruct() + { + $client = $this->getHttpClient(__FUNCTION__); + + try { + $client->request('GET', 'http://localhost:8057/404-gzipped'); + $this->fail(ClientExceptionInterface::class.' expected'); + } catch (ClientExceptionInterface $e) { + $this->assertSame('some text', $e->getResponse()->getContent(false)); + } + } + + public function testProxy() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://foo:b%3Dar@localhost:8057', + ]); + + $body = $response->toArray(); + $this->assertSame('Basic Zm9vOmI9YXI=', $body['HTTP_PROXY_AUTHORIZATION']); + + $_SERVER['http_proxy'] = 'http://localhost:8057'; + try { + $response = $client->request('GET', 'http://localhost:8057/'); + $body = $response->toArray(); + $this->assertSame('localhost:8057', $body['HTTP_HOST']); + $this->assertMatchesRegularExpression('#^http://(localhost|127\.0\.0\.1):8057/$#', $body['REQUEST_URI']); + } finally { + unset($_SERVER['http_proxy']); + } + } + + public function testNoProxy() + { + putenv('no_proxy='.$_SERVER['no_proxy'] = 'example.com, localhost'); + + try { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/', [ + 'proxy' => 'http://localhost:8057', + ]); + + $body = $response->toArray(); + + $this->assertSame('HTTP/1.1', $body['SERVER_PROTOCOL']); + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertSame('GET', $body['REQUEST_METHOD']); + } finally { + putenv('no_proxy'); + unset($_SERVER['no_proxy']); + } + } + + /** + * @requires extension zlib + */ + public function testAutoEncodingRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057'); + + $this->assertSame(200, $response->getStatusCode()); + + $headers = $response->getHeaders(); + + $this->assertSame(['Accept-Encoding'], $headers['vary']); + $this->assertStringContainsString('gzip', $headers['content-encoding'][0]); + + $body = $response->toArray(); + + $this->assertStringContainsString('gzip', $body['HTTP_ACCEPT_ENCODING']); + } + + public function testBaseUri() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', '../404', [ + 'base_uri' => 'http://localhost:8057/abc/', + ]); + + $this->assertSame(404, $response->getStatusCode()); + $this->assertSame(['application/json'], $response->getHeaders(false)['content-type']); + } + + public function testQuery() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/?a=a', [ + 'query' => ['b' => 'b'], + ]); + + $body = $response->toArray(); + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/?a=a&b=b', $body['REQUEST_URI']); + } + + public function testInformationalResponse() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $this->assertSame('Here the body', $response->getContent()); + $this->assertSame(200, $response->getStatusCode()); + } + + public function testInformationalResponseStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/103'); + + $chunks = []; + foreach ($client->stream($response) as $chunk) { + $chunks[] = $chunk; + } + + $this->assertSame(103, $chunks[0]->getInformationalStatus()[0]); + $this->assertSame(['; rel=preload; as=style', '; rel=preload; as=script'], $chunks[0]->getInformationalStatus()[1]['link']); + $this->assertTrue($chunks[1]->isFirst()); + $this->assertSame('Here the body', $chunks[2]->getContent()); + $this->assertTrue($chunks[3]->isLast()); + $this->assertNull($chunks[3]->getInformationalStatus()); + + $this->assertSame(['date', 'content-length'], array_keys($response->getHeaders())); + $this->assertContains('Link: ; rel=preload; as=style', $response->getInfo('response_headers')); + } + + /** + * @requires extension zlib + */ + public function testUserlandEncodingRequest() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057', [ + 'headers' => ['Accept-Encoding' => 'gzip'], + ]); + + $headers = $response->getHeaders(); + + $this->assertSame(['Accept-Encoding'], $headers['vary']); + $this->assertStringContainsString('gzip', $headers['content-encoding'][0]); + + $body = $response->getContent(); + $this->assertSame("\x1F", $body[0]); + + $body = json_decode(gzdecode($body), true); + $this->assertSame('gzip', $body['HTTP_ACCEPT_ENCODING']); + } + + /** + * @requires extension zlib + */ + public function testGzipBroken() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/gzip-broken'); + + $this->expectException(TransportExceptionInterface::class); + $response->getContent(); + } + + public function testMaxDuration() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/max-duration', [ + 'max_duration' => 0.1, + ]); + + $start = microtime(true); + + try { + $response->getContent(); + } catch (TransportExceptionInterface $e) { + $this->addToAssertionCount(1); + } + + $duration = microtime(true) - $start; + + $this->assertLessThan(10, $duration); + } + + public function testWithOptions() + { + $client = $this->getHttpClient(__FUNCTION__); + if (!method_exists($client, 'withOptions')) { + $this->markTestSkipped(sprintf('Not implementing "%s::withOptions()" is deprecated.', get_debug_type($client))); + } + + $client2 = $client->withOptions(['base_uri' => 'http://localhost:8057/']); + + $this->assertNotSame($client, $client2); + $this->assertSame(\get_class($client), \get_class($client2)); + + $response = $client2->request('GET', '/'); + $this->assertSame(200, $response->getStatusCode()); + } +} diff --git a/vendor/symfony/http-client-contracts/Test/TestHttpServer.php b/vendor/symfony/http-client-contracts/Test/TestHttpServer.php new file mode 100644 index 00000000..55a744ae --- /dev/null +++ b/vendor/symfony/http-client-contracts/Test/TestHttpServer.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\HttpClient\Test; + +use Symfony\Component\Process\PhpExecutableFinder; +use Symfony\Component\Process\Process; + +class TestHttpServer +{ + private static $process = []; + + /** + * @return Process + */ + public static function start(int $port = 8057) + { + if (isset(self::$process[$port])) { + self::$process[$port]->stop(); + } else { + register_shutdown_function(static function () use ($port) { + self::$process[$port]->stop(); + }); + } + + $finder = new PhpExecutableFinder(); + $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:'.$port])); + $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); + $process->start(); + self::$process[$port] = $process; + + do { + usleep(50000); + } while (!@fopen('http://127.0.0.1:'.$port, 'r')); + + return $process; + } +} diff --git a/vendor/symfony/http-client-contracts/composer.json b/vendor/symfony/http-client-contracts/composer.json new file mode 100644 index 00000000..b76cab85 --- /dev/null +++ b/vendor/symfony/http-client-contracts/composer.json @@ -0,0 +1,37 @@ +{ + "name": "symfony/http-client-contracts", + "type": "library", + "description": "Generic abstractions related to HTTP clients", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/http-client-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\HttpClient\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/vendor/symfony/http-foundation/.gitignore b/vendor/symfony/http-foundation/.gitignore deleted file mode 100644 index c49a5d8d..00000000 --- a/vendor/symfony/http-foundation/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff --git a/vendor/symfony/http-foundation/AcceptHeader.php b/vendor/symfony/http-foundation/AcceptHeader.php index daf7f1f4..057c6b53 100644 --- a/vendor/symfony/http-foundation/AcceptHeader.php +++ b/vendor/symfony/http-foundation/AcceptHeader.php @@ -11,6 +11,9 @@ namespace Symfony\Component\HttpFoundation; +// Help opcache.preload discover always-needed symbols +class_exists(AcceptHeaderItem::class); + /** * Represents an Accept-* header. * @@ -44,20 +47,23 @@ public function __construct(array $items) /** * Builds an AcceptHeader instance from a string. * - * @param string $headerValue - * * @return self */ - public static function fromString($headerValue) + public static function fromString(?string $headerValue) { $index = 0; - return new self(array_map(function ($itemValue) use (&$index) { - $item = AcceptHeaderItem::fromString($itemValue); + $parts = HeaderUtils::split($headerValue ?? '', ',;='); + + return new self(array_map(function ($subParts) use (&$index) { + $part = array_shift($subParts); + $attributes = HeaderUtils::combine($subParts); + + $item = new AcceptHeaderItem($part[0], $attributes); $item->setIndex($index++); return $item; - }, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE))); + }, $parts)); } /** @@ -73,11 +79,9 @@ public function __toString() /** * Tests if header has given value. * - * @param string $value - * * @return bool */ - public function has($value) + public function has(string $value) { return isset($this->items[$value]); } @@ -85,13 +89,11 @@ public function has($value) /** * Returns given value's item, if exists. * - * @param string $value - * * @return AcceptHeaderItem|null */ - public function get($value) + public function get(string $value) { - return isset($this->items[$value]) ? $this->items[$value] : null; + return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null; } /** @@ -122,11 +124,9 @@ public function all() /** * Filters items on their value using given regex. * - * @param string $pattern - * * @return self */ - public function filter($pattern) + public function filter(string $pattern) { return new self(array_filter($this->items, function (AcceptHeaderItem $item) use ($pattern) { return preg_match($pattern, $item->getValue()); @@ -148,7 +148,7 @@ public function first() /** * Sorts items by descending quality. */ - private function sort() + private function sort(): void { if (!$this->sorted) { uasort($this->items, function (AcceptHeaderItem $a, AcceptHeaderItem $b) { diff --git a/vendor/symfony/http-foundation/AcceptHeaderItem.php b/vendor/symfony/http-foundation/AcceptHeaderItem.php index 9eb74490..8b86eee6 100644 --- a/vendor/symfony/http-foundation/AcceptHeaderItem.php +++ b/vendor/symfony/http-foundation/AcceptHeaderItem.php @@ -23,10 +23,7 @@ class AcceptHeaderItem private $index = 0; private $attributes = []; - /** - * @param string $value - */ - public function __construct($value, array $attributes = []) + public function __construct(string $value, array $attributes = []) { $this->value = $value; foreach ($attributes as $name => $value) { @@ -37,30 +34,16 @@ public function __construct($value, array $attributes = []) /** * Builds an AcceptHeaderInstance instance from a string. * - * @param string $itemValue - * * @return self */ - public static function fromString($itemValue) + public static function fromString(?string $itemValue) { - $bits = preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/', $itemValue, 0, \PREG_SPLIT_NO_EMPTY | \PREG_SPLIT_DELIM_CAPTURE); - $value = array_shift($bits); - $attributes = []; - - $lastNullAttribute = null; - foreach ($bits as $bit) { - if (($start = substr($bit, 0, 1)) === ($end = substr($bit, -1)) && ('"' === $start || '\'' === $start)) { - $attributes[$lastNullAttribute] = substr($bit, 1, -1); - } elseif ('=' === $end) { - $lastNullAttribute = $bit = substr($bit, 0, -1); - $attributes[$bit] = null; - } else { - $parts = explode('=', $bit); - $attributes[$parts[0]] = isset($parts[1]) && \strlen($parts[1]) > 0 ? $parts[1] : ''; - } - } + $parts = HeaderUtils::split($itemValue ?? '', ';='); + + $part = array_shift($parts); + $attributes = HeaderUtils::combine($parts); - return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ('"' === $start || '\'' === $start) ? substr($value, 1, -1) : $value, $attributes); + return new self($part[0], $attributes); } /** @@ -72,9 +55,7 @@ public function __toString() { $string = $this->value.($this->quality < 1 ? ';q='.$this->quality : ''); if (\count($this->attributes) > 0) { - $string .= ';'.implode(';', array_map(function ($name, $value) { - return sprintf(preg_match('/[,;=]/', $value) ? '%s="%s"' : '%s=%s', $name, $value); - }, array_keys($this->attributes), $this->attributes)); + $string .= '; '.HeaderUtils::toString($this->attributes, ';'); } return $string; @@ -83,11 +64,9 @@ public function __toString() /** * Set the item value. * - * @param string $value - * * @return $this */ - public function setValue($value) + public function setValue(string $value) { $this->value = $value; @@ -107,11 +86,9 @@ public function getValue() /** * Set the item quality. * - * @param float $quality - * * @return $this */ - public function setQuality($quality) + public function setQuality(float $quality) { $this->quality = $quality; @@ -131,11 +108,9 @@ public function getQuality() /** * Set the item index. * - * @param int $index - * * @return $this */ - public function setIndex($index) + public function setIndex(int $index) { $this->index = $index; @@ -155,11 +130,9 @@ public function getIndex() /** * Tests if an attribute exists. * - * @param string $name - * * @return bool */ - public function hasAttribute($name) + public function hasAttribute(string $name) { return isset($this->attributes[$name]); } @@ -167,14 +140,13 @@ public function hasAttribute($name) /** * Returns an attribute by its name. * - * @param string $name - * @param mixed $default + * @param mixed $default * * @return mixed */ - public function getAttribute($name, $default = null) + public function getAttribute(string $name, $default = null) { - return isset($this->attributes[$name]) ? $this->attributes[$name] : $default; + return $this->attributes[$name] ?? $default; } /** @@ -190,17 +162,14 @@ public function getAttributes() /** * Set an attribute. * - * @param string $name - * @param string $value - * * @return $this */ - public function setAttribute($name, $value) + public function setAttribute(string $name, string $value) { if ('q' === $name) { $this->quality = (float) $value; } else { - $this->attributes[$name] = (string) $value; + $this->attributes[$name] = $value; } return $this; diff --git a/vendor/symfony/http-foundation/ApacheRequest.php b/vendor/symfony/http-foundation/ApacheRequest.php deleted file mode 100644 index 4e99186d..00000000 --- a/vendor/symfony/http-foundation/ApacheRequest.php +++ /dev/null @@ -1,43 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation; - -/** - * Request represents an HTTP request from an Apache server. - * - * @author Fabien Potencier - */ -class ApacheRequest extends Request -{ - /** - * {@inheritdoc} - */ - protected function prepareRequestUri() - { - return $this->server->get('REQUEST_URI'); - } - - /** - * {@inheritdoc} - */ - protected function prepareBaseUrl() - { - $baseUrl = $this->server->get('SCRIPT_NAME'); - - if (false === strpos($this->server->get('REQUEST_URI'), $baseUrl)) { - // assume mod_rewrite - return rtrim(\dirname($baseUrl), '/\\'); - } - - return $baseUrl; - } -} diff --git a/vendor/symfony/http-foundation/BinaryFileResponse.php b/vendor/symfony/http-foundation/BinaryFileResponse.php index 0a43b8ac..d3caa36a 100644 --- a/vendor/symfony/http-foundation/BinaryFileResponse.php +++ b/vendor/symfony/http-foundation/BinaryFileResponse.php @@ -34,6 +34,7 @@ class BinaryFileResponse extends Response protected $offset = 0; protected $maxlen = -1; protected $deleteFileAfterSend = false; + protected $chunkSize = 16 * 1024; /** * @param \SplFileInfo|string $file The file to stream @@ -44,7 +45,7 @@ class BinaryFileResponse extends Response * @param bool $autoEtag Whether the ETag header should be automatically set * @param bool $autoLastModified Whether the Last-Modified header should be automatically set */ - public function __construct($file, $status = 200, $headers = [], $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) + public function __construct($file, int $status = 200, array $headers = [], bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true) { parent::__construct(null, $status, $headers); @@ -65,25 +66,26 @@ public function __construct($file, $status = 200, $headers = [], $public = true, * @param bool $autoLastModified Whether the Last-Modified header should be automatically set * * @return static + * + * @deprecated since Symfony 5.2, use __construct() instead. */ - public static function create($file = null, $status = 200, $headers = [], $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) + public static function create($file = null, int $status = 200, array $headers = [], bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true) { + trigger_deprecation('symfony/http-foundation', '5.2', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class); + return new static($file, $status, $headers, $public, $contentDisposition, $autoEtag, $autoLastModified); } /** * Sets the file to stream. * - * @param \SplFileInfo|string $file The file to stream - * @param string $contentDisposition - * @param bool $autoEtag - * @param bool $autoLastModified + * @param \SplFileInfo|string $file The file to stream * * @return $this * * @throws FileException */ - public function setFile($file, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) + public function setFile($file, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true) { if (!$file instanceof File) { if ($file instanceof \SplFileInfo) { @@ -117,15 +119,33 @@ public function setFile($file, $contentDisposition = null, $autoEtag = false, $a /** * Gets the file. * - * @return File The file to stream + * @return File */ public function getFile() { return $this->file; } + /** + * Sets the response stream chunk size. + * + * @return $this + */ + public function setChunkSize(int $chunkSize): self + { + if ($chunkSize < 1 || $chunkSize > \PHP_INT_MAX) { + throw new \LogicException('The chunk size of a BinaryFileResponse cannot be less than 1 or greater than PHP_INT_MAX.'); + } + + $this->chunkSize = $chunkSize; + + return $this; + } + /** * Automatically sets the Last-Modified header according the file modification date. + * + * @return $this */ public function setAutoLastModified() { @@ -136,6 +156,8 @@ public function setAutoLastModified() /** * Automatically sets the ETag header according to the checksum of the file. + * + * @return $this */ public function setAutoEtag() { @@ -153,13 +175,13 @@ public function setAutoEtag() * * @return $this */ - public function setContentDisposition($disposition, $filename = '', $filenameFallback = '') + public function setContentDisposition(string $disposition, string $filename = '', string $filenameFallback = '') { if ('' === $filename) { $filename = $this->file->getFilename(); } - if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) { + if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || str_contains($filename, '%'))) { $encoding = mb_detect_encoding($filename, null, true) ?: '8bit'; for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) { @@ -184,15 +206,19 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal */ public function prepare(Request $request) { - if (!$this->headers->has('Content-Type')) { - $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); + if ($this->isInformational() || $this->isEmpty()) { + parent::prepare($request); + + $this->maxlen = 0; + + return $this; } - if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) { - $this->setProtocolVersion('1.1'); + if (!$this->headers->has('Content-Type')) { + $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); } - $this->ensureIEOverSSLCompatibility($request); + parent::prepare($request); $this->offset = 0; $this->maxlen = -1; @@ -200,11 +226,12 @@ public function prepare(Request $request) if (false === $fileSize = $this->file->getSize()) { return $this; } + $this->headers->remove('Transfer-Encoding'); $this->headers->set('Content-Length', $fileSize); if (!$this->headers->has('Accept-Ranges')) { // Only accept ranges on safe HTTP methods - $this->headers->set('Accept-Ranges', $request->isMethodSafe(false) ? 'bytes' : 'none'); + $this->headers->set('Accept-Ranges', $request->isMethodSafe() ? 'bytes' : 'none'); } if (self::$trustXSendfileTypeHeader && $request->headers->has('X-Sendfile-Type')) { @@ -218,21 +245,16 @@ public function prepare(Request $request) if ('x-accel-redirect' === strtolower($type)) { // Do X-Accel-Mapping substitutions. // @link https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-redirect - foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) { - $mapping = explode('=', $mapping, 2); - - if (2 === \count($mapping)) { - $pathPrefix = trim($mapping[0]); - $location = trim($mapping[1]); - - if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix) { - $path = $location.substr($path, \strlen($pathPrefix)); - // Only set X-Accel-Redirect header if a valid URI can be produced - // as nginx does not serve arbitrary file paths. - $this->headers->set($type, $path); - $this->maxlen = 0; - break; - } + $parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping', ''), ',='); + foreach ($parts as $part) { + [$pathPrefix, $location] = $part; + if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix) { + $path = $location.substr($path, \strlen($pathPrefix)); + // Only set X-Accel-Redirect header if a valid URI can be produced + // as nginx does not serve arbitrary file paths. + $this->headers->set($type, $path); + $this->maxlen = 0; + break; } } } else { @@ -244,8 +266,8 @@ public function prepare(Request $request) if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { $range = $request->headers->get('Range'); - if (0 === strpos($range, 'bytes=')) { - list($start, $end) = explode('-', substr($range, 6), 2) + [0]; + if (str_starts_with($range, 'bytes=')) { + [$start, $end] = explode('-', substr($range, 6), 2) + [1 => 0]; $end = ('' === $end) ? $fileSize - 1 : (int) $end; @@ -274,10 +296,14 @@ public function prepare(Request $request) } } + if ($request->isMethod('HEAD')) { + $this->maxlen = 0; + } + return $this; } - private function hasValidIfRangeHeader($header) + private function hasValidIfRangeHeader(?string $header): bool { if ($this->getEtag() === $header) { return true; @@ -291,30 +317,53 @@ private function hasValidIfRangeHeader($header) } /** - * Sends the file. - * * {@inheritdoc} */ public function sendContent() { - if (!$this->isSuccessful()) { - return parent::sendContent(); - } + try { + if (!$this->isSuccessful()) { + return parent::sendContent(); + } - if (0 === $this->maxlen) { - return $this; - } + if (0 === $this->maxlen) { + return $this; + } + + $out = fopen('php://output', 'w'); + $file = fopen($this->file->getPathname(), 'r'); - $out = fopen('php://output', 'wb'); - $file = fopen($this->file->getPathname(), 'rb'); + ignore_user_abort(true); - stream_copy_to_stream($file, $out, $this->maxlen, $this->offset); + if (0 !== $this->offset) { + fseek($file, $this->offset); + } - fclose($out); - fclose($file); + $length = $this->maxlen; + while ($length && !feof($file)) { + $read = $length > $this->chunkSize || 0 > $length ? $this->chunkSize : $length; - if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) { - unlink($this->file->getPathname()); + if (false === $data = fread($file, $read)) { + break; + } + while ('' !== $data) { + $read = fwrite($out, $data); + if (false === $read || connection_aborted()) { + break 2; + } + if (0 < $length) { + $length -= $read; + } + $data = substr($data, $read); + } + } + + fclose($out); + fclose($file); + } finally { + if ($this->deleteFileAfterSend && is_file($this->file->getPathname())) { + unlink($this->file->getPathname()); + } } return $this; @@ -325,7 +374,7 @@ public function sendContent() * * @throws \LogicException when the content is not null */ - public function setContent($content) + public function setContent(?string $content) { if (null !== $content) { throw new \LogicException('The content cannot be set on a BinaryFileResponse instance.'); @@ -354,11 +403,9 @@ public static function trustXSendfileTypeHeader() * If this is set to true, the file will be unlinked after the request is sent * Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used. * - * @param bool $shouldDelete - * * @return $this */ - public function deleteFileAfterSend($shouldDelete) + public function deleteFileAfterSend(bool $shouldDelete = true) { $this->deleteFileAfterSend = $shouldDelete; diff --git a/vendor/symfony/http-foundation/CHANGELOG.md b/vendor/symfony/http-foundation/CHANGELOG.md index c0d89016..ad7607ad 100644 --- a/vendor/symfony/http-foundation/CHANGELOG.md +++ b/vendor/symfony/http-foundation/CHANGELOG.md @@ -1,12 +1,143 @@ CHANGELOG ========= -3.4.14 ------- +5.4 +--- + + * Deprecate passing `null` as `$requestIp` to `IpUtils::__checkIp()`, `IpUtils::__checkIp4()` or `IpUtils::__checkIp6()`, pass an empty string instead. + * Add the `litespeed_finish_request` method to work with Litespeed + * Deprecate `upload_progress.*` and `url_rewriter.tags` session options + * Allow setting session options via DSN + +5.3 +--- + + * Add the `SessionFactory`, `NativeSessionStorageFactory`, `PhpBridgeSessionStorageFactory` and `MockFileSessionStorageFactory` classes + * Calling `Request::getSession()` when there is no available session throws a `SessionNotFoundException` + * Add the `RequestStack::getSession` method + * Deprecate the `NamespacedAttributeBag` class + * Add `ResponseFormatSame` PHPUnit constraint + * Deprecate the `RequestStack::getMasterRequest()` method and add `getMainRequest()` as replacement + +5.2.0 +----- + + * added support for `X-Forwarded-Prefix` header + * added `HeaderUtils::parseQuery()`: it does the same as `parse_str()` but preserves dots in variable names + * added `File::getContent()` + * added ability to use comma separated ip addresses for `RequestMatcher::matchIps()` + * added `Request::toArray()` to parse a JSON request body to an array + * added `RateLimiter\RequestRateLimiterInterface` and `RateLimiter\AbstractRequestRateLimiter` + * deprecated not passing a `Closure` together with `FILTER_CALLBACK` to `ParameterBag::filter()`; wrap your filter in a closure instead. + * Deprecated the `Request::HEADER_X_FORWARDED_ALL` constant, use either `HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO` or `HEADER_X_FORWARDED_AWS_ELB` or `HEADER_X_FORWARDED_TRAEFIK` constants instead. + * Deprecated `BinaryFileResponse::create()`, use `__construct()` instead + +5.1.0 +----- + + * added `Cookie::withValue`, `Cookie::withDomain`, `Cookie::withExpires`, + `Cookie::withPath`, `Cookie::withSecure`, `Cookie::withHttpOnly`, + `Cookie::withRaw`, `Cookie::withSameSite` + * Deprecate `Response::create()`, `JsonResponse::create()`, + `RedirectResponse::create()`, and `StreamedResponse::create()` methods (use + `__construct()` instead) + * added `Request::preferSafeContent()` and `Response::setContentSafe()` to handle "safe" HTTP preference + according to [RFC 8674](https://tools.ietf.org/html/rfc8674) + * made the Mime component an optional dependency + * added `MarshallingSessionHandler`, `IdentityMarshaller` + * made `Session` accept a callback to report when the session is being used + * Add support for all core cache control directives + * Added `Symfony\Component\HttpFoundation\InputBag` + * Deprecated retrieving non-string values using `InputBag::get()`, use `InputBag::all()` if you need access to the collection of values + +5.0.0 +----- + + * made `Cookie` auto-secure and lax by default + * removed classes in the `MimeType` namespace, use the Symfony Mime component instead + * removed method `UploadedFile::getClientSize()` and the related constructor argument + * made `Request::getSession()` throw if the session has not been set before + * removed `Response::HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL` + * passing a null url when instantiating a `RedirectResponse` is not allowed + +4.4.0 +----- + + * passing arguments to `Request::isMethodSafe()` is deprecated. + * `ApacheRequest` is deprecated, use the `Request` class instead. + * passing a third argument to `HeaderBag::get()` is deprecated, use method `all()` instead + * [BC BREAK] `PdoSessionHandler` with MySQL changed the type of the lifetime column, + make sure to run `ALTER TABLE sessions MODIFY sess_lifetime INTEGER UNSIGNED NOT NULL` to + update your database. + * `PdoSessionHandler` now precalculates the expiry timestamp in the lifetime column, + make sure to run `CREATE INDEX EXPIRY ON sessions (sess_lifetime)` to update your database + to speed up garbage collection of expired sessions. + * added `SessionHandlerFactory` to create session handlers with a DSN + * added `IpUtils::anonymize()` to help with GDPR compliance. + +4.3.0 +----- + + * added PHPUnit constraints: `RequestAttributeValueSame`, `ResponseCookieValueSame`, `ResponseHasCookie`, + `ResponseHasHeader`, `ResponseHeaderSame`, `ResponseIsRedirected`, `ResponseIsSuccessful`, and `ResponseStatusCodeSame` + * deprecated `MimeTypeGuesserInterface` and `ExtensionGuesserInterface` in favor of `Symfony\Component\Mime\MimeTypesInterface`. + * deprecated `MimeType` and `MimeTypeExtensionGuesser` in favor of `Symfony\Component\Mime\MimeTypes`. + * deprecated `FileBinaryMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileBinaryMimeTypeGuesser`. + * deprecated `FileinfoMimeTypeGuesser` in favor of `Symfony\Component\Mime\FileinfoMimeTypeGuesser`. + * added `UrlHelper` that allows to get an absolute URL and a relative path for a given path + +4.2.0 +----- + + * the default value of the "$secure" and "$samesite" arguments of Cookie's constructor + will respectively change from "false" to "null" and from "null" to "lax" in Symfony + 5.0, you should define their values explicitly or use "Cookie::create()" instead. + * added `matchPort()` in RequestMatcher + +4.1.3 +----- * [BC BREAK] Support for the IIS-only `X_ORIGINAL_URL` and `X_REWRITE_URL` HTTP headers has been dropped for security reasons. +4.1.0 +----- + + * Query string normalization uses `parse_str()` instead of custom parsing logic. + * Passing the file size to the constructor of the `UploadedFile` class is deprecated. + * The `getClientSize()` method of the `UploadedFile` class is deprecated. Use `getSize()` instead. + * added `RedisSessionHandler` to use Redis as a session storage + * The `get()` method of the `AcceptHeader` class now takes into account the + `*` and `*/*` default values (if they are present in the Accept HTTP header) + when looking for items. + * deprecated `Request::getSession()` when no session has been set. Use `Request::hasSession()` instead. + * added `CannotWriteFileException`, `ExtensionFileException`, `FormSizeFileException`, + `IniSizeFileException`, `NoFileException`, `NoTmpDirFileException`, `PartialFileException` to + handle failed `UploadedFile`. + * added `MigratingSessionHandler` for migrating between two session handlers without losing sessions + * added `HeaderUtils`. + +4.0.0 +----- + + * the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` + methods have been removed + * the `Request::HEADER_CLIENT_IP` constant has been removed, use + `Request::HEADER_X_FORWARDED_FOR` instead + * the `Request::HEADER_CLIENT_HOST` constant has been removed, use + `Request::HEADER_X_FORWARDED_HOST` instead + * the `Request::HEADER_CLIENT_PROTO` constant has been removed, use + `Request::HEADER_X_FORWARDED_PROTO` instead + * the `Request::HEADER_CLIENT_PORT` constant has been removed, use + `Request::HEADER_X_FORWARDED_PORT` instead + * checking for cacheable HTTP methods using the `Request::isMethodSafe()` + method (by not passing `false` as its argument) is not supported anymore and + throws a `\BadMethodCallException` + * the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes have been removed + * setting session save handlers that do not implement `\SessionHandlerInterface` in + `NativeSessionStorage::setSaveHandler()` is not supported anymore and throws a + `\TypeError` + 3.4.0 ----- diff --git a/vendor/symfony/http-foundation/Cookie.php b/vendor/symfony/http-foundation/Cookie.php index 98a5ef00..91024535 100644 --- a/vendor/symfony/http-foundation/Cookie.php +++ b/vendor/symfony/http-foundation/Cookie.php @@ -18,9 +18,9 @@ */ class Cookie { - const SAMESITE_NONE = 'none'; - const SAMESITE_LAX = 'lax'; - const SAMESITE_STRICT = 'strict'; + public const SAMESITE_NONE = 'none'; + public const SAMESITE_LAX = 'lax'; + public const SAMESITE_STRICT = 'strict'; protected $name; protected $value; @@ -32,20 +32,18 @@ class Cookie private $raw; private $sameSite; + private $secureDefault = false; - private static $reservedCharsList = "=,; \t\r\n\v\f"; - private static $reservedCharsFrom = ['=', ',', ';', ' ', "\t", "\r", "\n", "\v", "\f"]; - private static $reservedCharsTo = ['%3D', '%2C', '%3B', '%20', '%09', '%0D', '%0A', '%0B', '%0C']; + private const RESERVED_CHARS_LIST = "=,; \t\r\n\v\f"; + private const RESERVED_CHARS_FROM = ['=', ',', ';', ' ', "\t", "\r", "\n", "\v", "\f"]; + private const RESERVED_CHARS_TO = ['%3D', '%2C', '%3B', '%20', '%09', '%0D', '%0A', '%0B', '%0C']; /** * Creates cookie from raw header string. * - * @param string $cookie - * @param bool $decode - * * @return static */ - public static function fromString($cookie, $decode = false) + public static function fromString(string $cookie, bool $decode = false) { $data = [ 'expires' => 0, @@ -56,53 +54,45 @@ public static function fromString($cookie, $decode = false) 'raw' => !$decode, 'samesite' => null, ]; - foreach (explode(';', $cookie) as $part) { - if (false === strpos($part, '=')) { - $key = trim($part); - $value = true; - } else { - list($key, $value) = explode('=', trim($part), 2); - $key = trim($key); - $value = trim($value); - } - if (!isset($data['name'])) { - $data['name'] = $decode ? urldecode($key) : $key; - $data['value'] = true === $value ? null : ($decode ? urldecode($value) : $value); - continue; - } - switch ($key = strtolower($key)) { - case 'name': - case 'value': - break; - case 'max-age': - $data['expires'] = time() + (int) $value; - break; - default: - $data[$key] = $value; - break; - } + + $parts = HeaderUtils::split($cookie, ';='); + $part = array_shift($parts); + + $name = $decode ? urldecode($part[0]) : $part[0]; + $value = isset($part[1]) ? ($decode ? urldecode($part[1]) : $part[1]) : null; + + $data = HeaderUtils::combine($parts) + $data; + $data['expires'] = self::expiresTimestamp($data['expires']); + + if (isset($data['max-age']) && ($data['max-age'] > 0 || $data['expires'] > time())) { + $data['expires'] = time() + (int) $data['max-age']; } - return new static($data['name'], $data['value'], $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']); + return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']); + } + + public static function create(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX): self + { + return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite); } /** * @param string $name The name of the cookie * @param string|null $value The value of the cookie * @param int|string|\DateTimeInterface $expire The time the cookie expires - * @param string $path The path on the server in which the cookie will be available on + * @param string|null $path The path on the server in which the cookie will be available on * @param string|null $domain The domain that the cookie is available to - * @param bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client + * @param bool|null $secure Whether the client should send back the cookie only over HTTPS or null to auto-enable this when the request is already using HTTPS * @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol * @param bool $raw Whether the cookie value should be sent with no url encoding * @param string|null $sameSite Whether the cookie will be available for cross-site requests * * @throws \InvalidArgumentException */ - public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null) + public function __construct(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = 'lax') { // from PHP source code - if ($raw && false !== strpbrk($name, self::$reservedCharsList)) { + if ($raw && false !== strpbrk($name, self::RESERVED_CHARS_LIST)) { throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); } @@ -110,6 +100,65 @@ public function __construct($name, $value = null, $expire = 0, $path = '/', $dom throw new \InvalidArgumentException('The cookie name cannot be empty.'); } + $this->name = $name; + $this->value = $value; + $this->domain = $domain; + $this->expire = self::expiresTimestamp($expire); + $this->path = empty($path) ? '/' : $path; + $this->secure = $secure; + $this->httpOnly = $httpOnly; + $this->raw = $raw; + $this->sameSite = $this->withSameSite($sameSite)->sameSite; + } + + /** + * Creates a cookie copy with a new value. + * + * @return static + */ + public function withValue(?string $value): self + { + $cookie = clone $this; + $cookie->value = $value; + + return $cookie; + } + + /** + * Creates a cookie copy with a new domain that the cookie is available to. + * + * @return static + */ + public function withDomain(?string $domain): self + { + $cookie = clone $this; + $cookie->domain = $domain; + + return $cookie; + } + + /** + * Creates a cookie copy with a new time the cookie expires. + * + * @param int|string|\DateTimeInterface $expire + * + * @return static + */ + public function withExpires($expire = 0): self + { + $cookie = clone $this; + $cookie->expire = self::expiresTimestamp($expire); + + return $cookie; + } + + /** + * Converts expires formats to a unix timestamp. + * + * @param int|string|\DateTimeInterface $expire + */ + private static function expiresTimestamp($expire = 0): int + { // convert expiration time to a Unix timestamp if ($expire instanceof \DateTimeInterface) { $expire = $expire->format('U'); @@ -121,16 +170,75 @@ public function __construct($name, $value = null, $expire = 0, $path = '/', $dom } } - $this->name = $name; - $this->value = $value; - $this->domain = $domain; - $this->expire = 0 < $expire ? (int) $expire : 0; - $this->path = empty($path) ? '/' : $path; - $this->secure = (bool) $secure; - $this->httpOnly = (bool) $httpOnly; - $this->raw = (bool) $raw; + return 0 < $expire ? (int) $expire : 0; + } + + /** + * Creates a cookie copy with a new path on the server in which the cookie will be available on. + * + * @return static + */ + public function withPath(string $path): self + { + $cookie = clone $this; + $cookie->path = '' === $path ? '/' : $path; + + return $cookie; + } + + /** + * Creates a cookie copy that only be transmitted over a secure HTTPS connection from the client. + * + * @return static + */ + public function withSecure(bool $secure = true): self + { + $cookie = clone $this; + $cookie->secure = $secure; + + return $cookie; + } + + /** + * Creates a cookie copy that be accessible only through the HTTP protocol. + * + * @return static + */ + public function withHttpOnly(bool $httpOnly = true): self + { + $cookie = clone $this; + $cookie->httpOnly = $httpOnly; - if (null !== $sameSite) { + return $cookie; + } + + /** + * Creates a cookie copy that uses no url encoding. + * + * @return static + */ + public function withRaw(bool $raw = true): self + { + if ($raw && false !== strpbrk($this->name, self::RESERVED_CHARS_LIST)) { + throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $this->name)); + } + + $cookie = clone $this; + $cookie->raw = $raw; + + return $cookie; + } + + /** + * Creates a cookie copy with SameSite attribute. + * + * @return static + */ + public function withSameSite(?string $sameSite): self + { + if ('' === $sameSite) { + $sameSite = null; + } elseif (null !== $sameSite) { $sameSite = strtolower($sameSite); } @@ -138,20 +246,23 @@ public function __construct($name, $value = null, $expire = 0, $path = '/', $dom throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.'); } - $this->sameSite = $sameSite; + $cookie = clone $this; + $cookie->sameSite = $sameSite; + + return $cookie; } /** * Returns the cookie as a string. * - * @return string The cookie + * @return string */ public function __toString() { if ($this->isRaw()) { $str = $this->getName(); } else { - $str = str_replace(self::$reservedCharsFrom, self::$reservedCharsTo, $this->getName()); + $str = str_replace(self::RESERVED_CHARS_FROM, self::RESERVED_CHARS_TO, $this->getName()); } $str .= '='; @@ -258,7 +369,7 @@ public function getPath() */ public function isSecure() { - return $this->secure; + return $this->secure ?? $this->secureDefault; } /** @@ -300,4 +411,12 @@ public function getSameSite() { return $this->sameSite; } + + /** + * @param bool $default The default value of the "secure" flag when it is set to null + */ + public function setSecureDefault(bool $default): void + { + $this->secureDefault = $default; + } } diff --git a/vendor/symfony/http-foundation/Exception/BadRequestException.php b/vendor/symfony/http-foundation/Exception/BadRequestException.php new file mode 100644 index 00000000..e4bb309c --- /dev/null +++ b/vendor/symfony/http-foundation/Exception/BadRequestException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Exception; + +/** + * Raised when a user sends a malformed request. + */ +class BadRequestException extends \UnexpectedValueException implements RequestExceptionInterface +{ +} diff --git a/vendor/symfony/http-foundation/Exception/JsonException.php b/vendor/symfony/http-foundation/Exception/JsonException.php new file mode 100644 index 00000000..5990e760 --- /dev/null +++ b/vendor/symfony/http-foundation/Exception/JsonException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Exception; + +/** + * Thrown by Request::toArray() when the content cannot be JSON-decoded. + * + * @author Tobias Nyholm + */ +final class JsonException extends \UnexpectedValueException implements RequestExceptionInterface +{ +} diff --git a/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php b/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php new file mode 100644 index 00000000..94b0cb69 --- /dev/null +++ b/vendor/symfony/http-foundation/Exception/SessionNotFoundException.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Exception; + +/** + * Raised when a session does not exist. This happens in the following cases: + * - the session is not enabled + * - attempt to read a session outside a request context (ie. cli script). + * + * @author Jérémy Derussé + */ +class SessionNotFoundException extends \LogicException implements RequestExceptionInterface +{ + public function __construct(string $message = 'There is currently no session available.', int $code = 0, \Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + } +} diff --git a/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php b/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php index 3b8e41d4..136d2a9f 100644 --- a/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php +++ b/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php @@ -18,10 +18,7 @@ */ class AccessDeniedException extends FileException { - /** - * @param string $path The path to the accessed file - */ - public function __construct($path) + public function __construct(string $path) { parent::__construct(sprintf('The file %s could not be accessed', $path)); } diff --git a/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php b/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php new file mode 100644 index 00000000..c49f53a6 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_CANT_WRITE error occurred with UploadedFile. + * + * @author Florent Mata + */ +class CannotWriteFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php b/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php new file mode 100644 index 00000000..ed83499c --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_EXTENSION error occurred with UploadedFile. + * + * @author Florent Mata + */ +class ExtensionFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php b/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php index bfcc37ec..31bdf68f 100644 --- a/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php +++ b/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php @@ -18,10 +18,7 @@ */ class FileNotFoundException extends FileException { - /** - * @param string $path The path to the file that was not found - */ - public function __construct($path) + public function __construct(string $path) { parent::__construct(sprintf('The file "%s" does not exist', $path)); } diff --git a/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php b/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php new file mode 100644 index 00000000..8741be08 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_FORM_SIZE error occurred with UploadedFile. + * + * @author Florent Mata + */ +class FormSizeFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php b/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php new file mode 100644 index 00000000..c8fde610 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_INI_SIZE error occurred with UploadedFile. + * + * @author Florent Mata + */ +class IniSizeFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/NoFileException.php b/vendor/symfony/http-foundation/File/Exception/NoFileException.php new file mode 100644 index 00000000..4b48cc77 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/NoFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_NO_FILE error occurred with UploadedFile. + * + * @author Florent Mata + */ +class NoFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php b/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php new file mode 100644 index 00000000..bdead2d9 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_NO_TMP_DIR error occurred with UploadedFile. + * + * @author Florent Mata + */ +class NoTmpDirFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/PartialFileException.php b/vendor/symfony/http-foundation/File/Exception/PartialFileException.php new file mode 100644 index 00000000..4641efb5 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/PartialFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_PARTIAL error occurred with UploadedFile. + * + * @author Florent Mata + */ +class PartialFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php b/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php index 62005d3b..8533f99a 100644 --- a/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php +++ b/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php @@ -13,8 +13,8 @@ class UnexpectedTypeException extends FileException { - public function __construct($value, $expectedType) + public function __construct($value, string $expectedType) { - parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, \is_object($value) ? \get_class($value) : \gettype($value))); + parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, get_debug_type($value))); } } diff --git a/vendor/symfony/http-foundation/File/File.php b/vendor/symfony/http-foundation/File/File.php index 309339e5..d941577d 100644 --- a/vendor/symfony/http-foundation/File/File.php +++ b/vendor/symfony/http-foundation/File/File.php @@ -13,8 +13,7 @@ use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; -use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; +use Symfony\Component\Mime\MimeTypes; /** * A file in the file system. @@ -31,7 +30,7 @@ class File extends \SplFileInfo * * @throws FileNotFoundException If the given path is not a file */ - public function __construct($path, $checkPath = true) + public function __construct(string $path, bool $checkPath = true) { if ($checkPath && !is_file($path)) { throw new FileNotFoundException($path); @@ -48,54 +47,57 @@ public function __construct($path, $checkPath = true) * This method uses the mime type as guessed by getMimeType() * to guess the file extension. * - * @return string|null The guessed extension or null if it cannot be guessed + * @return string|null * - * @see ExtensionGuesser + * @see MimeTypes * @see getMimeType() */ public function guessExtension() { - $type = $this->getMimeType(); - $guesser = ExtensionGuesser::getInstance(); + if (!class_exists(MimeTypes::class)) { + throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".'); + } - return $guesser->guess($type); + return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null; } /** * Returns the mime type of the file. * - * The mime type is guessed using a MimeTypeGuesser instance, which uses finfo(), - * mime_content_type() and the system binary "file" (in this order), depending on - * which of those are available. + * The mime type is guessed using a MimeTypeGuesserInterface instance, + * which uses finfo_file() then the "file" system binary, + * depending on which of those are available. * - * @return string|null The guessed mime type (e.g. "application/pdf") + * @return string|null * - * @see MimeTypeGuesser + * @see MimeTypes */ public function getMimeType() { - $guesser = MimeTypeGuesser::getInstance(); + if (!class_exists(MimeTypes::class)) { + throw new \LogicException('You cannot guess the mime type as the Mime component is not installed. Try running "composer require symfony/mime".'); + } - return $guesser->guess($this->getPathname()); + return MimeTypes::getDefault()->guessMimeType($this->getPathname()); } /** * Moves the file to a new location. * - * @param string $directory The destination folder - * @param string $name The new file name - * - * @return self A File object representing the new file + * @return self * * @throws FileException if the target file could not be created */ - public function move($directory, $name = null) + public function move(string $directory, string $name = null) { $target = $this->getTargetFile($directory, $name); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); - $renamed = rename($this->getPathname(), $target); - restore_error_handler(); + try { + $renamed = rename($this->getPathname(), $target); + } finally { + restore_error_handler(); + } if (!$renamed) { throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); } @@ -105,7 +107,21 @@ public function move($directory, $name = null) return $target; } - protected function getTargetFile($directory, $name = null) + public function getContent(): string + { + $content = file_get_contents($this->getPathname()); + + if (false === $content) { + throw new FileException(sprintf('Could not get the content of the file "%s".', $this->getPathname())); + } + + return $content; + } + + /** + * @return self + */ + protected function getTargetFile(string $directory, string $name = null) { if (!is_dir($directory)) { if (false === @mkdir($directory, 0777, true) && !is_dir($directory)) { @@ -123,11 +139,9 @@ protected function getTargetFile($directory, $name = null) /** * Returns locale independent base name of the given path. * - * @param string $name The new file name - * - * @return string containing + * @return string */ - protected function getName($name) + protected function getName(string $name) { $originalName = str_replace('\\', '/', $name); $pos = strrpos($originalName, '/'); diff --git a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php b/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php deleted file mode 100644 index f9393df9..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php +++ /dev/null @@ -1,96 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -/** - * A singleton mime type to file extension guesser. - * - * A default guesser is provided. - * You can register custom guessers by calling the register() - * method on the singleton instance: - * - * $guesser = ExtensionGuesser::getInstance(); - * $guesser->register(new MyCustomExtensionGuesser()); - * - * The last registered guesser is preferred over previously registered ones. - */ -class ExtensionGuesser implements ExtensionGuesserInterface -{ - /** - * The singleton instance. - * - * @var ExtensionGuesser - */ - private static $instance = null; - - /** - * All registered ExtensionGuesserInterface instances. - * - * @var array - */ - protected $guessers = []; - - /** - * Returns the singleton instance. - * - * @return self - */ - public static function getInstance() - { - if (null === self::$instance) { - self::$instance = new self(); - } - - return self::$instance; - } - - /** - * Registers all natively provided extension guessers. - */ - private function __construct() - { - $this->register(new MimeTypeExtensionGuesser()); - } - - /** - * Registers a new extension guesser. - * - * When guessing, this guesser is preferred over previously registered ones. - */ - public function register(ExtensionGuesserInterface $guesser) - { - array_unshift($this->guessers, $guesser); - } - - /** - * Tries to guess the extension. - * - * The mime type is passed to each registered mime type guesser in reverse order - * of their registration (last registered is queried first). Once a guesser - * returns a value that is not NULL, this method terminates and returns the - * value. - * - * @param string $mimeType The mime type - * - * @return string The guessed extension or NULL, if none could be guessed - */ - public function guess($mimeType) - { - foreach ($this->guessers as $guesser) { - if (null !== $extension = $guesser->guess($mimeType)) { - return $extension; - } - } - - return null; - } -} diff --git a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php b/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php deleted file mode 100644 index d19a0e53..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -/** - * Guesses the file extension corresponding to a given mime type. - */ -interface ExtensionGuesserInterface -{ - /** - * Makes a best guess for a file extension, given a mime type. - * - * @param string $mimeType The mime type - * - * @return string The guessed extension or NULL, if none could be guessed - */ - public function guess($mimeType); -} diff --git a/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php deleted file mode 100644 index 7045e94d..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php +++ /dev/null @@ -1,99 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; -use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; - -/** - * Guesses the mime type with the binary "file" (only available on *nix). - * - * @author Bernhard Schussek - */ -class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface -{ - private $cmd; - - /** - * The $cmd pattern must contain a "%s" string that will be replaced - * with the file name to guess. - * - * The command output must start with the mime type of the file. - * - * @param string $cmd The command to run to get the mime type of a file - */ - public function __construct($cmd = 'file -b --mime -- %s 2>/dev/null') - { - $this->cmd = $cmd; - } - - /** - * Returns whether this guesser is supported on the current OS. - * - * @return bool - */ - public static function isSupported() - { - static $supported = null; - - if (null !== $supported) { - return $supported; - } - - if ('\\' === \DIRECTORY_SEPARATOR || !\function_exists('passthru') || !\function_exists('escapeshellarg')) { - return $supported = false; - } - - ob_start(); - passthru('command -v file', $exitStatus); - $binPath = trim(ob_get_clean()); - - return $supported = 0 === $exitStatus && '' !== $binPath; - } - - /** - * {@inheritdoc} - */ - public function guess($path) - { - if (!is_file($path)) { - throw new FileNotFoundException($path); - } - - if (!is_readable($path)) { - throw new AccessDeniedException($path); - } - - if (!self::isSupported()) { - return null; - } - - ob_start(); - - // need to use --mime instead of -i. see #6641 - passthru(sprintf($this->cmd, escapeshellarg((0 === strpos($path, '-') ? './' : '').$path)), $return); - if ($return > 0) { - ob_end_clean(); - - return null; - } - - $type = trim(ob_get_clean()); - - if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) { - // it's not a type, but an error message - return null; - } - - return $match[1]; - } -} diff --git a/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php deleted file mode 100644 index 99aa44f9..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; -use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; - -/** - * Guesses the mime type using the PECL extension FileInfo. - * - * @author Bernhard Schussek - */ -class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface -{ - private $magicFile; - - /** - * @param string $magicFile A magic file to use with the finfo instance - * - * @see https://php.net/finfo-open - */ - public function __construct($magicFile = null) - { - $this->magicFile = $magicFile; - } - - /** - * Returns whether this guesser is supported on the current OS/PHP setup. - * - * @return bool - */ - public static function isSupported() - { - return \function_exists('finfo_open'); - } - - /** - * {@inheritdoc} - */ - public function guess($path) - { - if (!is_file($path)) { - throw new FileNotFoundException($path); - } - - if (!is_readable($path)) { - throw new AccessDeniedException($path); - } - - if (!self::isSupported()) { - return null; - } - - if (!$finfo = new \finfo(\FILEINFO_MIME_TYPE, $this->magicFile)) { - return null; - } - $mimeType = $finfo->file($path); - - if ($mimeType && 0 === (\strlen($mimeType) % 2)) { - $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); - $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; - } - - return $mimeType; - } -} diff --git a/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php b/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php deleted file mode 100644 index 5a809a24..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php +++ /dev/null @@ -1,819 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -/** - * Provides a best-guess mapping of mime type to file extension. - */ -class MimeTypeExtensionGuesser implements ExtensionGuesserInterface -{ - /** - * A map of mime types and their default extensions. - * - * This list has been placed under the public domain by the Apache HTTPD project. - * This list has been updated from upstream on 2019-01-14. - * - * @see https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types - */ - protected $defaultExtensions = [ - 'application/andrew-inset' => 'ez', - 'application/applixware' => 'aw', - 'application/atom+xml' => 'atom', - 'application/atomcat+xml' => 'atomcat', - 'application/atomsvc+xml' => 'atomsvc', - 'application/ccxml+xml' => 'ccxml', - 'application/cdmi-capability' => 'cdmia', - 'application/cdmi-container' => 'cdmic', - 'application/cdmi-domain' => 'cdmid', - 'application/cdmi-object' => 'cdmio', - 'application/cdmi-queue' => 'cdmiq', - 'application/cu-seeme' => 'cu', - 'application/davmount+xml' => 'davmount', - 'application/docbook+xml' => 'dbk', - 'application/dssc+der' => 'dssc', - 'application/dssc+xml' => 'xdssc', - 'application/ecmascript' => 'ecma', - 'application/emma+xml' => 'emma', - 'application/epub+zip' => 'epub', - 'application/exi' => 'exi', - 'application/font-tdpfr' => 'pfr', - 'application/gml+xml' => 'gml', - 'application/gpx+xml' => 'gpx', - 'application/gxf' => 'gxf', - 'application/hyperstudio' => 'stk', - 'application/inkml+xml' => 'ink', - 'application/ipfix' => 'ipfix', - 'application/java-archive' => 'jar', - 'application/java-serialized-object' => 'ser', - 'application/java-vm' => 'class', - 'application/javascript' => 'js', - 'application/json' => 'json', - 'application/jsonml+json' => 'jsonml', - 'application/lost+xml' => 'lostxml', - 'application/mac-binhex40' => 'hqx', - 'application/mac-compactpro' => 'cpt', - 'application/mads+xml' => 'mads', - 'application/marc' => 'mrc', - 'application/marcxml+xml' => 'mrcx', - 'application/mathematica' => 'ma', - 'application/mathml+xml' => 'mathml', - 'application/mbox' => 'mbox', - 'application/mediaservercontrol+xml' => 'mscml', - 'application/metalink+xml' => 'metalink', - 'application/metalink4+xml' => 'meta4', - 'application/mets+xml' => 'mets', - 'application/mods+xml' => 'mods', - 'application/mp21' => 'm21', - 'application/mp4' => 'mp4s', - 'application/msword' => 'doc', - 'application/mxf' => 'mxf', - 'application/octet-stream' => 'bin', - 'application/oda' => 'oda', - 'application/oebps-package+xml' => 'opf', - 'application/ogg' => 'ogx', - 'application/omdoc+xml' => 'omdoc', - 'application/onenote' => 'onetoc', - 'application/oxps' => 'oxps', - 'application/patch-ops-error+xml' => 'xer', - 'application/pdf' => 'pdf', - 'application/pgp-encrypted' => 'pgp', - 'application/pgp-signature' => 'asc', - 'application/pics-rules' => 'prf', - 'application/pkcs10' => 'p10', - 'application/pkcs7-mime' => 'p7m', - 'application/pkcs7-signature' => 'p7s', - 'application/pkcs8' => 'p8', - 'application/pkix-attr-cert' => 'ac', - 'application/pkix-cert' => 'cer', - 'application/pkix-crl' => 'crl', - 'application/pkix-pkipath' => 'pkipath', - 'application/pkixcmp' => 'pki', - 'application/pls+xml' => 'pls', - 'application/postscript' => 'ai', - 'application/prs.cww' => 'cww', - 'application/pskc+xml' => 'pskcxml', - 'application/rdf+xml' => 'rdf', - 'application/reginfo+xml' => 'rif', - 'application/relax-ng-compact-syntax' => 'rnc', - 'application/resource-lists+xml' => 'rl', - 'application/resource-lists-diff+xml' => 'rld', - 'application/rls-services+xml' => 'rs', - 'application/rpki-ghostbusters' => 'gbr', - 'application/rpki-manifest' => 'mft', - 'application/rpki-roa' => 'roa', - 'application/rsd+xml' => 'rsd', - 'application/rss+xml' => 'rss', - 'application/rtf' => 'rtf', - 'application/sbml+xml' => 'sbml', - 'application/scvp-cv-request' => 'scq', - 'application/scvp-cv-response' => 'scs', - 'application/scvp-vp-request' => 'spq', - 'application/scvp-vp-response' => 'spp', - 'application/sdp' => 'sdp', - 'application/set-payment-initiation' => 'setpay', - 'application/set-registration-initiation' => 'setreg', - 'application/shf+xml' => 'shf', - 'application/smil+xml' => 'smi', - 'application/sparql-query' => 'rq', - 'application/sparql-results+xml' => 'srx', - 'application/srgs' => 'gram', - 'application/srgs+xml' => 'grxml', - 'application/sru+xml' => 'sru', - 'application/ssdl+xml' => 'ssdl', - 'application/ssml+xml' => 'ssml', - 'application/tei+xml' => 'tei', - 'application/thraud+xml' => 'tfi', - 'application/timestamped-data' => 'tsd', - 'application/vnd.3gpp.pic-bw-large' => 'plb', - 'application/vnd.3gpp.pic-bw-small' => 'psb', - 'application/vnd.3gpp.pic-bw-var' => 'pvb', - 'application/vnd.3gpp2.tcap' => 'tcap', - 'application/vnd.3m.post-it-notes' => 'pwn', - 'application/vnd.accpac.simply.aso' => 'aso', - 'application/vnd.accpac.simply.imp' => 'imp', - 'application/vnd.acucobol' => 'acu', - 'application/vnd.acucorp' => 'atc', - 'application/vnd.adobe.air-application-installer-package+zip' => 'air', - 'application/vnd.adobe.formscentral.fcdt' => 'fcdt', - 'application/vnd.adobe.fxp' => 'fxp', - 'application/vnd.adobe.xdp+xml' => 'xdp', - 'application/vnd.adobe.xfdf' => 'xfdf', - 'application/vnd.ahead.space' => 'ahead', - 'application/vnd.airzip.filesecure.azf' => 'azf', - 'application/vnd.airzip.filesecure.azs' => 'azs', - 'application/vnd.amazon.ebook' => 'azw', - 'application/vnd.americandynamics.acc' => 'acc', - 'application/vnd.amiga.ami' => 'ami', - 'application/vnd.android.package-archive' => 'apk', - 'application/vnd.anser-web-certificate-issue-initiation' => 'cii', - 'application/vnd.anser-web-funds-transfer-initiation' => 'fti', - 'application/vnd.antix.game-component' => 'atx', - 'application/vnd.apple.installer+xml' => 'mpkg', - 'application/vnd.apple.mpegurl' => 'm3u8', - 'application/vnd.aristanetworks.swi' => 'swi', - 'application/vnd.astraea-software.iota' => 'iota', - 'application/vnd.audiograph' => 'aep', - 'application/vnd.blueice.multipass' => 'mpm', - 'application/vnd.bmi' => 'bmi', - 'application/vnd.businessobjects' => 'rep', - 'application/vnd.chemdraw+xml' => 'cdxml', - 'application/vnd.chipnuts.karaoke-mmd' => 'mmd', - 'application/vnd.cinderella' => 'cdy', - 'application/vnd.claymore' => 'cla', - 'application/vnd.cloanto.rp9' => 'rp9', - 'application/vnd.clonk.c4group' => 'c4g', - 'application/vnd.cluetrust.cartomobile-config' => 'c11amc', - 'application/vnd.cluetrust.cartomobile-config-pkg' => 'c11amz', - 'application/vnd.commonspace' => 'csp', - 'application/vnd.contact.cmsg' => 'cdbcmsg', - 'application/vnd.cosmocaller' => 'cmc', - 'application/vnd.crick.clicker' => 'clkx', - 'application/vnd.crick.clicker.keyboard' => 'clkk', - 'application/vnd.crick.clicker.palette' => 'clkp', - 'application/vnd.crick.clicker.template' => 'clkt', - 'application/vnd.crick.clicker.wordbank' => 'clkw', - 'application/vnd.criticaltools.wbs+xml' => 'wbs', - 'application/vnd.ctc-posml' => 'pml', - 'application/vnd.cups-ppd' => 'ppd', - 'application/vnd.curl.car' => 'car', - 'application/vnd.curl.pcurl' => 'pcurl', - 'application/vnd.dart' => 'dart', - 'application/vnd.data-vision.rdz' => 'rdz', - 'application/vnd.dece.data' => 'uvf', - 'application/vnd.dece.ttml+xml' => 'uvt', - 'application/vnd.dece.unspecified' => 'uvx', - 'application/vnd.dece.zip' => 'uvz', - 'application/vnd.denovo.fcselayout-link' => 'fe_launch', - 'application/vnd.dna' => 'dna', - 'application/vnd.dolby.mlp' => 'mlp', - 'application/vnd.dpgraph' => 'dpg', - 'application/vnd.dreamfactory' => 'dfac', - 'application/vnd.ds-keypoint' => 'kpxx', - 'application/vnd.dvb.ait' => 'ait', - 'application/vnd.dvb.service' => 'svc', - 'application/vnd.dynageo' => 'geo', - 'application/vnd.ecowin.chart' => 'mag', - 'application/vnd.enliven' => 'nml', - 'application/vnd.epson.esf' => 'esf', - 'application/vnd.epson.msf' => 'msf', - 'application/vnd.epson.quickanime' => 'qam', - 'application/vnd.epson.salt' => 'slt', - 'application/vnd.epson.ssf' => 'ssf', - 'application/vnd.eszigno3+xml' => 'es3', - 'application/vnd.ezpix-album' => 'ez2', - 'application/vnd.ezpix-package' => 'ez3', - 'application/vnd.fdf' => 'fdf', - 'application/vnd.fdsn.mseed' => 'mseed', - 'application/vnd.fdsn.seed' => 'seed', - 'application/vnd.flographit' => 'gph', - 'application/vnd.fluxtime.clip' => 'ftc', - 'application/vnd.framemaker' => 'fm', - 'application/vnd.frogans.fnc' => 'fnc', - 'application/vnd.frogans.ltf' => 'ltf', - 'application/vnd.fsc.weblaunch' => 'fsc', - 'application/vnd.fujitsu.oasys' => 'oas', - 'application/vnd.fujitsu.oasys2' => 'oa2', - 'application/vnd.fujitsu.oasys3' => 'oa3', - 'application/vnd.fujitsu.oasysgp' => 'fg5', - 'application/vnd.fujitsu.oasysprs' => 'bh2', - 'application/vnd.fujixerox.ddd' => 'ddd', - 'application/vnd.fujixerox.docuworks' => 'xdw', - 'application/vnd.fujixerox.docuworks.binder' => 'xbd', - 'application/vnd.fuzzysheet' => 'fzs', - 'application/vnd.genomatix.tuxedo' => 'txd', - 'application/vnd.geogebra.file' => 'ggb', - 'application/vnd.geogebra.tool' => 'ggt', - 'application/vnd.geometry-explorer' => 'gex', - 'application/vnd.geonext' => 'gxt', - 'application/vnd.geoplan' => 'g2w', - 'application/vnd.geospace' => 'g3w', - 'application/vnd.gmx' => 'gmx', - 'application/vnd.google-earth.kml+xml' => 'kml', - 'application/vnd.google-earth.kmz' => 'kmz', - 'application/vnd.grafeq' => 'gqf', - 'application/vnd.groove-account' => 'gac', - 'application/vnd.groove-help' => 'ghf', - 'application/vnd.groove-identity-message' => 'gim', - 'application/vnd.groove-injector' => 'grv', - 'application/vnd.groove-tool-message' => 'gtm', - 'application/vnd.groove-tool-template' => 'tpl', - 'application/vnd.groove-vcard' => 'vcg', - 'application/vnd.hal+xml' => 'hal', - 'application/vnd.handheld-entertainment+xml' => 'zmm', - 'application/vnd.hbci' => 'hbci', - 'application/vnd.hhe.lesson-player' => 'les', - 'application/vnd.hp-hpgl' => 'hpgl', - 'application/vnd.hp-hpid' => 'hpid', - 'application/vnd.hp-hps' => 'hps', - 'application/vnd.hp-jlyt' => 'jlt', - 'application/vnd.hp-pcl' => 'pcl', - 'application/vnd.hp-pclxl' => 'pclxl', - 'application/vnd.hydrostatix.sof-data' => 'sfd-hdstx', - 'application/vnd.ibm.minipay' => 'mpy', - 'application/vnd.ibm.modcap' => 'afp', - 'application/vnd.ibm.rights-management' => 'irm', - 'application/vnd.ibm.secure-container' => 'sc', - 'application/vnd.iccprofile' => 'icc', - 'application/vnd.igloader' => 'igl', - 'application/vnd.immervision-ivp' => 'ivp', - 'application/vnd.immervision-ivu' => 'ivu', - 'application/vnd.insors.igm' => 'igm', - 'application/vnd.intercon.formnet' => 'xpw', - 'application/vnd.intergeo' => 'i2g', - 'application/vnd.intu.qbo' => 'qbo', - 'application/vnd.intu.qfx' => 'qfx', - 'application/vnd.ipunplugged.rcprofile' => 'rcprofile', - 'application/vnd.irepository.package+xml' => 'irp', - 'application/vnd.is-xpr' => 'xpr', - 'application/vnd.isac.fcs' => 'fcs', - 'application/vnd.jam' => 'jam', - 'application/vnd.jcp.javame.midlet-rms' => 'rms', - 'application/vnd.jisp' => 'jisp', - 'application/vnd.joost.joda-archive' => 'joda', - 'application/vnd.kahootz' => 'ktz', - 'application/vnd.kde.karbon' => 'karbon', - 'application/vnd.kde.kchart' => 'chrt', - 'application/vnd.kde.kformula' => 'kfo', - 'application/vnd.kde.kivio' => 'flw', - 'application/vnd.kde.kontour' => 'kon', - 'application/vnd.kde.kpresenter' => 'kpr', - 'application/vnd.kde.kspread' => 'ksp', - 'application/vnd.kde.kword' => 'kwd', - 'application/vnd.kenameaapp' => 'htke', - 'application/vnd.kidspiration' => 'kia', - 'application/vnd.kinar' => 'kne', - 'application/vnd.koan' => 'skp', - 'application/vnd.kodak-descriptor' => 'sse', - 'application/vnd.las.las+xml' => 'lasxml', - 'application/vnd.llamagraphics.life-balance.desktop' => 'lbd', - 'application/vnd.llamagraphics.life-balance.exchange+xml' => 'lbe', - 'application/vnd.lotus-1-2-3' => '123', - 'application/vnd.lotus-approach' => 'apr', - 'application/vnd.lotus-freelance' => 'pre', - 'application/vnd.lotus-notes' => 'nsf', - 'application/vnd.lotus-organizer' => 'org', - 'application/vnd.lotus-screencam' => 'scm', - 'application/vnd.lotus-wordpro' => 'lwp', - 'application/vnd.macports.portpkg' => 'portpkg', - 'application/vnd.mcd' => 'mcd', - 'application/vnd.medcalcdata' => 'mc1', - 'application/vnd.mediastation.cdkey' => 'cdkey', - 'application/vnd.mfer' => 'mwf', - 'application/vnd.mfmp' => 'mfm', - 'application/vnd.micrografx.flo' => 'flo', - 'application/vnd.micrografx.igx' => 'igx', - 'application/vnd.mif' => 'mif', - 'application/vnd.mobius.daf' => 'daf', - 'application/vnd.mobius.dis' => 'dis', - 'application/vnd.mobius.mbk' => 'mbk', - 'application/vnd.mobius.mqy' => 'mqy', - 'application/vnd.mobius.msl' => 'msl', - 'application/vnd.mobius.plc' => 'plc', - 'application/vnd.mobius.txf' => 'txf', - 'application/vnd.mophun.application' => 'mpn', - 'application/vnd.mophun.certificate' => 'mpc', - 'application/vnd.mozilla.xul+xml' => 'xul', - 'application/vnd.ms-artgalry' => 'cil', - 'application/vnd.ms-cab-compressed' => 'cab', - 'application/vnd.ms-excel' => 'xls', - 'application/vnd.ms-excel.addin.macroenabled.12' => 'xlam', - 'application/vnd.ms-excel.sheet.binary.macroenabled.12' => 'xlsb', - 'application/vnd.ms-excel.sheet.macroenabled.12' => 'xlsm', - 'application/vnd.ms-excel.template.macroenabled.12' => 'xltm', - 'application/vnd.ms-fontobject' => 'eot', - 'application/vnd.ms-htmlhelp' => 'chm', - 'application/vnd.ms-ims' => 'ims', - 'application/vnd.ms-lrm' => 'lrm', - 'application/vnd.ms-officetheme' => 'thmx', - 'application/vnd.ms-pki.seccat' => 'cat', - 'application/vnd.ms-pki.stl' => 'stl', - 'application/vnd.ms-powerpoint' => 'ppt', - 'application/vnd.ms-powerpoint.addin.macroenabled.12' => 'ppam', - 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'pptm', - 'application/vnd.ms-powerpoint.slide.macroenabled.12' => 'sldm', - 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'ppsm', - 'application/vnd.ms-powerpoint.template.macroenabled.12' => 'potm', - 'application/vnd.ms-project' => 'mpp', - 'application/vnd.ms-word.document.macroenabled.12' => 'docm', - 'application/vnd.ms-word.template.macroenabled.12' => 'dotm', - 'application/vnd.ms-works' => 'wps', - 'application/vnd.ms-wpl' => 'wpl', - 'application/vnd.ms-xpsdocument' => 'xps', - 'application/vnd.mseq' => 'mseq', - 'application/vnd.musician' => 'mus', - 'application/vnd.muvee.style' => 'msty', - 'application/vnd.mynfc' => 'taglet', - 'application/vnd.neurolanguage.nlu' => 'nlu', - 'application/vnd.nitf' => 'ntf', - 'application/vnd.noblenet-directory' => 'nnd', - 'application/vnd.noblenet-sealer' => 'nns', - 'application/vnd.noblenet-web' => 'nnw', - 'application/vnd.nokia.n-gage.data' => 'ngdat', - 'application/vnd.nokia.n-gage.symbian.install' => 'n-gage', - 'application/vnd.nokia.radio-preset' => 'rpst', - 'application/vnd.nokia.radio-presets' => 'rpss', - 'application/vnd.novadigm.edm' => 'edm', - 'application/vnd.novadigm.edx' => 'edx', - 'application/vnd.novadigm.ext' => 'ext', - 'application/vnd.oasis.opendocument.chart' => 'odc', - 'application/vnd.oasis.opendocument.chart-template' => 'otc', - 'application/vnd.oasis.opendocument.database' => 'odb', - 'application/vnd.oasis.opendocument.formula' => 'odf', - 'application/vnd.oasis.opendocument.formula-template' => 'odft', - 'application/vnd.oasis.opendocument.graphics' => 'odg', - 'application/vnd.oasis.opendocument.graphics-template' => 'otg', - 'application/vnd.oasis.opendocument.image' => 'odi', - 'application/vnd.oasis.opendocument.image-template' => 'oti', - 'application/vnd.oasis.opendocument.presentation' => 'odp', - 'application/vnd.oasis.opendocument.presentation-template' => 'otp', - 'application/vnd.oasis.opendocument.spreadsheet' => 'ods', - 'application/vnd.oasis.opendocument.spreadsheet-template' => 'ots', - 'application/vnd.oasis.opendocument.text' => 'odt', - 'application/vnd.oasis.opendocument.text-master' => 'odm', - 'application/vnd.oasis.opendocument.text-template' => 'ott', - 'application/vnd.oasis.opendocument.text-web' => 'oth', - 'application/vnd.olpc-sugar' => 'xo', - 'application/vnd.oma.dd2+xml' => 'dd2', - 'application/vnd.openofficeorg.extension' => 'oxt', - 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx', - 'application/vnd.openxmlformats-officedocument.presentationml.slide' => 'sldx', - 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx', - 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'potx', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx', - 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'xltx', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx', - 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'dotx', - 'application/vnd.osgeo.mapguide.package' => 'mgp', - 'application/vnd.osgi.dp' => 'dp', - 'application/vnd.osgi.subsystem' => 'esa', - 'application/vnd.palm' => 'pdb', - 'application/vnd.pawaafile' => 'paw', - 'application/vnd.pg.format' => 'str', - 'application/vnd.pg.osasli' => 'ei6', - 'application/vnd.picsel' => 'efif', - 'application/vnd.pmi.widget' => 'wg', - 'application/vnd.pocketlearn' => 'plf', - 'application/vnd.powerbuilder6' => 'pbd', - 'application/vnd.previewsystems.box' => 'box', - 'application/vnd.proteus.magazine' => 'mgz', - 'application/vnd.publishare-delta-tree' => 'qps', - 'application/vnd.pvi.ptid1' => 'ptid', - 'application/vnd.quark.quarkxpress' => 'qxd', - 'application/vnd.realvnc.bed' => 'bed', - 'application/vnd.recordare.musicxml' => 'mxl', - 'application/vnd.recordare.musicxml+xml' => 'musicxml', - 'application/vnd.rig.cryptonote' => 'cryptonote', - 'application/vnd.rim.cod' => 'cod', - 'application/vnd.rn-realmedia' => 'rm', - 'application/vnd.rn-realmedia-vbr' => 'rmvb', - 'application/vnd.route66.link66+xml' => 'link66', - 'application/vnd.sailingtracker.track' => 'st', - 'application/vnd.seemail' => 'see', - 'application/vnd.sema' => 'sema', - 'application/vnd.semd' => 'semd', - 'application/vnd.semf' => 'semf', - 'application/vnd.shana.informed.formdata' => 'ifm', - 'application/vnd.shana.informed.formtemplate' => 'itp', - 'application/vnd.shana.informed.interchange' => 'iif', - 'application/vnd.shana.informed.package' => 'ipk', - 'application/vnd.simtech-mindmapper' => 'twd', - 'application/vnd.smaf' => 'mmf', - 'application/vnd.smart.teacher' => 'teacher', - 'application/vnd.solent.sdkm+xml' => 'sdkm', - 'application/vnd.spotfire.dxp' => 'dxp', - 'application/vnd.spotfire.sfs' => 'sfs', - 'application/vnd.stardivision.calc' => 'sdc', - 'application/vnd.stardivision.draw' => 'sda', - 'application/vnd.stardivision.impress' => 'sdd', - 'application/vnd.stardivision.math' => 'smf', - 'application/vnd.stardivision.writer' => 'sdw', - 'application/vnd.stardivision.writer-global' => 'sgl', - 'application/vnd.stepmania.package' => 'smzip', - 'application/vnd.stepmania.stepchart' => 'sm', - 'application/vnd.sun.xml.calc' => 'sxc', - 'application/vnd.sun.xml.calc.template' => 'stc', - 'application/vnd.sun.xml.draw' => 'sxd', - 'application/vnd.sun.xml.draw.template' => 'std', - 'application/vnd.sun.xml.impress' => 'sxi', - 'application/vnd.sun.xml.impress.template' => 'sti', - 'application/vnd.sun.xml.math' => 'sxm', - 'application/vnd.sun.xml.writer' => 'sxw', - 'application/vnd.sun.xml.writer.global' => 'sxg', - 'application/vnd.sun.xml.writer.template' => 'stw', - 'application/vnd.sus-calendar' => 'sus', - 'application/vnd.svd' => 'svd', - 'application/vnd.symbian.install' => 'sis', - 'application/vnd.syncml+xml' => 'xsm', - 'application/vnd.syncml.dm+wbxml' => 'bdm', - 'application/vnd.syncml.dm+xml' => 'xdm', - 'application/vnd.tao.intent-module-archive' => 'tao', - 'application/vnd.tcpdump.pcap' => 'pcap', - 'application/vnd.tmobile-livetv' => 'tmo', - 'application/vnd.trid.tpt' => 'tpt', - 'application/vnd.triscape.mxs' => 'mxs', - 'application/vnd.trueapp' => 'tra', - 'application/vnd.ufdl' => 'ufd', - 'application/vnd.uiq.theme' => 'utz', - 'application/vnd.umajin' => 'umj', - 'application/vnd.unity' => 'unityweb', - 'application/vnd.uoml+xml' => 'uoml', - 'application/vnd.vcx' => 'vcx', - 'application/vnd.visio' => 'vsd', - 'application/vnd.visionary' => 'vis', - 'application/vnd.vsf' => 'vsf', - 'application/vnd.wap.wbxml' => 'wbxml', - 'application/vnd.wap.wmlc' => 'wmlc', - 'application/vnd.wap.wmlscriptc' => 'wmlsc', - 'application/vnd.webturbo' => 'wtb', - 'application/vnd.wolfram.player' => 'nbp', - 'application/vnd.wordperfect' => 'wpd', - 'application/vnd.wqd' => 'wqd', - 'application/vnd.wt.stf' => 'stf', - 'application/vnd.xara' => 'xar', - 'application/vnd.xfdl' => 'xfdl', - 'application/vnd.yamaha.hv-dic' => 'hvd', - 'application/vnd.yamaha.hv-script' => 'hvs', - 'application/vnd.yamaha.hv-voice' => 'hvp', - 'application/vnd.yamaha.openscoreformat' => 'osf', - 'application/vnd.yamaha.openscoreformat.osfpvg+xml' => 'osfpvg', - 'application/vnd.yamaha.smaf-audio' => 'saf', - 'application/vnd.yamaha.smaf-phrase' => 'spf', - 'application/vnd.yellowriver-custom-menu' => 'cmp', - 'application/vnd.zul' => 'zir', - 'application/vnd.zzazz.deck+xml' => 'zaz', - 'application/voicexml+xml' => 'vxml', - 'application/widget' => 'wgt', - 'application/winhlp' => 'hlp', - 'application/wsdl+xml' => 'wsdl', - 'application/wspolicy+xml' => 'wspolicy', - 'application/x-7z-compressed' => '7z', - 'application/x-abiword' => 'abw', - 'application/x-ace-compressed' => 'ace', - 'application/x-apple-diskimage' => 'dmg', - 'application/x-authorware-bin' => 'aab', - 'application/x-authorware-map' => 'aam', - 'application/x-authorware-seg' => 'aas', - 'application/x-bcpio' => 'bcpio', - 'application/x-bittorrent' => 'torrent', - 'application/x-blorb' => 'blb', - 'application/x-bzip' => 'bz', - 'application/x-bzip2' => 'bz2', - 'application/x-cbr' => 'cbr', - 'application/x-cdlink' => 'vcd', - 'application/x-cfs-compressed' => 'cfs', - 'application/x-chat' => 'chat', - 'application/x-chess-pgn' => 'pgn', - 'application/x-conference' => 'nsc', - 'application/x-cpio' => 'cpio', - 'application/x-csh' => 'csh', - 'application/x-debian-package' => 'deb', - 'application/x-dgc-compressed' => 'dgc', - 'application/x-director' => 'dir', - 'application/x-doom' => 'wad', - 'application/x-dtbncx+xml' => 'ncx', - 'application/x-dtbook+xml' => 'dtb', - 'application/x-dtbresource+xml' => 'res', - 'application/x-dvi' => 'dvi', - 'application/x-envoy' => 'evy', - 'application/x-eva' => 'eva', - 'application/x-font-bdf' => 'bdf', - 'application/x-font-ghostscript' => 'gsf', - 'application/x-font-linux-psf' => 'psf', - 'application/x-font-otf' => 'otf', - 'application/x-font-pcf' => 'pcf', - 'application/x-font-snf' => 'snf', - 'application/x-font-ttf' => 'ttf', - 'application/x-font-type1' => 'pfa', - 'application/x-font-woff' => 'woff', - 'application/x-freearc' => 'arc', - 'application/x-futuresplash' => 'spl', - 'application/x-gca-compressed' => 'gca', - 'application/x-glulx' => 'ulx', - 'application/x-gnumeric' => 'gnumeric', - 'application/x-gramps-xml' => 'gramps', - 'application/x-gtar' => 'gtar', - 'application/x-hdf' => 'hdf', - 'application/x-install-instructions' => 'install', - 'application/x-iso9660-image' => 'iso', - 'application/x-java-jnlp-file' => 'jnlp', - 'application/x-latex' => 'latex', - 'application/x-lzh-compressed' => 'lzh', - 'application/x-mie' => 'mie', - 'application/x-mobipocket-ebook' => 'prc', - 'application/x-ms-application' => 'application', - 'application/x-ms-shortcut' => 'lnk', - 'application/x-ms-wmd' => 'wmd', - 'application/x-ms-wmz' => 'wmz', - 'application/x-ms-xbap' => 'xbap', - 'application/x-msaccess' => 'mdb', - 'application/x-msbinder' => 'obd', - 'application/x-mscardfile' => 'crd', - 'application/x-msclip' => 'clp', - 'application/x-msdownload' => 'exe', - 'application/x-msmediaview' => 'mvb', - 'application/x-msmetafile' => 'wmf', - 'application/x-msmoney' => 'mny', - 'application/x-mspublisher' => 'pub', - 'application/x-msschedule' => 'scd', - 'application/x-msterminal' => 'trm', - 'application/x-mswrite' => 'wri', - 'application/x-netcdf' => 'nc', - 'application/x-nzb' => 'nzb', - 'application/x-pkcs12' => 'p12', - 'application/x-pkcs7-certificates' => 'p7b', - 'application/x-pkcs7-certreqresp' => 'p7r', - 'application/x-rar-compressed' => 'rar', - 'application/x-rar' => 'rar', - 'application/x-research-info-systems' => 'ris', - 'application/x-sh' => 'sh', - 'application/x-shar' => 'shar', - 'application/x-shockwave-flash' => 'swf', - 'application/x-silverlight-app' => 'xap', - 'application/x-sql' => 'sql', - 'application/x-stuffit' => 'sit', - 'application/x-stuffitx' => 'sitx', - 'application/x-subrip' => 'srt', - 'application/x-sv4cpio' => 'sv4cpio', - 'application/x-sv4crc' => 'sv4crc', - 'application/x-t3vm-image' => 't3', - 'application/x-tads' => 'gam', - 'application/x-tar' => 'tar', - 'application/x-tcl' => 'tcl', - 'application/x-tex' => 'tex', - 'application/x-tex-tfm' => 'tfm', - 'application/x-texinfo' => 'texinfo', - 'application/x-tgif' => 'obj', - 'application/x-ustar' => 'ustar', - 'application/x-wais-source' => 'src', - 'application/x-x509-ca-cert' => 'der', - 'application/x-xfig' => 'fig', - 'application/x-xliff+xml' => 'xlf', - 'application/x-xpinstall' => 'xpi', - 'application/x-xz' => 'xz', - 'application/x-zip-compressed' => 'zip', - 'application/x-zmachine' => 'z1', - 'application/xaml+xml' => 'xaml', - 'application/xcap-diff+xml' => 'xdf', - 'application/xenc+xml' => 'xenc', - 'application/xhtml+xml' => 'xhtml', - 'application/xml' => 'xml', - 'application/xml-dtd' => 'dtd', - 'application/xop+xml' => 'xop', - 'application/xproc+xml' => 'xpl', - 'application/xslt+xml' => 'xslt', - 'application/xspf+xml' => 'xspf', - 'application/xv+xml' => 'mxml', - 'application/yang' => 'yang', - 'application/yin+xml' => 'yin', - 'application/zip' => 'zip', - 'audio/adpcm' => 'adp', - 'audio/basic' => 'au', - 'audio/midi' => 'mid', - 'audio/mp4' => 'm4a', - 'audio/mpeg' => 'mp3', - 'audio/ogg' => 'oga', - 'audio/s3m' => 's3m', - 'audio/silk' => 'sil', - 'audio/vnd.dece.audio' => 'uva', - 'audio/vnd.digital-winds' => 'eol', - 'audio/vnd.dra' => 'dra', - 'audio/vnd.dts' => 'dts', - 'audio/vnd.dts.hd' => 'dtshd', - 'audio/vnd.lucent.voice' => 'lvp', - 'audio/vnd.ms-playready.media.pya' => 'pya', - 'audio/vnd.nuera.ecelp4800' => 'ecelp4800', - 'audio/vnd.nuera.ecelp7470' => 'ecelp7470', - 'audio/vnd.nuera.ecelp9600' => 'ecelp9600', - 'audio/vnd.rip' => 'rip', - 'audio/webm' => 'weba', - 'audio/x-aac' => 'aac', - 'audio/x-aiff' => 'aif', - 'audio/x-caf' => 'caf', - 'audio/x-flac' => 'flac', - 'audio/x-matroska' => 'mka', - 'audio/x-mpegurl' => 'm3u', - 'audio/x-ms-wax' => 'wax', - 'audio/x-ms-wma' => 'wma', - 'audio/x-pn-realaudio' => 'ram', - 'audio/x-pn-realaudio-plugin' => 'rmp', - 'audio/x-wav' => 'wav', - 'audio/xm' => 'xm', - 'chemical/x-cdx' => 'cdx', - 'chemical/x-cif' => 'cif', - 'chemical/x-cmdf' => 'cmdf', - 'chemical/x-cml' => 'cml', - 'chemical/x-csml' => 'csml', - 'chemical/x-xyz' => 'xyz', - 'font/collection' => 'ttc', - 'font/otf' => 'otf', - 'font/ttf' => 'ttf', - 'font/woff' => 'woff', - 'font/woff2' => 'woff2', - 'image/bmp' => 'bmp', - 'image/x-ms-bmp' => 'bmp', - 'image/cgm' => 'cgm', - 'image/g3fax' => 'g3', - 'image/gif' => 'gif', - 'image/ief' => 'ief', - 'image/jpeg' => 'jpeg', - 'image/pjpeg' => 'jpeg', - 'image/ktx' => 'ktx', - 'image/png' => 'png', - 'image/prs.btif' => 'btif', - 'image/sgi' => 'sgi', - 'image/svg+xml' => 'svg', - 'image/tiff' => 'tiff', - 'image/vnd.adobe.photoshop' => 'psd', - 'image/vnd.dece.graphic' => 'uvi', - 'image/vnd.djvu' => 'djvu', - 'image/vnd.dvb.subtitle' => 'sub', - 'image/vnd.dwg' => 'dwg', - 'image/vnd.dxf' => 'dxf', - 'image/vnd.fastbidsheet' => 'fbs', - 'image/vnd.fpx' => 'fpx', - 'image/vnd.fst' => 'fst', - 'image/vnd.fujixerox.edmics-mmr' => 'mmr', - 'image/vnd.fujixerox.edmics-rlc' => 'rlc', - 'image/vnd.ms-modi' => 'mdi', - 'image/vnd.ms-photo' => 'wdp', - 'image/vnd.net-fpx' => 'npx', - 'image/vnd.wap.wbmp' => 'wbmp', - 'image/vnd.xiff' => 'xif', - 'image/webp' => 'webp', - 'image/x-3ds' => '3ds', - 'image/x-cmu-raster' => 'ras', - 'image/x-cmx' => 'cmx', - 'image/x-freehand' => 'fh', - 'image/x-icon' => 'ico', - 'image/x-mrsid-image' => 'sid', - 'image/x-pcx' => 'pcx', - 'image/x-pict' => 'pic', - 'image/x-portable-anymap' => 'pnm', - 'image/x-portable-bitmap' => 'pbm', - 'image/x-portable-graymap' => 'pgm', - 'image/x-portable-pixmap' => 'ppm', - 'image/x-rgb' => 'rgb', - 'image/x-tga' => 'tga', - 'image/x-xbitmap' => 'xbm', - 'image/x-xpixmap' => 'xpm', - 'image/x-xwindowdump' => 'xwd', - 'message/rfc822' => 'eml', - 'model/iges' => 'igs', - 'model/mesh' => 'msh', - 'model/vnd.collada+xml' => 'dae', - 'model/vnd.dwf' => 'dwf', - 'model/vnd.gdl' => 'gdl', - 'model/vnd.gtw' => 'gtw', - 'model/vnd.mts' => 'mts', - 'model/vnd.vtu' => 'vtu', - 'model/vrml' => 'wrl', - 'model/x3d+binary' => 'x3db', - 'model/x3d+vrml' => 'x3dv', - 'model/x3d+xml' => 'x3d', - 'text/cache-manifest' => 'appcache', - 'text/calendar' => 'ics', - 'text/css' => 'css', - 'text/csv' => 'csv', - 'text/html' => 'html', - 'text/n3' => 'n3', - 'text/plain' => 'txt', - 'text/prs.lines.tag' => 'dsc', - 'text/richtext' => 'rtx', - 'text/rtf' => 'rtf', - 'text/sgml' => 'sgml', - 'text/tab-separated-values' => 'tsv', - 'text/troff' => 't', - 'text/turtle' => 'ttl', - 'text/uri-list' => 'uri', - 'text/vcard' => 'vcard', - 'text/vnd.curl' => 'curl', - 'text/vnd.curl.dcurl' => 'dcurl', - 'text/vnd.curl.mcurl' => 'mcurl', - 'text/vnd.curl.scurl' => 'scurl', - 'text/vnd.dvb.subtitle' => 'sub', - 'text/vnd.fly' => 'fly', - 'text/vnd.fmi.flexstor' => 'flx', - 'text/vnd.graphviz' => 'gv', - 'text/vnd.in3d.3dml' => '3dml', - 'text/vnd.in3d.spot' => 'spot', - 'text/vnd.sun.j2me.app-descriptor' => 'jad', - 'text/vnd.wap.wml' => 'wml', - 'text/vnd.wap.wmlscript' => 'wmls', - 'text/vtt' => 'vtt', - 'text/x-asm' => 's', - 'text/x-c' => 'c', - 'text/x-fortran' => 'f', - 'text/x-java-source' => 'java', - 'text/x-nfo' => 'nfo', - 'text/x-opml' => 'opml', - 'text/x-pascal' => 'p', - 'text/x-setext' => 'etx', - 'text/x-sfv' => 'sfv', - 'text/x-uuencode' => 'uu', - 'text/x-vcalendar' => 'vcs', - 'text/x-vcard' => 'vcf', - 'video/3gpp' => '3gp', - 'video/3gpp2' => '3g2', - 'video/h261' => 'h261', - 'video/h263' => 'h263', - 'video/h264' => 'h264', - 'video/jpeg' => 'jpgv', - 'video/jpm' => 'jpm', - 'video/mj2' => 'mj2', - 'video/mp4' => 'mp4', - 'video/mpeg' => 'mpeg', - 'video/ogg' => 'ogv', - 'video/quicktime' => 'qt', - 'video/vnd.dece.hd' => 'uvh', - 'video/vnd.dece.mobile' => 'uvm', - 'video/vnd.dece.pd' => 'uvp', - 'video/vnd.dece.sd' => 'uvs', - 'video/vnd.dece.video' => 'uvv', - 'video/vnd.dvb.file' => 'dvb', - 'video/vnd.fvt' => 'fvt', - 'video/vnd.mpegurl' => 'mxu', - 'video/vnd.ms-playready.media.pyv' => 'pyv', - 'video/vnd.uvvu.mp4' => 'uvu', - 'video/vnd.vivo' => 'viv', - 'video/webm' => 'webm', - 'video/x-f4v' => 'f4v', - 'video/x-fli' => 'fli', - 'video/x-flv' => 'flv', - 'video/x-m4v' => 'm4v', - 'video/x-matroska' => 'mkv', - 'video/x-mng' => 'mng', - 'video/x-ms-asf' => 'asf', - 'video/x-ms-vob' => 'vob', - 'video/x-ms-wm' => 'wm', - 'video/x-ms-wmv' => 'wmv', - 'video/x-ms-wmx' => 'wmx', - 'video/x-ms-wvx' => 'wvx', - 'video/x-msvideo' => 'avi', - 'video/x-sgi-movie' => 'movie', - 'video/x-smv' => 'smv', - 'x-conference/x-cooltalk' => 'ice', - ]; - - /** - * {@inheritdoc} - */ - public function guess($mimeType) - { - if (isset($this->defaultExtensions[$mimeType])) { - return $this->defaultExtensions[$mimeType]; - } - - $lcMimeType = strtolower($mimeType); - - return isset($this->defaultExtensions[$lcMimeType]) ? $this->defaultExtensions[$lcMimeType] : null; - } -} diff --git a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php deleted file mode 100644 index 8d971ed6..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; -use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; - -/** - * A singleton mime type guesser. - * - * By default, all mime type guessers provided by the framework are installed - * (if available on the current OS/PHP setup). - * - * You can register custom guessers by calling the register() method on the - * singleton instance. Custom guessers are always called before any default ones. - * - * $guesser = MimeTypeGuesser::getInstance(); - * $guesser->register(new MyCustomMimeTypeGuesser()); - * - * If you want to change the order of the default guessers, just re-register your - * preferred one as a custom one. The last registered guesser is preferred over - * previously registered ones. - * - * Re-registering a built-in guesser also allows you to configure it: - * - * $guesser = MimeTypeGuesser::getInstance(); - * $guesser->register(new FileinfoMimeTypeGuesser('/path/to/magic/file')); - * - * @author Bernhard Schussek - */ -class MimeTypeGuesser implements MimeTypeGuesserInterface -{ - /** - * The singleton instance. - * - * @var MimeTypeGuesser - */ - private static $instance = null; - - /** - * All registered MimeTypeGuesserInterface instances. - * - * @var array - */ - protected $guessers = []; - - /** - * Returns the singleton instance. - * - * @return self - */ - public static function getInstance() - { - if (null === self::$instance) { - self::$instance = new self(); - } - - return self::$instance; - } - - /** - * Resets the singleton instance. - */ - public static function reset() - { - self::$instance = null; - } - - /** - * Registers all natively provided mime type guessers. - */ - private function __construct() - { - $this->register(new FileBinaryMimeTypeGuesser()); - $this->register(new FileinfoMimeTypeGuesser()); - } - - /** - * Registers a new mime type guesser. - * - * When guessing, this guesser is preferred over previously registered ones. - */ - public function register(MimeTypeGuesserInterface $guesser) - { - array_unshift($this->guessers, $guesser); - } - - /** - * Tries to guess the mime type of the given file. - * - * The file is passed to each registered mime type guesser in reverse order - * of their registration (last registered is queried first). Once a guesser - * returns a value that is not NULL, this method terminates and returns the - * value. - * - * @param string $path The path to the file - * - * @return string The mime type or NULL, if none could be guessed - * - * @throws \LogicException - * @throws FileNotFoundException - * @throws AccessDeniedException - */ - public function guess($path) - { - if (!is_file($path)) { - throw new FileNotFoundException($path); - } - - if (!is_readable($path)) { - throw new AccessDeniedException($path); - } - - foreach ($this->guessers as $guesser) { - if (null !== $mimeType = $guesser->guess($path)) { - return $mimeType; - } - } - - if (2 === \count($this->guessers) && !FileBinaryMimeTypeGuesser::isSupported() && !FileinfoMimeTypeGuesser::isSupported()) { - throw new \LogicException('Unable to guess the mime type as no guessers are available (Did you enable the php_fileinfo extension?).'); - } - - return null; - } -} diff --git a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php b/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php deleted file mode 100644 index e46e78ee..00000000 --- a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php +++ /dev/null @@ -1,35 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\File\MimeType; - -use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; -use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; - -/** - * Guesses the mime type of a file. - * - * @author Bernhard Schussek - */ -interface MimeTypeGuesserInterface -{ - /** - * Guesses the mime type of the file with the given path. - * - * @param string $path The path to the file - * - * @return string|null The mime type or NULL, if none could be guessed - * - * @throws FileNotFoundException If the file does not exist - * @throws AccessDeniedException If the file could not be read - */ - public function guess($path); -} diff --git a/vendor/symfony/http-foundation/File/Stream.php b/vendor/symfony/http-foundation/File/Stream.php index 69ae74c1..cef3e039 100644 --- a/vendor/symfony/http-foundation/File/Stream.php +++ b/vendor/symfony/http-foundation/File/Stream.php @@ -20,7 +20,10 @@ class Stream extends File { /** * {@inheritdoc} + * + * @return int|false */ + #[\ReturnTypeWillChange] public function getSize() { return false; diff --git a/vendor/symfony/http-foundation/File/UploadedFile.php b/vendor/symfony/http-foundation/File/UploadedFile.php index 99132d14..1161556c 100644 --- a/vendor/symfony/http-foundation/File/UploadedFile.php +++ b/vendor/symfony/http-foundation/File/UploadedFile.php @@ -11,9 +11,16 @@ namespace Symfony\Component\HttpFoundation\File; +use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException; +use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; -use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser; +use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException; +use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException; +use Symfony\Component\HttpFoundation\File\Exception\NoFileException; +use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException; +use Symfony\Component\HttpFoundation\File\Exception\PartialFileException; +use Symfony\Component\Mime\MimeTypes; /** * A file uploaded through a form. @@ -27,7 +34,6 @@ class UploadedFile extends File private $test; private $originalName; private $mimeType; - private $size; private $error; /** @@ -47,7 +53,6 @@ class UploadedFile extends File * @param string $path The full temporary path to the file * @param string $originalName The original file name of the uploaded file * @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream - * @param int|null $size The file size provided by the uploader * @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK * @param bool $test Whether the test mode is active * Local files are used in test mode hence the code should not enforce HTTP uploads @@ -55,13 +60,12 @@ class UploadedFile extends File * @throws FileException If file_uploads is disabled * @throws FileNotFoundException If the file does not exist */ - public function __construct($path, $originalName, $mimeType = null, $size = null, $error = null, $test = false) + public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, bool $test = false) { $this->originalName = $this->getName($originalName); $this->mimeType = $mimeType ?: 'application/octet-stream'; - $this->size = $size; $this->error = $error ?: \UPLOAD_ERR_OK; - $this->test = (bool) $test; + $this->test = $test; parent::__construct($path, \UPLOAD_ERR_OK === $this->error); } @@ -70,9 +74,9 @@ public function __construct($path, $originalName, $mimeType = null, $size = null * Returns the original file name. * * It is extracted from the request from which the file has been uploaded. - * Then it should not be considered as a safe value. + * This should not be considered as a safe value to use for a file name on your servers. * - * @return string The original name + * @return string */ public function getClientOriginalName() { @@ -83,9 +87,9 @@ public function getClientOriginalName() * Returns the original file extension. * * It is extracted from the original file name that was uploaded. - * Then it should not be considered as a safe value. + * This should not be considered as a safe value to use for a file name on your servers. * - * @return string The extension + * @return string */ public function getClientOriginalExtension() { @@ -101,7 +105,7 @@ public function getClientOriginalExtension() * For a trusted mime type, use getMimeType() instead (which guesses the mime * type based on the file content). * - * @return string The mime type + * @return string * * @see getMimeType() */ @@ -122,30 +126,18 @@ public function getClientMimeType() * For a trusted extension, use guessExtension() instead (which guesses * the extension based on the guessed mime type for the file). * - * @return string|null The guessed extension or null if it cannot be guessed + * @return string|null * * @see guessExtension() * @see getClientMimeType() */ public function guessClientExtension() { - $type = $this->getClientMimeType(); - $guesser = ExtensionGuesser::getInstance(); + if (!class_exists(MimeTypes::class)) { + throw new \LogicException('You cannot guess the extension as the Mime component is not installed. Try running "composer require symfony/mime".'); + } - return $guesser->guess($type); - } - - /** - * Returns the file size. - * - * It is extracted from the request from which the file has been uploaded. - * Then it should not be considered as a safe value. - * - * @return int|null The file size - */ - public function getClientSize() - { - return $this->size; + return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null; } /** @@ -154,7 +146,7 @@ public function getClientSize() * If the upload was successful, the constant UPLOAD_ERR_OK is returned. * Otherwise one of the other UPLOAD_ERR_XXX constants is returned. * - * @return int The upload error + * @return int */ public function getError() { @@ -162,9 +154,9 @@ public function getError() } /** - * Returns whether the file was uploaded successfully. + * Returns whether the file has been uploaded with HTTP and no error occurred. * - * @return bool True if the file has been uploaded with HTTP and no error occurred + * @return bool */ public function isValid() { @@ -176,14 +168,11 @@ public function isValid() /** * Moves the file to a new location. * - * @param string $directory The destination folder - * @param string $name The new file name - * - * @return File A File object representing the new file + * @return File * * @throws FileException if, for any reason, the file could not have been moved */ - public function move($directory, $name = null) + public function move(string $directory, string $name = null) { if ($this->isValid()) { if ($this->test) { @@ -193,8 +182,11 @@ public function move($directory, $name = null) $target = $this->getTargetFile($directory, $name); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); - $moved = move_uploaded_file($this->getPathname(), $target); - restore_error_handler(); + try { + $moved = move_uploaded_file($this->getPathname(), $target); + } finally { + restore_error_handler(); + } if (!$moved) { throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s).', $this->getPathname(), $target, strip_tags($error))); } @@ -204,18 +196,35 @@ public function move($directory, $name = null) return $target; } + switch ($this->error) { + case \UPLOAD_ERR_INI_SIZE: + throw new IniSizeFileException($this->getErrorMessage()); + case \UPLOAD_ERR_FORM_SIZE: + throw new FormSizeFileException($this->getErrorMessage()); + case \UPLOAD_ERR_PARTIAL: + throw new PartialFileException($this->getErrorMessage()); + case \UPLOAD_ERR_NO_FILE: + throw new NoFileException($this->getErrorMessage()); + case \UPLOAD_ERR_CANT_WRITE: + throw new CannotWriteFileException($this->getErrorMessage()); + case \UPLOAD_ERR_NO_TMP_DIR: + throw new NoTmpDirFileException($this->getErrorMessage()); + case \UPLOAD_ERR_EXTENSION: + throw new ExtensionFileException($this->getErrorMessage()); + } + throw new FileException($this->getErrorMessage()); } /** * Returns the maximum size of an uploaded file as configured in php.ini. * - * @return int The maximum size of an uploaded file in bytes + * @return int|float The maximum size of an uploaded file in bytes (returns float if size > PHP_INT_MAX) */ public static function getMaxFilesize() { - $sizePostMax = self::parseFilesize(ini_get('post_max_size')); - $sizeUploadMax = self::parseFilesize(ini_get('upload_max_filesize')); + $sizePostMax = self::parseFilesize(\ini_get('post_max_size')); + $sizeUploadMax = self::parseFilesize(\ini_get('upload_max_filesize')); return min($sizePostMax ?: \PHP_INT_MAX, $sizeUploadMax ?: \PHP_INT_MAX); } @@ -223,9 +232,9 @@ public static function getMaxFilesize() /** * Returns the given size from an ini value in bytes. * - * @return int The given size in bytes + * @return int|float Returns float if size > PHP_INT_MAX */ - private static function parseFilesize($size) + private static function parseFilesize(string $size) { if ('' === $size) { return 0; @@ -234,9 +243,9 @@ private static function parseFilesize($size) $size = strtolower($size); $max = ltrim($size, '+'); - if (0 === strpos($max, '0x')) { + if (str_starts_with($max, '0x')) { $max = \intval($max, 16); - } elseif (0 === strpos($max, '0')) { + } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; @@ -244,11 +253,11 @@ private static function parseFilesize($size) switch (substr($size, -1)) { case 't': $max *= 1024; - // no break + // no break case 'g': $max *= 1024; - // no break + // no break case 'm': $max *= 1024; - // no break + // no break case 'k': $max *= 1024; } @@ -258,7 +267,7 @@ private static function parseFilesize($size) /** * Returns an informative upload error message. * - * @return string The error message regarding the specified error code + * @return string */ public function getErrorMessage() { @@ -274,7 +283,7 @@ public function getErrorMessage() $errorCode = $this->error; $maxFilesize = \UPLOAD_ERR_INI_SIZE === $errorCode ? self::getMaxFilesize() / 1024 : 0; - $message = isset($errors[$errorCode]) ? $errors[$errorCode] : 'The file "%s" was not uploaded due to an unknown error.'; + $message = $errors[$errorCode] ?? 'The file "%s" was not uploaded due to an unknown error.'; return sprintf($message, $this->getClientOriginalName(), $maxFilesize); } diff --git a/vendor/symfony/http-foundation/FileBag.php b/vendor/symfony/http-foundation/FileBag.php index e2acca4e..ff5ab777 100644 --- a/vendor/symfony/http-foundation/FileBag.php +++ b/vendor/symfony/http-foundation/FileBag.php @@ -21,10 +21,10 @@ */ class FileBag extends ParameterBag { - private static $fileKeys = ['error', 'name', 'size', 'tmp_name', 'type']; + private const FILE_KEYS = ['error', 'name', 'size', 'tmp_name', 'type']; /** - * @param array $parameters An array of HTTP files + * @param array|UploadedFile[] $parameters An array of HTTP files */ public function __construct(array $parameters = []) { @@ -43,7 +43,7 @@ public function replace(array $files = []) /** * {@inheritdoc} */ - public function set($key, $value) + public function set(string $key, $value) { if (!\is_array($value) && !$value instanceof UploadedFile) { throw new \InvalidArgumentException('An uploaded file must be an array or an instance of UploadedFile.'); @@ -67,7 +67,7 @@ public function add(array $files = []) * * @param array|UploadedFile $file A (multi-dimensional) array of uploaded file information * - * @return UploadedFile[]|UploadedFile|null A (multi-dimensional) array of UploadedFile instances + * @return UploadedFile[]|UploadedFile|null */ protected function convertFileInformation($file) { @@ -75,22 +75,20 @@ protected function convertFileInformation($file) return $file; } - if (\is_array($file)) { - $file = $this->fixPhpFilesArray($file); - $keys = array_keys($file); - sort($keys); - - if ($keys == self::$fileKeys) { - if (\UPLOAD_ERR_NO_FILE == $file['error']) { - $file = null; - } else { - $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['size'], $file['error']); - } + $file = $this->fixPhpFilesArray($file); + $keys = array_keys($file); + sort($keys); + + if (self::FILE_KEYS == $keys) { + if (\UPLOAD_ERR_NO_FILE == $file['error']) { + $file = null; } else { - $file = array_map([$this, 'convertFileInformation'], $file); - if (array_keys($keys) === $keys) { - $file = array_filter($file); - } + $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error'], false); + } + } else { + $file = array_map(function ($v) { return $v instanceof UploadedFile || \is_array($v) ? $this->convertFileInformation($v) : $v; }, $file); + if (array_keys($keys) === $keys) { + $file = array_filter($file); } } @@ -109,21 +107,21 @@ protected function convertFileInformation($file) * It's safe to pass an already converted array, in which case this method * just returns the original array unmodified. * - * @param array $data - * * @return array */ - protected function fixPhpFilesArray($data) + protected function fixPhpFilesArray(array $data) { + // Remove extra key added by PHP 8.1. + unset($data['full_path']); $keys = array_keys($data); sort($keys); - if (self::$fileKeys != $keys || !isset($data['name']) || !\is_array($data['name'])) { + if (self::FILE_KEYS != $keys || !isset($data['name']) || !\is_array($data['name'])) { return $data; } $files = $data; - foreach (self::$fileKeys as $k) { + foreach (self::FILE_KEYS as $k) { unset($files[$k]); } diff --git a/vendor/symfony/http-foundation/HeaderBag.php b/vendor/symfony/http-foundation/HeaderBag.php index 301ec9cf..4683a684 100644 --- a/vendor/symfony/http-foundation/HeaderBag.php +++ b/vendor/symfony/http-foundation/HeaderBag.php @@ -15,15 +15,20 @@ * HeaderBag is a container for HTTP headers. * * @author Fabien Potencier + * + * @implements \IteratorAggregate> */ class HeaderBag implements \IteratorAggregate, \Countable { - protected $headers = []; - protected $cacheControl = []; + protected const UPPER = '_ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + protected const LOWER = '-abcdefghijklmnopqrstuvwxyz'; /** - * @param array $headers An array of HTTP headers + * @var array> */ + protected $headers = []; + protected $cacheControl = []; + public function __construct(array $headers = []) { foreach ($headers as $key => $values) { @@ -34,7 +39,7 @@ public function __construct(array $headers = []) /** * Returns the headers as a string. * - * @return string The headers + * @return string */ public function __toString() { @@ -46,7 +51,7 @@ public function __toString() $max = max(array_map('strlen', array_keys($headers))) + 1; $content = ''; foreach ($headers as $name => $values) { - $name = implode('-', array_map('ucfirst', explode('-', $name))); + $name = ucwords($name, '-'); foreach ($values as $value) { $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value); } @@ -58,17 +63,23 @@ public function __toString() /** * Returns the headers. * - * @return array An array of headers + * @param string|null $key The name of the headers to return or null to get them all + * + * @return array>|array */ - public function all() + public function all(string $key = null) { + if (null !== $key) { + return $this->headers[strtr($key, self::UPPER, self::LOWER)] ?? []; + } + return $this->headers; } /** * Returns the parameter keys. * - * @return array An array of parameter keys + * @return string[] */ public function keys() { @@ -77,8 +88,6 @@ public function keys() /** * Replaces the current HTTP headers by a new set. - * - * @param array $headers An array of HTTP headers */ public function replace(array $headers = []) { @@ -88,8 +97,6 @@ public function replace(array $headers = []) /** * Adds new headers the current HTTP headers set. - * - * @param array $headers An array of HTTP headers */ public function add(array $headers) { @@ -99,52 +106,34 @@ public function add(array $headers) } /** - * Returns a header value by name. - * - * @param string $key The header name - * @param string|null $default The default value - * @param bool $first Whether to return the first value or all header values + * Returns the first header by name or the default one. * - * @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise + * @return string|null */ - public function get($key, $default = null, $first = true) + public function get(string $key, string $default = null) { - $key = str_replace('_', '-', strtolower($key)); - $headers = $this->all(); + $headers = $this->all($key); - if (!\array_key_exists($key, $headers)) { - if (null === $default) { - return $first ? null : []; - } - - return $first ? $default : [$default]; + if (!$headers) { + return $default; } - if ($first) { - if (!$headers[$key]) { - return $default; - } - - if (null === $headers[$key][0]) { - return null; - } - - return (string) $headers[$key][0]; + if (null === $headers[0]) { + return null; } - return $headers[$key]; + return (string) $headers[0]; } /** * Sets a header by name. * - * @param string $key The key - * @param string|string[] $values The value or an array of values - * @param bool $replace Whether to replace the actual value or not (true by default) + * @param string|string[]|null $values The value or an array of values + * @param bool $replace Whether to replace the actual value or not (true by default) */ - public function set($key, $values, $replace = true) + public function set(string $key, $values, bool $replace = true) { - $key = str_replace('_', '-', strtolower($key)); + $key = strtr($key, self::UPPER, self::LOWER); if (\is_array($values)) { $values = array_values($values); @@ -170,36 +159,29 @@ public function set($key, $values, $replace = true) /** * Returns true if the HTTP header is defined. * - * @param string $key The HTTP header - * - * @return bool true if the parameter exists, false otherwise + * @return bool */ - public function has($key) + public function has(string $key) { - return \array_key_exists(str_replace('_', '-', strtolower($key)), $this->all()); + return \array_key_exists(strtr($key, self::UPPER, self::LOWER), $this->all()); } /** * Returns true if the given HTTP header contains the given value. * - * @param string $key The HTTP header name - * @param string $value The HTTP value - * - * @return bool true if the value is contained in the header, false otherwise + * @return bool */ - public function contains($key, $value) + public function contains(string $key, string $value) { - return \in_array($value, $this->get($key, null, false)); + return \in_array($value, $this->all($key)); } /** * Removes a header. - * - * @param string $key The HTTP header name */ - public function remove($key) + public function remove(string $key) { - $key = str_replace('_', '-', strtolower($key)); + $key = strtr($key, self::UPPER, self::LOWER); unset($this->headers[$key]); @@ -211,14 +193,11 @@ public function remove($key) /** * Returns the HTTP header value converted to a date. * - * @param string $key The parameter key - * @param \DateTime $default The default value - * - * @return \DateTime|null The parsed DateTime or the default value if the header does not exist + * @return \DateTimeInterface|null * * @throws \RuntimeException When the HTTP header is not parseable */ - public function getDate($key, \DateTime $default = null) + public function getDate(string $key, \DateTime $default = null) { if (null === $value = $this->get($key)) { return $default; @@ -234,10 +213,9 @@ public function getDate($key, \DateTime $default = null) /** * Adds a custom Cache-Control directive. * - * @param string $key The Cache-Control directive name - * @param mixed $value The Cache-Control directive value + * @param bool|string $value The Cache-Control directive value */ - public function addCacheControlDirective($key, $value = true) + public function addCacheControlDirective(string $key, $value = true) { $this->cacheControl[$key] = $value; @@ -247,11 +225,9 @@ public function addCacheControlDirective($key, $value = true) /** * Returns true if the Cache-Control directive is defined. * - * @param string $key The Cache-Control directive - * - * @return bool true if the directive exists, false otherwise + * @return bool */ - public function hasCacheControlDirective($key) + public function hasCacheControlDirective(string $key) { return \array_key_exists($key, $this->cacheControl); } @@ -259,21 +235,17 @@ public function hasCacheControlDirective($key) /** * Returns a Cache-Control directive value by name. * - * @param string $key The directive name - * - * @return mixed|null The directive value if defined, null otherwise + * @return bool|string|null */ - public function getCacheControlDirective($key) + public function getCacheControlDirective(string $key) { - return \array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null; + return $this->cacheControl[$key] ?? null; } /** * Removes a Cache-Control directive. - * - * @param string $key The Cache-Control directive */ - public function removeCacheControlDirective($key) + public function removeCacheControlDirective(string $key) { unset($this->cacheControl[$key]); @@ -283,8 +255,9 @@ public function removeCacheControlDirective($key) /** * Returns an iterator for headers. * - * @return \ArrayIterator An \ArrayIterator instance + * @return \ArrayIterator> */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->headers); @@ -293,8 +266,9 @@ public function getIterator() /** * Returns the number of headers. * - * @return int The number of headers + * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->headers); @@ -302,38 +276,20 @@ public function count() protected function getCacheControlHeader() { - $parts = []; ksort($this->cacheControl); - foreach ($this->cacheControl as $key => $value) { - if (true === $value) { - $parts[] = $key; - } else { - if (preg_match('#[^a-zA-Z0-9._-]#', $value)) { - $value = '"'.$value.'"'; - } - - $parts[] = "$key=$value"; - } - } - return implode(', ', $parts); + return HeaderUtils::toString($this->cacheControl, ','); } /** * Parses a Cache-Control HTTP header. * - * @param string $header The value of the Cache-Control HTTP header - * - * @return array An array representing the attribute values + * @return array */ - protected function parseCacheControl($header) + protected function parseCacheControl(string $header) { - $cacheControl = []; - preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, \PREG_SET_ORDER); - foreach ($matches as $match) { - $cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true); - } + $parts = HeaderUtils::split($header, ',='); - return $cacheControl; + return HeaderUtils::combine($parts); } } diff --git a/vendor/symfony/http-foundation/HeaderUtils.php b/vendor/symfony/http-foundation/HeaderUtils.php new file mode 100644 index 00000000..46b1e6ae --- /dev/null +++ b/vendor/symfony/http-foundation/HeaderUtils.php @@ -0,0 +1,293 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation; + +/** + * HTTP header utility functions. + * + * @author Christian Schmidt + */ +class HeaderUtils +{ + public const DISPOSITION_ATTACHMENT = 'attachment'; + public const DISPOSITION_INLINE = 'inline'; + + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + + /** + * Splits an HTTP header by one or more separators. + * + * Example: + * + * HeaderUtils::split("da, en-gb;q=0.8", ",;") + * // => ['da'], ['en-gb', 'q=0.8']] + * + * @param string $separators List of characters to split on, ordered by + * precedence, e.g. ",", ";=", or ",;=" + * + * @return array Nested array with as many levels as there are characters in + * $separators + */ + public static function split(string $header, string $separators): array + { + $quotedSeparators = preg_quote($separators, '/'); + + preg_match_all(' + / + (?!\s) + (?: + # quoted-string + "(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$) + | + # token + [^"'.$quotedSeparators.']+ + )+ + (?['.$quotedSeparators.']) + \s* + /x', trim($header), $matches, \PREG_SET_ORDER); + + return self::groupParts($matches, $separators); + } + + /** + * Combines an array of arrays into one associative array. + * + * Each of the nested arrays should have one or two elements. The first + * value will be used as the keys in the associative array, and the second + * will be used as the values, or true if the nested array only contains one + * element. Array keys are lowercased. + * + * Example: + * + * HeaderUtils::combine([["foo", "abc"], ["bar"]]) + * // => ["foo" => "abc", "bar" => true] + */ + public static function combine(array $parts): array + { + $assoc = []; + foreach ($parts as $part) { + $name = strtolower($part[0]); + $value = $part[1] ?? true; + $assoc[$name] = $value; + } + + return $assoc; + } + + /** + * Joins an associative array into a string for use in an HTTP header. + * + * The key and value of each entry are joined with "=", and all entries + * are joined with the specified separator and an additional space (for + * readability). Values are quoted if necessary. + * + * Example: + * + * HeaderUtils::toString(["foo" => "abc", "bar" => true, "baz" => "a b c"], ",") + * // => 'foo=abc, bar, baz="a b c"' + */ + public static function toString(array $assoc, string $separator): string + { + $parts = []; + foreach ($assoc as $name => $value) { + if (true === $value) { + $parts[] = $name; + } else { + $parts[] = $name.'='.self::quote($value); + } + } + + return implode($separator.' ', $parts); + } + + /** + * Encodes a string as a quoted string, if necessary. + * + * If a string contains characters not allowed by the "token" construct in + * the HTTP specification, it is backslash-escaped and enclosed in quotes + * to match the "quoted-string" construct. + */ + public static function quote(string $s): string + { + if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) { + return $s; + } + + return '"'.addcslashes($s, '"\\"').'"'; + } + + /** + * Decodes a quoted string. + * + * If passed an unquoted string that matches the "token" construct (as + * defined in the HTTP specification), it is passed through verbatim. + */ + public static function unquote(string $s): string + { + return preg_replace('/\\\\(.)|"/', '$1', $s); + } + + /** + * Generates an HTTP Content-Disposition field-value. + * + * @param string $disposition One of "inline" or "attachment" + * @param string $filename A unicode string + * @param string $filenameFallback A string containing only ASCII characters that + * is semantically equivalent to $filename. If the filename is already ASCII, + * it can be omitted, or just copied from $filename + * + * @throws \InvalidArgumentException + * + * @see RFC 6266 + */ + public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string + { + if (!\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE])) { + throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); + } + + if ('' === $filenameFallback) { + $filenameFallback = $filename; + } + + // filenameFallback is not ASCII. + if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) { + throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.'); + } + + // percent characters aren't safe in fallback. + if (str_contains($filenameFallback, '%')) { + throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.'); + } + + // path separators aren't allowed in either. + if (str_contains($filename, '/') || str_contains($filename, '\\') || str_contains($filenameFallback, '/') || str_contains($filenameFallback, '\\')) { + throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.'); + } + + $params = ['filename' => $filenameFallback]; + if ($filename !== $filenameFallback) { + $params['filename*'] = "utf-8''".rawurlencode($filename); + } + + return $disposition.'; '.self::toString($params, ';'); + } + + /** + * Like parse_str(), but preserves dots in variable names. + */ + public static function parseQuery(string $query, bool $ignoreBrackets = false, string $separator = '&'): array + { + $q = []; + + foreach (explode($separator, $query) as $v) { + if (false !== $i = strpos($v, "\0")) { + $v = substr($v, 0, $i); + } + + if (false === $i = strpos($v, '=')) { + $k = urldecode($v); + $v = ''; + } else { + $k = urldecode(substr($v, 0, $i)); + $v = substr($v, $i); + } + + if (false !== $i = strpos($k, "\0")) { + $k = substr($k, 0, $i); + } + + $k = ltrim($k, ' '); + + if ($ignoreBrackets) { + $q[$k][] = urldecode(substr($v, 1)); + + continue; + } + + if (false === $i = strpos($k, '[')) { + $q[] = bin2hex($k).$v; + } else { + $q[] = bin2hex(substr($k, 0, $i)).rawurlencode(substr($k, $i)).$v; + } + } + + if ($ignoreBrackets) { + return $q; + } + + parse_str(implode('&', $q), $q); + + $query = []; + + foreach ($q as $k => $v) { + if (false !== $i = strpos($k, '_')) { + $query[substr_replace($k, hex2bin(substr($k, 0, $i)).'[', 0, 1 + $i)] = $v; + } else { + $query[hex2bin($k)] = $v; + } + } + + return $query; + } + + private static function groupParts(array $matches, string $separators, bool $first = true): array + { + $separator = $separators[0]; + $partSeparators = substr($separators, 1); + + $i = 0; + $partMatches = []; + $previousMatchWasSeparator = false; + foreach ($matches as $match) { + if (!$first && $previousMatchWasSeparator && isset($match['separator']) && $match['separator'] === $separator) { + $previousMatchWasSeparator = true; + $partMatches[$i][] = $match; + } elseif (isset($match['separator']) && $match['separator'] === $separator) { + $previousMatchWasSeparator = true; + ++$i; + } else { + $previousMatchWasSeparator = false; + $partMatches[$i][] = $match; + } + } + + $parts = []; + if ($partSeparators) { + foreach ($partMatches as $matches) { + $parts[] = self::groupParts($matches, $partSeparators, false); + } + } else { + foreach ($partMatches as $matches) { + $parts[] = self::unquote($matches[0][0]); + } + + if (!$first && 2 < \count($parts)) { + $parts = [ + $parts[0], + implode($separator, \array_slice($parts, 1)), + ]; + } + } + + return $parts; + } +} diff --git a/vendor/symfony/http-foundation/InputBag.php b/vendor/symfony/http-foundation/InputBag.php new file mode 100644 index 00000000..a9d3cd82 --- /dev/null +++ b/vendor/symfony/http-foundation/InputBag.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation; + +use Symfony\Component\HttpFoundation\Exception\BadRequestException; + +/** + * InputBag is a container for user input values such as $_GET, $_POST, $_REQUEST, and $_COOKIE. + * + * @author Saif Eddin Gmati + */ +final class InputBag extends ParameterBag +{ + /** + * Returns a scalar input value by name. + * + * @param string|int|float|bool|null $default The default value if the input key does not exist + * + * @return string|int|float|bool|null + */ + public function get(string $key, $default = null) + { + if (null !== $default && !\is_scalar($default) && !(\is_object($default) && method_exists($default, '__toString'))) { + trigger_deprecation('symfony/http-foundation', '5.1', 'Passing a non-scalar value as 2nd argument to "%s()" is deprecated, pass a scalar or null instead.', __METHOD__); + } + + $value = parent::get($key, $this); + + if (null !== $value && $this !== $value && !\is_scalar($value) && !(\is_object($value) && method_exists($value, '__toString'))) { + trigger_deprecation('symfony/http-foundation', '5.1', 'Retrieving a non-scalar value from "%s()" is deprecated, and will throw a "%s" exception in Symfony 6.0, use "%s::all($key)" instead.', __METHOD__, BadRequestException::class, __CLASS__); + } + + return $this === $value ? $default : $value; + } + + /** + * {@inheritdoc} + */ + public function all(string $key = null): array + { + return parent::all($key); + } + + /** + * Replaces the current input values by a new set. + */ + public function replace(array $inputs = []) + { + $this->parameters = []; + $this->add($inputs); + } + + /** + * Adds input values. + */ + public function add(array $inputs = []) + { + foreach ($inputs as $input => $value) { + $this->set($input, $value); + } + } + + /** + * Sets an input by name. + * + * @param string|int|float|bool|array|null $value + */ + public function set(string $key, $value) + { + if (null !== $value && !\is_scalar($value) && !\is_array($value) && !method_exists($value, '__toString')) { + trigger_deprecation('symfony/http-foundation', '5.1', 'Passing "%s" as a 2nd Argument to "%s()" is deprecated, pass a scalar, array, or null instead.', get_debug_type($value), __METHOD__); + } + + $this->parameters[$key] = $value; + } + + /** + * {@inheritdoc} + */ + public function filter(string $key, $default = null, int $filter = \FILTER_DEFAULT, $options = []) + { + $value = $this->has($key) ? $this->all()[$key] : $default; + + // Always turn $options into an array - this allows filter_var option shortcuts. + if (!\is_array($options) && $options) { + $options = ['flags' => $options]; + } + + if (\is_array($value) && !(($options['flags'] ?? 0) & (\FILTER_REQUIRE_ARRAY | \FILTER_FORCE_ARRAY))) { + trigger_deprecation('symfony/http-foundation', '5.1', 'Filtering an array value with "%s()" without passing the FILTER_REQUIRE_ARRAY or FILTER_FORCE_ARRAY flag is deprecated', __METHOD__); + + if (!isset($options['flags'])) { + $options['flags'] = \FILTER_REQUIRE_ARRAY; + } + } + + if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) { + trigger_deprecation('symfony/http-foundation', '5.2', 'Not passing a Closure together with FILTER_CALLBACK to "%s()" is deprecated. Wrap your filter in a closure instead.', __METHOD__); + // throw new \InvalidArgumentException(sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); + } + + return filter_var($value, $filter, $options); + } +} diff --git a/vendor/symfony/http-foundation/IpUtils.php b/vendor/symfony/http-foundation/IpUtils.php index a83d3249..49d9a9d7 100644 --- a/vendor/symfony/http-foundation/IpUtils.php +++ b/vendor/symfony/http-foundation/IpUtils.php @@ -30,13 +30,18 @@ private function __construct() /** * Checks if an IPv4 or IPv6 address is contained in the list of given IPs or subnets. * - * @param string $requestIp IP to check - * @param string|array $ips List of IPs or subnets (can be a string if only a single one) + * @param string|array $ips List of IPs or subnets (can be a string if only a single one) * - * @return bool Whether the IP is valid + * @return bool */ - public static function checkIp($requestIp, $ips) + public static function checkIp(?string $requestIp, $ips) { + if (null === $requestIp) { + trigger_deprecation('symfony/http-foundation', '5.4', 'Passing null as $requestIp to "%s()" is deprecated, pass an empty string instead.', __METHOD__); + + return false; + } + if (!\is_array($ips)) { $ips = [$ips]; } @@ -56,14 +61,19 @@ public static function checkIp($requestIp, $ips) * Compares two IPv4 addresses. * In case a subnet is given, it checks if it contains the request IP. * - * @param string $requestIp IPv4 address to check - * @param string $ip IPv4 address or subnet in CIDR notation + * @param string $ip IPv4 address or subnet in CIDR notation * * @return bool Whether the request IP matches the IP, or whether the request IP is within the CIDR subnet */ - public static function checkIp4($requestIp, $ip) + public static function checkIp4(?string $requestIp, string $ip) { - $cacheKey = $requestIp.'-'.$ip; + if (null === $requestIp) { + trigger_deprecation('symfony/http-foundation', '5.4', 'Passing null as $requestIp to "%s()" is deprecated, pass an empty string instead.', __METHOD__); + + return false; + } + + $cacheKey = $requestIp.'-'.$ip.'-v4'; if (isset(self::$checkedIps[$cacheKey])) { return self::$checkedIps[$cacheKey]; } @@ -72,11 +82,11 @@ public static function checkIp4($requestIp, $ip) return self::$checkedIps[$cacheKey] = false; } - if (false !== strpos($ip, '/')) { - list($address, $netmask) = explode('/', $ip, 2); + if (str_contains($ip, '/')) { + [$address, $netmask] = explode('/', $ip, 2); if ('0' === $netmask) { - return self::$checkedIps[$cacheKey] = filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4); + return self::$checkedIps[$cacheKey] = false !== filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV4); } if ($netmask < 0 || $netmask > 32) { @@ -102,16 +112,21 @@ public static function checkIp4($requestIp, $ip) * * @see https://github.com/dsp/v6tools * - * @param string $requestIp IPv6 address to check - * @param string $ip IPv6 address or subnet in CIDR notation + * @param string $ip IPv6 address or subnet in CIDR notation * - * @return bool Whether the IP is valid + * @return bool * * @throws \RuntimeException When IPV6 support is not enabled */ - public static function checkIp6($requestIp, $ip) + public static function checkIp6(?string $requestIp, string $ip) { - $cacheKey = $requestIp.'-'.$ip; + if (null === $requestIp) { + trigger_deprecation('symfony/http-foundation', '5.4', 'Passing null as $requestIp to "%s()" is deprecated, pass an empty string instead.', __METHOD__); + + return false; + } + + $cacheKey = $requestIp.'-'.$ip.'-v6'; if (isset(self::$checkedIps[$cacheKey])) { return self::$checkedIps[$cacheKey]; } @@ -120,8 +135,17 @@ public static function checkIp6($requestIp, $ip) throw new \RuntimeException('Unable to check Ipv6. Check that PHP was not compiled with option "disable-ipv6".'); } - if (false !== strpos($ip, '/')) { - list($address, $netmask) = explode('/', $ip, 2); + // Check to see if we were given a IP4 $requestIp or $ip by mistake + if (!filter_var($requestIp, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + return self::$checkedIps[$cacheKey] = false; + } + + if (str_contains($ip, '/')) { + [$address, $netmask] = explode('/', $ip, 2); + + if (!filter_var($address, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + return self::$checkedIps[$cacheKey] = false; + } if ('0' === $netmask) { return (bool) unpack('n*', @inet_pton($address)); @@ -131,6 +155,10 @@ public static function checkIp6($requestIp, $ip) return self::$checkedIps[$cacheKey] = false; } } else { + if (!filter_var($ip, \FILTER_VALIDATE_IP, \FILTER_FLAG_IPV6)) { + return self::$checkedIps[$cacheKey] = false; + } + $address = $ip; $netmask = 128; } @@ -145,7 +173,7 @@ public static function checkIp6($requestIp, $ip) for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) { $left = $netmask - 16 * ($i - 1); $left = ($left <= 16) ? $left : 16; - $mask = ~(0xffff >> $left) & 0xffff; + $mask = ~(0xFFFF >> $left) & 0xFFFF; if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) { return self::$checkedIps[$cacheKey] = false; } @@ -153,4 +181,36 @@ public static function checkIp6($requestIp, $ip) return self::$checkedIps[$cacheKey] = true; } + + /** + * Anonymizes an IP/IPv6. + * + * Removes the last byte for v4 and the last 8 bytes for v6 IPs + */ + public static function anonymize(string $ip): string + { + $wrappedIPv6 = false; + if ('[' === substr($ip, 0, 1) && ']' === substr($ip, -1, 1)) { + $wrappedIPv6 = true; + $ip = substr($ip, 1, -1); + } + + $packedAddress = inet_pton($ip); + if (4 === \strlen($packedAddress)) { + $mask = '255.255.255.0'; + } elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff:ffff'))) { + $mask = '::ffff:ffff:ff00'; + } elseif ($ip === inet_ntop($packedAddress & inet_pton('::ffff:ffff'))) { + $mask = '::ffff:ff00'; + } else { + $mask = 'ffff:ffff:ffff:ffff:0000:0000:0000:0000'; + } + $ip = inet_ntop($packedAddress & inet_pton($mask)); + + if ($wrappedIPv6) { + $ip = '['.$ip.']'; + } + + return $ip; + } } diff --git a/vendor/symfony/http-foundation/JsonResponse.php b/vendor/symfony/http-foundation/JsonResponse.php index 1a23a933..501a6387 100644 --- a/vendor/symfony/http-foundation/JsonResponse.php +++ b/vendor/symfony/http-foundation/JsonResponse.php @@ -29,7 +29,7 @@ class JsonResponse extends Response // Encode <, >, ', &, and " characters in the JSON, making it also safe to be embedded into HTML. // 15 === JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT - const DEFAULT_ENCODING_OPTIONS = 15; + public const DEFAULT_ENCODING_OPTIONS = 15; protected $encodingOptions = self::DEFAULT_ENCODING_OPTIONS; @@ -39,10 +39,14 @@ class JsonResponse extends Response * @param array $headers An array of response headers * @param bool $json If the data is already a JSON string */ - public function __construct($data = null, $status = 200, $headers = [], $json = false) + public function __construct($data = null, int $status = 200, array $headers = [], bool $json = false) { parent::__construct('', $status, $headers); + if ($json && !\is_string($data) && !is_numeric($data) && !\is_callable([$data, '__toString'])) { + throw new \TypeError(sprintf('"%s": If $json is set to true, argument $data must be a string or object implementing __toString(), "%s" given.', __METHOD__, get_debug_type($data))); + } + if (null === $data) { $data = new \ArrayObject(); } @@ -63,9 +67,13 @@ public function __construct($data = null, $status = 200, $headers = [], $json = * @param array $headers An array of response headers * * @return static + * + * @deprecated since Symfony 5.1, use __construct() instead. */ - public static function create($data = null, $status = 200, $headers = []) + public static function create($data = null, int $status = 200, array $headers = []) { + trigger_deprecation('symfony/http-foundation', '5.1', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class); + return new static($data, $status, $headers); } @@ -77,13 +85,13 @@ public static function create($data = null, $status = 200, $headers = []) * return JsonResponse::fromJsonString('{"key": "value"}') * ->setSharedMaxAge(300); * - * @param string|null $data The JSON response string - * @param int $status The response status code - * @param array $headers An array of response headers + * @param string $data The JSON response string + * @param int $status The response status code + * @param array $headers An array of response headers * * @return static */ - public static function fromJsonString($data = null, $status = 200, $headers = []) + public static function fromJsonString(string $data, int $status = 200, array $headers = []) { return new static($data, $status, $headers, true); } @@ -97,7 +105,7 @@ public static function fromJsonString($data = null, $status = 200, $headers = [] * * @throws \InvalidArgumentException When the callback name is not valid */ - public function setCallback($callback = null) + public function setCallback(string $callback = null) { if (null !== $callback) { // partially taken from https://geekality.net/2011/08/03/valid-javascript-identifier/ @@ -126,13 +134,9 @@ public function setCallback($callback = null) /** * Sets a raw string containing a JSON document to be sent. * - * @param string $json - * * @return $this - * - * @throws \InvalidArgumentException */ - public function setJson($json) + public function setJson(string $json) { $this->data = $json; @@ -150,33 +154,17 @@ public function setJson($json) */ public function setData($data = []) { - if (\defined('HHVM_VERSION')) { - // HHVM does not trigger any warnings and let exceptions - // thrown from a JsonSerializable object pass through. - // If only PHP did the same... + try { $data = json_encode($data, $this->encodingOptions); - } else { - if (!interface_exists('JsonSerializable', false)) { - set_error_handler(function () { return false; }); - try { - $data = @json_encode($data, $this->encodingOptions); - } finally { - restore_error_handler(); - } - } else { - try { - $data = json_encode($data, $this->encodingOptions); - } catch (\Exception $e) { - if ('Exception' === \get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) { - throw $e->getPrevious() ?: $e; - } - throw $e; - } - - if (\PHP_VERSION_ID >= 70300 && (\JSON_THROW_ON_ERROR & $this->encodingOptions)) { - return $this->setJson($data); - } + } catch (\Exception $e) { + if ('Exception' === \get_class($e) && str_starts_with($e->getMessage(), 'Failed calling ')) { + throw $e->getPrevious() ?: $e; } + throw $e; + } + + if (\PHP_VERSION_ID >= 70300 && (\JSON_THROW_ON_ERROR & $this->encodingOptions)) { + return $this->setJson($data); } if (\JSON_ERROR_NONE !== json_last_error()) { @@ -199,13 +187,11 @@ public function getEncodingOptions() /** * Sets options used while encoding data to JSON. * - * @param int $encodingOptions - * * @return $this */ - public function setEncodingOptions($encodingOptions) + public function setEncodingOptions(int $encodingOptions) { - $this->encodingOptions = (int) $encodingOptions; + $this->encodingOptions = $encodingOptions; return $this->setData(json_decode($this->data)); } diff --git a/vendor/symfony/http-foundation/LICENSE b/vendor/symfony/http-foundation/LICENSE index 9e936ec0..0138f8f0 100644 --- a/vendor/symfony/http-foundation/LICENSE +++ b/vendor/symfony/http-foundation/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/http-foundation/ParameterBag.php b/vendor/symfony/http-foundation/ParameterBag.php index 5f2d9293..e1f89d69 100644 --- a/vendor/symfony/http-foundation/ParameterBag.php +++ b/vendor/symfony/http-foundation/ParameterBag.php @@ -11,10 +11,14 @@ namespace Symfony\Component\HttpFoundation; +use Symfony\Component\HttpFoundation\Exception\BadRequestException; + /** * ParameterBag is a container for key/value pairs. * * @author Fabien Potencier + * + * @implements \IteratorAggregate */ class ParameterBag implements \IteratorAggregate, \Countable { @@ -23,9 +27,6 @@ class ParameterBag implements \IteratorAggregate, \Countable */ protected $parameters; - /** - * @param array $parameters An array of parameters - */ public function __construct(array $parameters = []) { $this->parameters = $parameters; @@ -34,17 +35,29 @@ public function __construct(array $parameters = []) /** * Returns the parameters. * - * @return array An array of parameters + * @param string|null $key The name of the parameter to return or null to get them all + * + * @return array */ - public function all() + public function all(/* string $key = null */) { - return $this->parameters; + $key = \func_num_args() > 0 ? func_get_arg(0) : null; + + if (null === $key) { + return $this->parameters; + } + + if (!\is_array($value = $this->parameters[$key] ?? [])) { + throw new BadRequestException(sprintf('Unexpected value for parameter "%s": expecting "array", got "%s".', $key, get_debug_type($value))); + } + + return $value; } /** * Returns the parameter keys. * - * @return array An array of parameter keys + * @return array */ public function keys() { @@ -53,8 +66,6 @@ public function keys() /** * Replaces the current parameters by a new set. - * - * @param array $parameters An array of parameters */ public function replace(array $parameters = []) { @@ -63,8 +74,6 @@ public function replace(array $parameters = []) /** * Adds parameters. - * - * @param array $parameters An array of parameters */ public function add(array $parameters = []) { @@ -74,12 +83,11 @@ public function add(array $parameters = []) /** * Returns a parameter by name. * - * @param string $key The key - * @param mixed $default The default value if the parameter key does not exist + * @param mixed $default The default value if the parameter key does not exist * * @return mixed */ - public function get($key, $default = null) + public function get(string $key, $default = null) { return \array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default; } @@ -87,10 +95,9 @@ public function get($key, $default = null) /** * Sets a parameter by name. * - * @param string $key The key - * @param mixed $value The value + * @param mixed $value The value */ - public function set($key, $value) + public function set(string $key, $value) { $this->parameters[$key] = $value; } @@ -98,21 +105,17 @@ public function set($key, $value) /** * Returns true if the parameter is defined. * - * @param string $key The key - * - * @return bool true if the parameter exists, false otherwise + * @return bool */ - public function has($key) + public function has(string $key) { return \array_key_exists($key, $this->parameters); } /** * Removes a parameter. - * - * @param string $key The key */ - public function remove($key) + public function remove(string $key) { unset($this->parameters[$key]); } @@ -120,12 +123,9 @@ public function remove($key) /** * Returns the alphabetic characters of the parameter value. * - * @param string $key The parameter key - * @param string $default The default value if the parameter key does not exist - * - * @return string The filtered value + * @return string */ - public function getAlpha($key, $default = '') + public function getAlpha(string $key, string $default = '') { return preg_replace('/[^[:alpha:]]/', '', $this->get($key, $default)); } @@ -133,12 +133,9 @@ public function getAlpha($key, $default = '') /** * Returns the alphabetic characters and digits of the parameter value. * - * @param string $key The parameter key - * @param string $default The default value if the parameter key does not exist - * - * @return string The filtered value + * @return string */ - public function getAlnum($key, $default = '') + public function getAlnum(string $key, string $default = '') { return preg_replace('/[^[:alnum:]]/', '', $this->get($key, $default)); } @@ -146,12 +143,9 @@ public function getAlnum($key, $default = '') /** * Returns the digits of the parameter value. * - * @param string $key The parameter key - * @param string $default The default value if the parameter key does not exist - * - * @return string The filtered value + * @return string */ - public function getDigits($key, $default = '') + public function getDigits(string $key, string $default = '') { // we need to remove - and + because they're allowed in the filter return str_replace(['-', '+'], '', $this->filter($key, $default, \FILTER_SANITIZE_NUMBER_INT)); @@ -160,12 +154,9 @@ public function getDigits($key, $default = '') /** * Returns the parameter value converted to integer. * - * @param string $key The parameter key - * @param int $default The default value if the parameter key does not exist - * - * @return int The filtered value + * @return int */ - public function getInt($key, $default = 0) + public function getInt(string $key, int $default = 0) { return (int) $this->get($key, $default); } @@ -173,12 +164,9 @@ public function getInt($key, $default = 0) /** * Returns the parameter value converted to boolean. * - * @param string $key The parameter key - * @param bool $default The default value if the parameter key does not exist - * - * @return bool The filtered value + * @return bool */ - public function getBoolean($key, $default = false) + public function getBoolean(string $key, bool $default = false) { return $this->filter($key, $default, \FILTER_VALIDATE_BOOLEAN); } @@ -186,16 +174,15 @@ public function getBoolean($key, $default = false) /** * Filter key. * - * @param string $key Key - * @param mixed $default Default = null - * @param int $filter FILTER_* constant - * @param mixed $options Filter options + * @param mixed $default Default = null + * @param int $filter FILTER_* constant + * @param mixed $options Filter options * * @see https://php.net/filter-var * * @return mixed */ - public function filter($key, $default = null, $filter = \FILTER_DEFAULT, $options = []) + public function filter(string $key, $default = null, int $filter = \FILTER_DEFAULT, $options = []) { $value = $this->get($key, $default); @@ -209,14 +196,20 @@ public function filter($key, $default = null, $filter = \FILTER_DEFAULT, $option $options['flags'] = \FILTER_REQUIRE_ARRAY; } + if ((\FILTER_CALLBACK & $filter) && !(($options['options'] ?? null) instanceof \Closure)) { + trigger_deprecation('symfony/http-foundation', '5.2', 'Not passing a Closure together with FILTER_CALLBACK to "%s()" is deprecated. Wrap your filter in a closure instead.', __METHOD__); + // throw new \InvalidArgumentException(sprintf('A Closure must be passed to "%s()" when FILTER_CALLBACK is used, "%s" given.', __METHOD__, get_debug_type($options['options'] ?? null))); + } + return filter_var($value, $filter, $options); } /** * Returns an iterator for parameters. * - * @return \ArrayIterator An \ArrayIterator instance + * @return \ArrayIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->parameters); @@ -225,8 +218,9 @@ public function getIterator() /** * Returns the number of parameters. * - * @return int The number of parameters + * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->parameters); diff --git a/vendor/symfony/http-foundation/README.md b/vendor/symfony/http-foundation/README.md index ac98f9b8..424f2c4f 100644 --- a/vendor/symfony/http-foundation/README.md +++ b/vendor/symfony/http-foundation/README.md @@ -4,11 +4,25 @@ HttpFoundation Component The HttpFoundation component defines an object-oriented layer for the HTTP specification. +Sponsor +------- + +The HttpFoundation component for Symfony 5.4/6.0 is [backed][1] by [Laravel][2]. + +Laravel is a PHP web development framework that is passionate about maximum developer +happiness. Laravel is built using a variety of bespoke and Symfony based components. + +Help Symfony by [sponsoring][3] its development! + Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://laravel.com/ +[3]: https://symfony.com/sponsor diff --git a/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php b/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php new file mode 100644 index 00000000..a6dd993b --- /dev/null +++ b/vendor/symfony/http-foundation/RateLimiter/AbstractRequestRateLimiter.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\RateLimiter; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\RateLimiter\LimiterInterface; +use Symfony\Component\RateLimiter\Policy\NoLimiter; +use Symfony\Component\RateLimiter\RateLimit; + +/** + * An implementation of RequestRateLimiterInterface that + * fits most use-cases. + * + * @author Wouter de Jong + */ +abstract class AbstractRequestRateLimiter implements RequestRateLimiterInterface +{ + public function consume(Request $request): RateLimit + { + $limiters = $this->getLimiters($request); + if (0 === \count($limiters)) { + $limiters = [new NoLimiter()]; + } + + $minimalRateLimit = null; + foreach ($limiters as $limiter) { + $rateLimit = $limiter->consume(1); + + $minimalRateLimit = $minimalRateLimit ? self::getMinimalRateLimit($minimalRateLimit, $rateLimit) : $rateLimit; + } + + return $minimalRateLimit; + } + + public function reset(Request $request): void + { + foreach ($this->getLimiters($request) as $limiter) { + $limiter->reset(); + } + } + + /** + * @return LimiterInterface[] a set of limiters using keys extracted from the request + */ + abstract protected function getLimiters(Request $request): array; + + private static function getMinimalRateLimit(RateLimit $first, RateLimit $second): RateLimit + { + if ($first->isAccepted() !== $second->isAccepted()) { + return $first->isAccepted() ? $second : $first; + } + + $firstRemainingTokens = $first->getRemainingTokens(); + $secondRemainingTokens = $second->getRemainingTokens(); + + if ($firstRemainingTokens === $secondRemainingTokens) { + return $first->getRetryAfter() < $second->getRetryAfter() ? $second : $first; + } + + return $firstRemainingTokens > $secondRemainingTokens ? $second : $first; + } +} diff --git a/vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php b/vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php new file mode 100644 index 00000000..4c87a40a --- /dev/null +++ b/vendor/symfony/http-foundation/RateLimiter/RequestRateLimiterInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\RateLimiter; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\RateLimiter\RateLimit; + +/** + * A special type of limiter that deals with requests. + * + * This allows to limit on different types of information + * from the requests. + * + * @author Wouter de Jong + */ +interface RequestRateLimiterInterface +{ + public function consume(Request $request): RateLimit; + + public function reset(Request $request): void; +} diff --git a/vendor/symfony/http-foundation/RedirectResponse.php b/vendor/symfony/http-foundation/RedirectResponse.php index 9ef9059f..2103280c 100644 --- a/vendor/symfony/http-foundation/RedirectResponse.php +++ b/vendor/symfony/http-foundation/RedirectResponse.php @@ -32,7 +32,7 @@ class RedirectResponse extends Response * * @see https://tools.ietf.org/html/rfc2616#section-10.3 */ - public function __construct($url, $status = 302, $headers = []) + public function __construct(string $url, int $status = 302, array $headers = []) { parent::__construct('', $status, $headers); @@ -50,21 +50,23 @@ public function __construct($url, $status = 302, $headers = []) /** * Factory method for chainability. * - * @param string $url The url to redirect to - * @param int $status The response status code - * @param array $headers An array of response headers + * @param string $url The URL to redirect to * * @return static + * + * @deprecated since Symfony 5.1, use __construct() instead. */ - public static function create($url = '', $status = 302, $headers = []) + public static function create($url = '', int $status = 302, array $headers = []) { + trigger_deprecation('symfony/http-foundation', '5.1', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class); + return new static($url, $status, $headers); } /** * Returns the target URL. * - * @return string target URL + * @return string */ public function getTargetUrl() { @@ -74,15 +76,13 @@ public function getTargetUrl() /** * Sets the redirect target of this response. * - * @param string $url The URL to redirect to - * * @return $this * * @throws \InvalidArgumentException */ - public function setTargetUrl($url) + public function setTargetUrl(string $url) { - if (empty($url)) { + if ('' === $url) { throw new \InvalidArgumentException('Cannot redirect to an empty URL.'); } diff --git a/vendor/symfony/http-foundation/Request.php b/vendor/symfony/http-foundation/Request.php index c9bf0a26..f8e34215 100644 --- a/vendor/symfony/http-foundation/Request.php +++ b/vendor/symfony/http-foundation/Request.php @@ -12,9 +12,20 @@ namespace Symfony\Component\HttpFoundation; use Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException; +use Symfony\Component\HttpFoundation\Exception\JsonException; +use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpFoundation\Session\SessionInterface; +// Help opcache.preload discover always-needed symbols +class_exists(AcceptHeader::class); +class_exists(FileBag::class); +class_exists(HeaderBag::class); +class_exists(HeaderUtils::class); +class_exists(InputBag::class); +class_exists(ParameterBag::class); +class_exists(ServerBag::class); + /** * Request represents an HTTP request. * @@ -30,33 +41,28 @@ */ class Request { - const HEADER_FORWARDED = 0b00001; // When using RFC 7239 - const HEADER_X_FORWARDED_FOR = 0b00010; - const HEADER_X_FORWARDED_HOST = 0b00100; - const HEADER_X_FORWARDED_PROTO = 0b01000; - const HEADER_X_FORWARDED_PORT = 0b10000; - const HEADER_X_FORWARDED_ALL = 0b11110; // All "X-Forwarded-*" headers - const HEADER_X_FORWARDED_AWS_ELB = 0b11010; // AWS ELB doesn't send X-Forwarded-Host - - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_IP = self::HEADER_X_FORWARDED_FOR; - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_HOST = self::HEADER_X_FORWARDED_HOST; - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_PROTO = self::HEADER_X_FORWARDED_PROTO; - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_PORT = self::HEADER_X_FORWARDED_PORT; - - const METHOD_HEAD = 'HEAD'; - const METHOD_GET = 'GET'; - const METHOD_POST = 'POST'; - const METHOD_PUT = 'PUT'; - const METHOD_PATCH = 'PATCH'; - const METHOD_DELETE = 'DELETE'; - const METHOD_PURGE = 'PURGE'; - const METHOD_OPTIONS = 'OPTIONS'; - const METHOD_TRACE = 'TRACE'; - const METHOD_CONNECT = 'CONNECT'; + public const HEADER_FORWARDED = 0b000001; // When using RFC 7239 + public const HEADER_X_FORWARDED_FOR = 0b000010; + public const HEADER_X_FORWARDED_HOST = 0b000100; + public const HEADER_X_FORWARDED_PROTO = 0b001000; + public const HEADER_X_FORWARDED_PORT = 0b010000; + public const HEADER_X_FORWARDED_PREFIX = 0b100000; + + /** @deprecated since Symfony 5.2, use either "HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO" or "HEADER_X_FORWARDED_AWS_ELB" or "HEADER_X_FORWARDED_TRAEFIK" constants instead. */ + public const HEADER_X_FORWARDED_ALL = 0b1011110; // All "X-Forwarded-*" headers sent by "usual" reverse proxy + public const HEADER_X_FORWARDED_AWS_ELB = 0b0011010; // AWS ELB doesn't send X-Forwarded-Host + public const HEADER_X_FORWARDED_TRAEFIK = 0b0111110; // All "X-Forwarded-*" headers sent by Traefik reverse proxy + + public const METHOD_HEAD = 'HEAD'; + public const METHOD_GET = 'GET'; + public const METHOD_POST = 'POST'; + public const METHOD_PUT = 'PUT'; + public const METHOD_PATCH = 'PATCH'; + public const METHOD_DELETE = 'DELETE'; + public const METHOD_PURGE = 'PURGE'; + public const METHOD_OPTIONS = 'OPTIONS'; + public const METHOD_TRACE = 'TRACE'; + public const METHOD_CONNECT = 'CONNECT'; /** * @var string[] @@ -73,25 +79,6 @@ class Request */ protected static $trustedHosts = []; - /** - * Names for headers that can be trusted when - * using trusted proxies. - * - * The FORWARDED header is the standard as of rfc7239. - * - * The other headers are non-standard, but widely used - * by popular reverse proxies (like Apache mod_proxy or Amazon EC2). - * - * @deprecated since version 3.3, to be removed in 4.0 - */ - protected static $trustedHeaders = [ - self::HEADER_FORWARDED => 'FORWARDED', - self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', - self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', - self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', - self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ]; - protected static $httpMethodParameterOverride = false; /** @@ -104,14 +91,14 @@ class Request /** * Request body parameters ($_POST). * - * @var ParameterBag + * @var InputBag */ public $request; /** * Query string parameters ($_GET). * - * @var ParameterBag + * @var InputBag */ public $query; @@ -132,7 +119,7 @@ class Request /** * Cookies ($_COOKIE). * - * @var ParameterBag + * @var InputBag */ public $cookies; @@ -199,12 +186,12 @@ class Request protected $format; /** - * @var SessionInterface + * @var SessionInterface|callable(): SessionInterface */ protected $session; /** - * @var string + * @var string|null */ protected $locale; @@ -220,27 +207,48 @@ class Request protected static $requestFactory; + /** + * @var string|null + */ + private $preferredFormat; private $isHostValid = true; private $isForwardedValid = true; - private static $trustedHeaderSet = -1; + /** + * @var bool|null + */ + private $isSafeContentPreferred; - /** @deprecated since version 3.3, to be removed in 4.0 */ - private static $trustedHeaderNames = [ - self::HEADER_FORWARDED => 'FORWARDED', - self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', - self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', - self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', - self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ]; + private static $trustedHeaderSet = -1; - private static $forwardedParams = [ + private const FORWARDED_PARAMS = [ self::HEADER_X_FORWARDED_FOR => 'for', self::HEADER_X_FORWARDED_HOST => 'host', self::HEADER_X_FORWARDED_PROTO => 'proto', self::HEADER_X_FORWARDED_PORT => 'host', ]; + /** + * Names for headers that can be trusted when + * using trusted proxies. + * + * The FORWARDED header is the standard as of rfc7239. + * + * The other headers are non-standard, but widely used + * by popular reverse proxies (like Apache mod_proxy or Amazon EC2). + */ + private const TRUSTED_HEADERS = [ + self::HEADER_FORWARDED => 'FORWARDED', + self::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', + self::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', + self::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', + self::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', + self::HEADER_X_FORWARDED_PREFIX => 'X_FORWARDED_PREFIX', + ]; + + /** @var bool */ + private $isIisRewrite = false; + /** * @param array $query The GET parameters * @param array $request The POST parameters @@ -270,10 +278,10 @@ public function __construct(array $query = [], array $request = [], array $attri */ public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) { - $this->request = new ParameterBag($request); - $this->query = new ParameterBag($query); + $this->request = new InputBag($request); + $this->query = new InputBag($query); $this->attributes = new ParameterBag($attributes); - $this->cookies = new ParameterBag($cookies); + $this->cookies = new InputBag($cookies); $this->files = new FileBag($files); $this->server = new ServerBag($server); $this->headers = new HeaderBag($this->server->getHeaders()); @@ -298,26 +306,13 @@ public function initialize(array $query = [], array $request = [], array $attrib */ public static function createFromGlobals() { - // With the php's bug #66606, the php's built-in web server - // stores the Content-Type and Content-Length header values in - // HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields. - $server = $_SERVER; - if ('cli-server' === \PHP_SAPI) { - if (\array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) { - $server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH']; - } - if (\array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) { - $server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE']; - } - } + $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $_SERVER); - $request = self::createRequestFromFactory($_GET, $_POST, [], $_COOKIE, $_FILES, $server); - - if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded') + if (str_starts_with($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded') && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH']) ) { parse_str($request->getContent(), $data); - $request->request = new ParameterBag($data); + $request->request = new InputBag($data); } return $request; @@ -339,13 +334,13 @@ public static function createFromGlobals() * * @return static */ - public static function create($uri, $method = 'GET', $parameters = [], $cookies = [], $files = [], $server = [], $content = null) + public static function create(string $uri, string $method = 'GET', array $parameters = [], array $cookies = [], array $files = [], array $server = [], $content = null) { $server = array_replace([ 'SERVER_NAME' => 'localhost', 'SERVER_PORT' => 80, 'HTTP_HOST' => 'localhost', - 'HTTP_USER_AGENT' => 'Symfony/3.X', + 'HTTP_USER_AGENT' => 'Symfony', 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', @@ -354,6 +349,7 @@ public static function create($uri, $method = 'GET', $parameters = [], $cookies 'SCRIPT_FILENAME' => '', 'SERVER_PROTOCOL' => 'HTTP/1.1', 'REQUEST_TIME' => time(), + 'REQUEST_TIME_FLOAT' => microtime(true), ], $server); $server['PATH_INFO'] = ''; @@ -437,10 +433,8 @@ public static function create($uri, $method = 'GET', $parameters = [], $cookies * This is mainly useful when you need to override the Request class * to keep BC with an existing system. It should not be used for any * other purpose. - * - * @param callable|null $callable A PHP callable */ - public static function setFactory($callable) + public static function setFactory(?callable $callable) { self::$requestFactory = $callable; } @@ -448,12 +442,12 @@ public static function setFactory($callable) /** * Clones a request and overrides some of its parameters. * - * @param array $query The GET parameters - * @param array $request The POST parameters - * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) - * @param array $cookies The COOKIE parameters - * @param array $files The FILES parameters - * @param array $server The SERVER parameters + * @param array|null $query The GET parameters + * @param array|null $request The POST parameters + * @param array|null $attributes The request attributes (parameters parsed from the PATH_INFO, ...) + * @param array|null $cookies The COOKIE parameters + * @param array|null $files The FILES parameters + * @param array|null $server The SERVER parameters * * @return static */ @@ -461,16 +455,16 @@ public function duplicate(array $query = null, array $request = null, array $att { $dup = clone $this; if (null !== $query) { - $dup->query = new ParameterBag($query); + $dup->query = new InputBag($query); } if (null !== $request) { - $dup->request = new ParameterBag($request); + $dup->request = new InputBag($request); } if (null !== $attributes) { $dup->attributes = new ParameterBag($attributes); } if (null !== $cookies) { - $dup->cookies = new ParameterBag($cookies); + $dup->cookies = new InputBag($cookies); } if (null !== $files) { $dup->files = new FileBag($files); @@ -521,28 +515,20 @@ public function __clone() /** * Returns the request as a string. * - * @return string The request + * @return string */ public function __toString() { - try { - $content = $this->getContent(); - } catch (\LogicException $e) { - if (\PHP_VERSION_ID >= 70400) { - throw $e; - } - - return trigger_error($e, \E_USER_ERROR); - } + $content = $this->getContent(); $cookieHeader = ''; $cookies = []; foreach ($this->cookies as $k => $v) { - $cookies[] = $k.'='.$v; + $cookies[] = \is_array($v) ? http_build_query([$k => $v], '', '; ', \PHP_QUERY_RFC3986) : "$k=$v"; } - if (!empty($cookies)) { + if ($cookies) { $cookieHeader = 'Cookie: '.implode('; ', $cookies)."\r\n"; } @@ -570,7 +556,7 @@ public function overrideGlobals() foreach ($this->headers->all() as $key => $value) { $key = strtoupper(str_replace('-', '_', $key)); - if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) { + if (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) { $_SERVER[$key] = implode(', ', $value); } else { $_SERVER['HTTP_'.$key] = implode(', ', $value); @@ -579,13 +565,16 @@ public function overrideGlobals() $request = ['g' => $_GET, 'p' => $_POST, 'c' => $_COOKIE]; - $requestOrder = ini_get('request_order') ?: ini_get('variables_order'); + $requestOrder = \ini_get('request_order') ?: \ini_get('variables_order'); $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp'; - $_REQUEST = []; + $_REQUEST = [[]]; + foreach (str_split($requestOrder) as $order) { - $_REQUEST = array_merge($_REQUEST, $request[$order]); + $_REQUEST[] = $request[$order]; } + + $_REQUEST = array_merge(...$_REQUEST); } /** @@ -593,32 +582,30 @@ public function overrideGlobals() * * You should only list the reverse proxies that you manage directly. * - * @param array $proxies A list of trusted proxies + * @param array $proxies A list of trusted proxies, the string 'REMOTE_ADDR' will be replaced with $_SERVER['REMOTE_ADDR'] * @param int $trustedHeaderSet A bit field of Request::HEADER_*, to set which headers to trust from your proxies - * - * @throws \InvalidArgumentException When $trustedHeaderSet is invalid */ - public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet*/) + public static function setTrustedProxies(array $proxies, int $trustedHeaderSet) { - self::$trustedProxies = $proxies; - - if (2 > \func_num_args()) { - @trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since Symfony 3.3. Defining it will be required in 4.0. ', __METHOD__), \E_USER_DEPRECATED); - - return; + if (self::HEADER_X_FORWARDED_ALL === $trustedHeaderSet) { + trigger_deprecation('symfony/http-foundation', '5.2', 'The "HEADER_X_FORWARDED_ALL" constant is deprecated, use either "HEADER_X_FORWARDED_FOR | HEADER_X_FORWARDED_HOST | HEADER_X_FORWARDED_PORT | HEADER_X_FORWARDED_PROTO" or "HEADER_X_FORWARDED_AWS_ELB" or "HEADER_X_FORWARDED_TRAEFIK" constants instead.'); } - $trustedHeaderSet = (int) func_get_arg(1); + self::$trustedProxies = array_reduce($proxies, function ($proxies, $proxy) { + if ('REMOTE_ADDR' !== $proxy) { + $proxies[] = $proxy; + } elseif (isset($_SERVER['REMOTE_ADDR'])) { + $proxies[] = $_SERVER['REMOTE_ADDR']; + } - foreach (self::$trustedHeaderNames as $header => $name) { - self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null; - } + return $proxies; + }, []); self::$trustedHeaderSet = $trustedHeaderSet; } /** * Gets the list of trusted proxies. * - * @return array An array of trusted proxies + * @return array */ public static function getTrustedProxies() { @@ -654,126 +641,31 @@ public static function setTrustedHosts(array $hostPatterns) /** * Gets the list of trusted host patterns. * - * @return array An array of trusted host patterns + * @return array */ public static function getTrustedHosts() { return self::$trustedHostPatterns; } - /** - * Sets the name for trusted headers. - * - * The following header keys are supported: - * - * * Request::HEADER_CLIENT_IP: defaults to X-Forwarded-For (see getClientIp()) - * * Request::HEADER_CLIENT_HOST: defaults to X-Forwarded-Host (see getHost()) - * * Request::HEADER_CLIENT_PORT: defaults to X-Forwarded-Port (see getPort()) - * * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure()) - * * Request::HEADER_FORWARDED: defaults to Forwarded (see RFC 7239) - * - * Setting an empty value allows to disable the trusted header for the given key. - * - * @param string $key The header key - * @param string $value The header name - * - * @throws \InvalidArgumentException - * - * @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead. - */ - public static function setTrustedHeaderName($key, $value) - { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), \E_USER_DEPRECATED); - - if ('forwarded' === $key) { - $key = self::HEADER_FORWARDED; - } elseif ('client_ip' === $key) { - $key = self::HEADER_CLIENT_IP; - } elseif ('client_host' === $key) { - $key = self::HEADER_CLIENT_HOST; - } elseif ('client_proto' === $key) { - $key = self::HEADER_CLIENT_PROTO; - } elseif ('client_port' === $key) { - $key = self::HEADER_CLIENT_PORT; - } elseif (!\array_key_exists($key, self::$trustedHeaders)) { - throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key)); - } - - self::$trustedHeaders[$key] = $value; - - if (null !== $value) { - self::$trustedHeaderNames[$key] = $value; - self::$trustedHeaderSet |= $key; - } else { - self::$trustedHeaderSet &= ~$key; - } - } - - /** - * Gets the trusted proxy header name. - * - * @param string $key The header key - * - * @return string The header name - * - * @throws \InvalidArgumentException - * - * @deprecated since version 3.3, to be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead. - */ - public static function getTrustedHeaderName($key) - { - if (2 > \func_num_args() || func_get_arg(1)) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.', __METHOD__), \E_USER_DEPRECATED); - } - - if (!\array_key_exists($key, self::$trustedHeaders)) { - throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key)); - } - - return self::$trustedHeaders[$key]; - } - /** * Normalizes a query string. * * It builds a normalized query string, where keys/value pairs are alphabetized, * have consistent escaping and unneeded delimiters are removed. * - * @param string $qs Query string - * - * @return string A normalized query string for the Request + * @return string */ - public static function normalizeQueryString($qs) + public static function normalizeQueryString(?string $qs) { - if ('' == $qs) { + if ('' === ($qs ?? '')) { return ''; } - $parts = []; - $order = []; - - foreach (explode('&', $qs) as $param) { - if ('' === $param || '=' === $param[0]) { - // Ignore useless delimiters, e.g. "x=y&". - // Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway. - // PHP also does not include them when building _GET. - continue; - } - - $keyValuePair = explode('=', $param, 2); - - // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded). - // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. This is why we use urldecode and then normalize to - // RFC 3986 with rawurlencode. - $parts[] = isset($keyValuePair[1]) ? - rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) : - rawurlencode(urldecode($keyValuePair[0])); - $order[] = urldecode($keyValuePair[0]); - } - - array_multisort($order, \SORT_ASC, $parts); + $qs = HeaderUtils::parseQuery($qs); + ksort($qs); - return implode('&', $parts); + return http_build_query($qs, '', '&', \PHP_QUERY_RFC3986); } /** @@ -795,7 +687,7 @@ public static function enableHttpMethodParameterOverride() /** * Checks whether support for the _method request parameter is enabled. * - * @return bool True when the _method request parameter is enabled, false otherwise + * @return bool */ public static function getHttpMethodParameterOverride() { @@ -809,25 +701,26 @@ public static function getHttpMethodParameterOverride() * flexibility in controllers, it is better to explicitly get request parameters from the appropriate * public property instead (attributes, query, request). * - * Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY + * Order of precedence: PATH (routing placeholders or custom attributes), GET, POST * - * @param string $key The key - * @param mixed $default The default value if the parameter key does not exist + * @param mixed $default The default value if the parameter key does not exist * * @return mixed + * + * @internal since Symfony 5.4, use explicit input sources instead */ - public function get($key, $default = null) + public function get(string $key, $default = null) { if ($this !== $result = $this->attributes->get($key, $this)) { return $result; } - if ($this !== $result = $this->query->get($key, $this)) { - return $result; + if ($this->query->has($key)) { + return $this->query->all()[$key]; } - if ($this !== $result = $this->request->get($key, $this)) { - return $result; + if ($this->request->has($key)) { + return $this->request->all()[$key]; } return $default; @@ -836,11 +729,20 @@ public function get($key, $default = null) /** * Gets the Session. * - * @return SessionInterface|null The session + * @return SessionInterface */ public function getSession() { - return $this->session; + $session = $this->session; + if (!$session instanceof SessionInterface && null !== $session) { + $this->setSession($session = $session()); + } + + if (null === $session) { + throw new SessionNotFoundException('Session has not been set.'); + } + + return $session; } /** @@ -852,7 +754,7 @@ public function getSession() public function hasPreviousSession() { // the check for $this->session avoids malicious users trying to fake a session cookie with proper name - return $this->hasSession() && $this->cookies->has($this->session->getName()); + return $this->hasSession() && $this->cookies->has($this->getSession()->getName()); } /** @@ -862,21 +764,30 @@ public function hasPreviousSession() * like whether the session is started or not. It is just a way to check if this Request * is associated with a Session instance. * - * @return bool true when the Request contains a Session object, false otherwise + * @param bool $skipIfUninitialized When true, ignores factories injected by `setSessionFactory` + * + * @return bool */ - public function hasSession() + public function hasSession(/* bool $skipIfUninitialized = false */) + { + $skipIfUninitialized = \func_num_args() > 0 ? func_get_arg(0) : false; + + return null !== $this->session && (!$skipIfUninitialized || $this->session instanceof SessionInterface); + } + + public function setSession(SessionInterface $session) { - return null !== $this->session; + $this->session = $session; } /** - * Sets the Session. + * @internal * - * @param SessionInterface $session The Session + * @param callable(): SessionInterface $factory */ - public function setSession(SessionInterface $session) + public function setSessionFactory(callable $factory) { - $this->session = $session; + $this->session = $factory; } /** @@ -888,7 +799,7 @@ public function setSession(SessionInterface $session) * * Use this method carefully; you should use getClientIp() instead. * - * @return array The client IP addresses + * @return array * * @see getClientIp() */ @@ -900,7 +811,7 @@ public function getClientIps() return [$ip]; } - return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: [$ip]; + return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip]; } /** @@ -916,7 +827,7 @@ public function getClientIps() * ("Client-Ip" for instance), configure it via the $trustedHeaderSet * argument of the Request::setTrustedProxies() method instead. * - * @return string|null The client IP address + * @return string|null * * @see getClientIps() * @see https://wikipedia.org/wiki/X-Forwarded-For @@ -993,6 +904,24 @@ public function getBasePath() * @return string The raw URL (i.e. not urldecoded) */ public function getBaseUrl() + { + $trustedPrefix = ''; + + // the proxy prefix must be prepended to any prefix being needed at the webserver level + if ($this->isFromTrustedProxy() && $trustedPrefixValues = $this->getTrustedValues(self::HEADER_X_FORWARDED_PREFIX)) { + $trustedPrefix = rtrim($trustedPrefixValues[0], '/'); + } + + return $trustedPrefix.$this->getBaseUrlReal(); + } + + /** + * Returns the real base URL received by the webserver from which this request is executed. + * The URL does not include trusted reverse proxy prefix. + * + * @return string The raw URL (i.e. not urldecoded) + */ + private function getBaseUrlReal(): string { if (null === $this->baseUrl) { $this->baseUrl = $this->prepareBaseUrl(); @@ -1019,17 +948,13 @@ public function getScheme() * * The "X-Forwarded-Port" header must contain the client port. * - * If your reverse proxy uses a different header name than "X-Forwarded-Port", - * configure it via via the $trustedHeaderSet argument of the - * Request::setTrustedProxies() method instead. - * - * @return int|string can be a string if fetched from the server bag + * @return int|string|null Can be a string if fetched from the server bag */ public function getPort() { - if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_PORT)) { + if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_PORT)) { $host = $host[0]; - } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) { + } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) { $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { return $this->server->get('SERVER_PORT'); @@ -1071,7 +996,7 @@ public function getPassword() /** * Gets the user info. * - * @return string A user name and, optionally, scheme-specific information about how to gain authorization to access the server + * @return string|null A user name if any and, optionally, scheme-specific information about how to gain authorization to access the server */ public function getUserInfo() { @@ -1124,7 +1049,7 @@ public function getRequestUri() * If the URL was called with basic authentication, the user * and the password are not added to the generated string. * - * @return string The scheme and HTTP host + * @return string */ public function getSchemeAndHttpHost() { @@ -1134,7 +1059,7 @@ public function getSchemeAndHttpHost() /** * Generates a normalized URI (URL) for the Request. * - * @return string A normalized URI (URL) for the Request + * @return string * * @see getQueryString() */ @@ -1152,9 +1077,9 @@ public function getUri() * * @param string $path A path to use instead of the current one * - * @return string The normalized URI for the path + * @return string */ - public function getUriForPath($path) + public function getUriForPath(string $path) { return $this->getSchemeAndHttpHost().$this->getBaseUrl().$path; } @@ -1174,11 +1099,9 @@ public function getUriForPath($path) * - "/a/b/c/other" -> "other" * - "/a/x/y" -> "../../x/y" * - * @param string $path The target path - * - * @return string The relative target path + * @return string */ - public function getRelativeUriForPath($path) + public function getRelativeUriForPath(string $path) { // be sure that we are dealing with an absolute path if (!isset($path[0]) || '/' !== $path[0]) { @@ -1220,7 +1143,7 @@ public function getRelativeUriForPath($path) * It builds a normalized query string, where keys/value pairs are alphabetized * and have consistent escaping. * - * @return string|null A normalized query string for the Request + * @return string|null */ public function getQueryString() { @@ -1237,15 +1160,11 @@ public function getQueryString() * * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http". * - * If your reverse proxy uses a different header name than "X-Forwarded-Proto" - * ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet - * argument of the Request::setTrustedProxies() method instead. - * * @return bool */ public function isSecure() { - if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) { + if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) { return \in_array(strtolower($proto[0]), ['https', 'on', 'ssl', '1'], true); } @@ -1262,17 +1181,13 @@ public function isSecure() * * The "X-Forwarded-Host" header must contain the client host name. * - * If your reverse proxy uses a different header name than "X-Forwarded-Host", - * configure it via the $trustedHeaderSet argument of the - * Request::setTrustedProxies() method instead. - * * @return string * * @throws SuspiciousOperationException when the host name is invalid or not trusted */ public function getHost() { - if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) { + if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) { $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { if (!$host = $this->server->get('SERVER_NAME')) { @@ -1324,10 +1239,8 @@ public function getHost() /** * Sets the request method. - * - * @param string $method */ - public function setMethod($method) + public function setMethod(string $method) { $this->method = null; $this->server->set('REQUEST_METHOD', $method); @@ -1344,7 +1257,7 @@ public function setMethod($method) * * The method is always an uppercased string. * - * @return string The request method + * @return string * * @see getRealMethod() */ @@ -1386,7 +1299,7 @@ public function getMethod() /** * Gets the "real" request method. * - * @return string The request method + * @return string * * @see getMethod() */ @@ -1398,11 +1311,9 @@ public function getRealMethod() /** * Gets the mime type associated with the format. * - * @param string $format The format - * - * @return string|null The associated mime type (null if not found) + * @return string|null */ - public function getMimeType($format) + public function getMimeType(string $format) { if (null === static::$formats) { static::initializeFormats(); @@ -1414,30 +1325,26 @@ public function getMimeType($format) /** * Gets the mime types associated with the format. * - * @param string $format The format - * - * @return array The associated mime types + * @return array */ - public static function getMimeTypes($format) + public static function getMimeTypes(string $format) { if (null === static::$formats) { static::initializeFormats(); } - return isset(static::$formats[$format]) ? static::$formats[$format] : []; + return static::$formats[$format] ?? []; } /** * Gets the format associated with the mime type. * - * @param string $mimeType The associated mime type - * - * @return string|null The format (null if not found) + * @return string|null */ - public function getFormat($mimeType) + public function getFormat(?string $mimeType) { $canonicalMimeType = null; - if (false !== $pos = strpos($mimeType, ';')) { + if ($mimeType && false !== $pos = strpos($mimeType, ';')) { $canonicalMimeType = trim(substr($mimeType, 0, $pos)); } @@ -1460,10 +1367,9 @@ public function getFormat($mimeType) /** * Associates a format with mime types. * - * @param string $format The format * @param string|array $mimeTypes The associated mime types (the preferred one must be the first as it will be used as the content type) */ - public function setFormat($format, $mimeTypes) + public function setFormat(?string $format, $mimeTypes) { if (null === static::$formats) { static::initializeFormats(); @@ -1481,25 +1387,23 @@ public function setFormat($format, $mimeTypes) * * _format request attribute * * $default * - * @param string|null $default The default format + * @see getPreferredFormat * - * @return string|null The request format + * @return string|null */ - public function getRequestFormat($default = 'html') + public function getRequestFormat(?string $default = 'html') { if (null === $this->format) { $this->format = $this->attributes->get('_format'); } - return null === $this->format ? $default : $this->format; + return $this->format ?? $default; } /** * Sets the request format. - * - * @param string $format The request format */ - public function setRequestFormat($format) + public function setRequestFormat(?string $format) { $this->format = $format; } @@ -1507,19 +1411,17 @@ public function setRequestFormat($format) /** * Gets the format associated with the request. * - * @return string|null The format (null if no content type is present) + * @return string|null */ public function getContentType() { - return $this->getFormat($this->headers->get('CONTENT_TYPE')); + return $this->getFormat($this->headers->get('CONTENT_TYPE', '')); } /** * Sets the default locale. - * - * @param string $locale */ - public function setDefaultLocale($locale) + public function setDefaultLocale(string $locale) { $this->defaultLocale = $locale; @@ -1540,10 +1442,8 @@ public function getDefaultLocale() /** * Sets the locale. - * - * @param string $locale */ - public function setLocale($locale) + public function setLocale(string $locale) { $this->setPhpDefaultLocale($this->locale = $locale); } @@ -1555,7 +1455,7 @@ public function setLocale($locale) */ public function getLocale() { - return null === $this->locale ? $this->defaultLocale : $this->locale; + return $this->locale ?? $this->defaultLocale; } /** @@ -1565,7 +1465,7 @@ public function getLocale() * * @return bool */ - public function isMethod($method) + public function isMethod(string $method) { return $this->getMethod() === strtoupper($method); } @@ -1575,20 +1475,10 @@ public function isMethod($method) * * @see https://tools.ietf.org/html/rfc7231#section-4.2.1 * - * @param bool $andCacheable Adds the additional condition that the method should be cacheable. True by default. - * * @return bool */ - public function isMethodSafe(/* $andCacheable = true */) + public function isMethodSafe() { - if (!\func_num_args() || func_get_arg(0)) { - // This deprecation should be turned into a BadMethodCallException in 4.0 (without adding the argument in the signature) - // then setting $andCacheable to false should be deprecated in 4.1 - @trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', \E_USER_DEPRECATED); - - return \in_array($this->getMethod(), ['GET', 'HEAD']); - } - return \in_array($this->getMethod(), ['GET', 'HEAD', 'OPTIONS', 'TRACE']); } @@ -1607,7 +1497,7 @@ public function isMethodIdempotent() * * @see https://tools.ietf.org/html/rfc7231#section-4.2.3 * - * @return bool True for GET and HEAD, false otherwise + * @return bool */ public function isMethodCacheable() { @@ -1623,12 +1513,12 @@ public function isMethodCacheable() * if the proxy is trusted (see "setTrustedProxies()"), otherwise it returns * the latter (from the "SERVER_PROTOCOL" server parameter). * - * @return string + * @return string|null */ public function getProtocolVersion() { if ($this->isFromTrustedProxy()) { - preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via'), $matches); + preg_match('~^(HTTP/)?([1-9]\.[0-9]) ~', $this->headers->get('Via') ?? '', $matches); if ($matches) { return 'HTTP/'.$matches[2]; @@ -1643,16 +1533,11 @@ public function getProtocolVersion() * * @param bool $asResource If true, a resource will be returned * - * @return string|resource The request body content or a resource to read the body stream - * - * @throws \LogicException + * @return string|resource */ - public function getContent($asResource = false) + public function getContent(bool $asResource = false) { $currentContentIsResource = \is_resource($this->content); - if (\PHP_VERSION_ID < 50600 && false === $this->content) { - throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.'); - } if (true === $asResource) { if ($currentContentIsResource) { @@ -1672,7 +1557,7 @@ public function getContent($asResource = false) $this->content = false; - return fopen('php://input', 'rb'); + return fopen('php://input', 'r'); } if ($currentContentIsResource) { @@ -1688,14 +1573,44 @@ public function getContent($asResource = false) return $this->content; } + /** + * Gets the request body decoded as array, typically from a JSON payload. + * + * @return array + * + * @throws JsonException When the body cannot be decoded to an array + */ + public function toArray() + { + if ('' === $content = $this->getContent()) { + throw new JsonException('Request body is empty.'); + } + + try { + $content = json_decode($content, true, 512, \JSON_BIGINT_AS_STRING | (\PHP_VERSION_ID >= 70300 ? \JSON_THROW_ON_ERROR : 0)); + } catch (\JsonException $e) { + throw new JsonException('Could not decode request body.', $e->getCode(), $e); + } + + if (\PHP_VERSION_ID < 70300 && \JSON_ERROR_NONE !== json_last_error()) { + throw new JsonException('Could not decode request body: '.json_last_error_msg(), json_last_error()); + } + + if (!\is_array($content)) { + throw new JsonException(sprintf('JSON content was expected to decode to an array, "%s" returned.', get_debug_type($content))); + } + + return $content; + } + /** * Gets the Etags. * - * @return array The entity tags + * @return array */ public function getETags() { - return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, \PREG_SPLIT_NO_EMPTY); + return preg_split('/\s*,\s*/', $this->headers->get('If-None-Match', ''), -1, \PREG_SPLIT_NO_EMPTY); } /** @@ -1706,19 +1621,42 @@ public function isNoCache() return $this->headers->hasCacheControlDirective('no-cache') || 'no-cache' == $this->headers->get('Pragma'); } + /** + * Gets the preferred format for the response by inspecting, in the following order: + * * the request format set using setRequestFormat; + * * the values of the Accept HTTP header. + * + * Note that if you use this method, you should send the "Vary: Accept" header + * in the response to prevent any issues with intermediary HTTP caches. + */ + public function getPreferredFormat(?string $default = 'html'): ?string + { + if (null !== $this->preferredFormat || null !== $this->preferredFormat = $this->getRequestFormat(null)) { + return $this->preferredFormat; + } + + foreach ($this->getAcceptableContentTypes() as $mimeType) { + if ($this->preferredFormat = $this->getFormat($mimeType)) { + return $this->preferredFormat; + } + } + + return $default; + } + /** * Returns the preferred language. * - * @param array $locales An array of ordered available locales + * @param string[] $locales An array of ordered available locales * - * @return string|null The preferred locale + * @return string|null */ public function getPreferredLanguage(array $locales = null) { $preferredLanguages = $this->getLanguages(); if (empty($locales)) { - return isset($preferredLanguages[0]) ? $preferredLanguages[0] : null; + return $preferredLanguages[0] ?? null; } if (!$preferredLanguages) { @@ -1738,13 +1676,13 @@ public function getPreferredLanguage(array $locales = null) $preferredLanguages = array_values(array_intersect($extendedPreferredLanguages, $locales)); - return isset($preferredLanguages[0]) ? $preferredLanguages[0] : $locales[0]; + return $preferredLanguages[0] ?? $locales[0]; } /** - * Gets a list of languages acceptable by the client browser. + * Gets a list of languages acceptable by the client browser ordered in the user browser preferences. * - * @return array Languages ordered in the user browser preferences + * @return array */ public function getLanguages() { @@ -1754,8 +1692,9 @@ public function getLanguages() $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all(); $this->languages = []; - foreach ($languages as $lang => $acceptHeaderItem) { - if (false !== strpos($lang, '-')) { + foreach ($languages as $acceptHeaderItem) { + $lang = $acceptHeaderItem->getValue(); + if (str_contains($lang, '-')) { $codes = explode('-', $lang); if ('i' === $codes[0]) { // Language not listed in ISO 639 that are not variants @@ -1782,9 +1721,9 @@ public function getLanguages() } /** - * Gets a list of charsets acceptable by the client browser. + * Gets a list of charsets acceptable by the client browser in preferable order. * - * @return array List of charsets in preferable order + * @return array */ public function getCharsets() { @@ -1792,13 +1731,13 @@ public function getCharsets() return $this->charsets; } - return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()); + return $this->charsets = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all())); } /** - * Gets a list of encodings acceptable by the client browser. + * Gets a list of encodings acceptable by the client browser in preferable order. * - * @return array List of encodings in preferable order + * @return array */ public function getEncodings() { @@ -1806,13 +1745,13 @@ public function getEncodings() return $this->encodings; } - return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all()); + return $this->encodings = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all())); } /** - * Gets a list of content types acceptable by the client browser. + * Gets a list of content types acceptable by the client browser in preferable order. * - * @return array List of content types in preferable order + * @return array */ public function getAcceptableContentTypes() { @@ -1820,24 +1759,43 @@ public function getAcceptableContentTypes() return $this->acceptableContentTypes; } - return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()); + return $this->acceptableContentTypes = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all())); } /** - * Returns true if the request is a XMLHttpRequest. + * Returns true if the request is an XMLHttpRequest. * * It works if your JavaScript library sets an X-Requested-With HTTP header. * It is known to work with common JavaScript frameworks: * * @see https://wikipedia.org/wiki/List_of_Ajax_frameworks#JavaScript * - * @return bool true if the request is an XMLHttpRequest, false otherwise + * @return bool */ public function isXmlHttpRequest() { return 'XMLHttpRequest' == $this->headers->get('X-Requested-With'); } + /** + * Checks whether the client browser prefers safe content or not according to RFC8674. + * + * @see https://tools.ietf.org/html/rfc8674 + */ + public function preferSafeContent(): bool + { + if (null !== $this->isSafeContentPreferred) { + return $this->isSafeContentPreferred; + } + + if (!$this->isSecure()) { + // see https://tools.ietf.org/html/rfc8674#section-3 + return $this->isSafeContentPreferred = false; + } + + return $this->isSafeContentPreferred = AcceptHeader::fromString($this->headers->get('Prefer'))->has('safe'); + } + /* * The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24) * @@ -1850,11 +1808,10 @@ protected function prepareRequestUri() { $requestUri = ''; - if ('1' == $this->server->get('IIS_WasUrlRewritten') && '' != $this->server->get('UNENCODED_URL')) { + if ($this->isIisRewrite() && '' != $this->server->get('UNENCODED_URL')) { // IIS7 with URL Rewrite: make sure we get the unencoded URL (double slash problem) $requestUri = $this->server->get('UNENCODED_URL'); $this->server->remove('UNENCODED_URL'); - $this->server->remove('IIS_WasUrlRewritten'); } elseif ($this->server->has('REQUEST_URI')) { $requestUri = $this->server->get('REQUEST_URI'); @@ -1898,13 +1855,13 @@ protected function prepareRequestUri() */ protected function prepareBaseUrl() { - $filename = basename($this->server->get('SCRIPT_FILENAME')); + $filename = basename($this->server->get('SCRIPT_FILENAME', '')); - if (basename($this->server->get('SCRIPT_NAME')) === $filename) { + if (basename($this->server->get('SCRIPT_NAME', '')) === $filename) { $baseUrl = $this->server->get('SCRIPT_NAME'); - } elseif (basename($this->server->get('PHP_SELF')) === $filename) { + } elseif (basename($this->server->get('PHP_SELF', '')) === $filename) { $baseUrl = $this->server->get('PHP_SELF'); - } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) { + } elseif (basename($this->server->get('ORIG_SCRIPT_NAME', '')) === $filename) { $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility } else { // Backtrack up the script_filename to find the portion matching @@ -1929,12 +1886,12 @@ protected function prepareBaseUrl() $requestUri = '/'.$requestUri; } - if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) { + if ($baseUrl && null !== $prefix = $this->getUrlencodedPrefix($requestUri, $baseUrl)) { // full $baseUrl matches return $prefix; } - if ($baseUrl && false !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) { + if ($baseUrl && null !== $prefix = $this->getUrlencodedPrefix($requestUri, rtrim(\dirname($baseUrl), '/'.\DIRECTORY_SEPARATOR).'/')) { // directory portion of $baseUrl matches return rtrim($prefix, '/'.\DIRECTORY_SEPARATOR); } @@ -1944,7 +1901,7 @@ protected function prepareBaseUrl() $truncatedRequestUri = substr($requestUri, 0, $pos); } - $basename = basename($baseUrl); + $basename = basename($baseUrl ?? ''); if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) { // no match whatsoever; set it blank return ''; @@ -1963,7 +1920,7 @@ protected function prepareBaseUrl() /** * Prepares the base path. * - * @return string base path + * @return string */ protected function prepareBasePath() { @@ -1989,7 +1946,7 @@ protected function prepareBasePath() /** * Prepares the path info. * - * @return string path info + * @return string */ protected function preparePathInfo() { @@ -2005,7 +1962,7 @@ protected function preparePathInfo() $requestUri = '/'.$requestUri; } - if (null === ($baseUrl = $this->getBaseUrl())) { + if (null === ($baseUrl = $this->getBaseUrlReal())) { return $requestUri; } @@ -2015,7 +1972,7 @@ protected function preparePathInfo() return '/'; } - return (string) $pathInfo; + return $pathInfo; } /** @@ -2034,22 +1991,17 @@ protected static function initializeFormats() 'rdf' => ['application/rdf+xml'], 'atom' => ['application/atom+xml'], 'rss' => ['application/rss+xml'], - 'form' => ['application/x-www-form-urlencoded'], + 'form' => ['application/x-www-form-urlencoded', 'multipart/form-data'], ]; } - /** - * Sets the default PHP locale. - * - * @param string $locale - */ - private function setPhpDefaultLocale($locale) + private function setPhpDefaultLocale(string $locale): void { // if either the class Locale doesn't exist, or an exception is thrown when // setting the default locale, the intl module is not installed, and // the call can be ignored: try { - if (class_exists('Locale', false)) { + if (class_exists(\Locale::class, false)) { \Locale::setDefault($locale); } } catch (\Exception $e) { @@ -2058,17 +2010,18 @@ private function setPhpDefaultLocale($locale) /** * Returns the prefix as encoded in the string when the string starts with - * the given prefix, false otherwise. - * - * @param string $string The urlencoded string - * @param string $prefix The prefix not encoded - * - * @return string|false The prefix as it is encoded in $string, or false + * the given prefix, null otherwise. */ - private function getUrlencodedPrefix($string, $prefix) + private function getUrlencodedPrefix(string $string, string $prefix): ?string { - if (0 !== strpos(rawurldecode($string), $prefix)) { - return false; + if ($this->isIisRewrite()) { + // ISS with UrlRewriteModule might report SCRIPT_NAME/PHP_SELF with wrong case + // see https://github.com/php/php-src/issues/11981 + if (0 !== stripos(rawurldecode($string), $prefix)) { + return null; + } + } elseif (!str_starts_with(rawurldecode($string), $prefix)) { + return null; } $len = \strlen($prefix); @@ -2077,13 +2030,13 @@ private function getUrlencodedPrefix($string, $prefix) return $match[0]; } - return false; + return null; } - private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) + private static function createRequestFromFactory(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): self { if (self::$requestFactory) { - $request = \call_user_func(self::$requestFactory, $query, $request, $attributes, $cookies, $files, $server, $content); + $request = (self::$requestFactory)($query, $request, $attributes, $cookies, $files, $server, $content); if (!$request instanceof self) { throw new \LogicException('The Request factory must return an instance of Symfony\Component\HttpFoundation\Request.'); @@ -2101,34 +2054,40 @@ private static function createRequestFromFactory(array $query = [], array $reque * This can be useful to determine whether or not to trust the * contents of a proxy-specific header. * - * @return bool true if the request came from a trusted proxy, false otherwise + * @return bool */ public function isFromTrustedProxy() { - return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies); + return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies); } - private function getTrustedValues($type, $ip = null) + private function getTrustedValues(int $type, string $ip = null): array { $clientValues = []; $forwardedValues = []; - if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) { - foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) { - $clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v); + if ((self::$trustedHeaderSet & $type) && $this->headers->has(self::TRUSTED_HEADERS[$type])) { + foreach (explode(',', $this->headers->get(self::TRUSTED_HEADERS[$type])) as $v) { + $clientValues[] = (self::HEADER_X_FORWARDED_PORT === $type ? '0.0.0.0:' : '').trim($v); } } - if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) { - $forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); - $forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : []; - if (self::HEADER_CLIENT_PORT === $type) { - foreach ($forwardedValues as $k => $v) { - if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) { + if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && (isset(self::FORWARDED_PARAMS[$type])) && $this->headers->has(self::TRUSTED_HEADERS[self::HEADER_FORWARDED])) { + $forwarded = $this->headers->get(self::TRUSTED_HEADERS[self::HEADER_FORWARDED]); + $parts = HeaderUtils::split($forwarded, ',;='); + $forwardedValues = []; + $param = self::FORWARDED_PARAMS[$type]; + foreach ($parts as $subParts) { + if (null === $v = HeaderUtils::combine($subParts)[$param] ?? null) { + continue; + } + if (self::HEADER_X_FORWARDED_PORT === $type) { + if (str_ends_with($v, ']') || false === $v = strrchr($v, ':')) { $v = $this->isSecure() ? ':443' : ':80'; } - $forwardedValues[$k] = '0.0.0.0'.$v; + $v = '0.0.0.0'.$v; } + $forwardedValues[] = $v; } } @@ -2150,10 +2109,10 @@ private function getTrustedValues($type, $ip = null) } $this->isForwardedValid = false; - throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::$trustedHeaders[self::HEADER_FORWARDED], self::$trustedHeaders[$type])); + throw new ConflictingHeadersException(sprintf('The request has both a trusted "%s" header and a trusted "%s" header, conflicting with each other. You should either configure your proxy to remove one of them, or configure your project to distrust the offending one.', self::TRUSTED_HEADERS[self::HEADER_FORWARDED], self::TRUSTED_HEADERS[$type])); } - private function normalizeAndFilterClientIps(array $clientIps, $ip) + private function normalizeAndFilterClientIps(array $clientIps, string $ip): array { if (!$clientIps) { return []; @@ -2169,7 +2128,7 @@ private function normalizeAndFilterClientIps(array $clientIps, $ip) if ($i) { $clientIps[$key] = $clientIp = substr($clientIp, 0, $i); } - } elseif (0 === strpos($clientIp, '[')) { + } elseif (str_starts_with($clientIp, '[')) { // Strip brackets and :port from IPv6 addresses. $i = strpos($clientIp, ']', 1); $clientIps[$key] = $clientIp = substr($clientIp, 1, $i - 1); @@ -2194,4 +2153,20 @@ private function normalizeAndFilterClientIps(array $clientIps, $ip) // Now the IP chain contains only untrusted proxies and the client IP return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp]; } + + /** + * Is this IIS with UrlRewriteModule? + * + * This method consumes, caches and removed the IIS_WasUrlRewritten env var, + * so we don't inherit it to sub-requests. + */ + private function isIisRewrite(): bool + { + if (1 === $this->server->getInt('IIS_WasUrlRewritten')) { + $this->isIisRewrite = true; + $this->server->remove('IIS_WasUrlRewritten'); + } + + return $this->isIisRewrite; + } } diff --git a/vendor/symfony/http-foundation/RequestMatcher.php b/vendor/symfony/http-foundation/RequestMatcher.php index 3f514957..f2645f9a 100644 --- a/vendor/symfony/http-foundation/RequestMatcher.php +++ b/vendor/symfony/http-foundation/RequestMatcher.php @@ -28,6 +28,11 @@ class RequestMatcher implements RequestMatcherInterface */ private $host; + /** + * @var int|null + */ + private $port; + /** * @var string[] */ @@ -49,19 +54,18 @@ class RequestMatcher implements RequestMatcherInterface private $schemes = []; /** - * @param string|null $path - * @param string|null $host * @param string|string[]|null $methods * @param string|string[]|null $ips * @param string|string[]|null $schemes */ - public function __construct($path = null, $host = null, $methods = null, $ips = null, array $attributes = [], $schemes = null) + public function __construct(string $path = null, string $host = null, $methods = null, $ips = null, array $attributes = [], $schemes = null, int $port = null) { $this->matchPath($path); $this->matchHost($host); $this->matchMethod($methods); $this->matchIps($ips); $this->matchScheme($schemes); + $this->matchPort($port); foreach ($attributes as $k => $v) { $this->matchAttribute($k, $v); @@ -80,20 +84,26 @@ public function matchScheme($scheme) /** * Adds a check for the URL host name. - * - * @param string|null $regexp A Regexp */ - public function matchHost($regexp) + public function matchHost(?string $regexp) { $this->host = $regexp; } /** - * Adds a check for the URL path info. + * Adds a check for the the URL port. * - * @param string|null $regexp A Regexp + * @param int|null $port The port number to connect to + */ + public function matchPort(?int $port) + { + $this->port = $port; + } + + /** + * Adds a check for the URL path info. */ - public function matchPath($regexp) + public function matchPath(?string $regexp) { $this->path = $regexp; } @@ -103,7 +113,7 @@ public function matchPath($regexp) * * @param string $ip A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 */ - public function matchIp($ip) + public function matchIp(string $ip) { $this->matchIps($ip); } @@ -115,7 +125,11 @@ public function matchIp($ip) */ public function matchIps($ips) { - $this->ips = null !== $ips ? (array) $ips : []; + $ips = null !== $ips ? (array) $ips : []; + + $this->ips = array_reduce($ips, static function (array $ips, string $ip) { + return array_merge($ips, preg_split('/\s*,\s*/', $ip)); + }, []); } /** @@ -130,11 +144,8 @@ public function matchMethod($method) /** * Adds a check for request attribute. - * - * @param string $key The request attribute name - * @param string $regexp A Regexp */ - public function matchAttribute($key, $regexp) + public function matchAttribute(string $key, string $regexp) { $this->attributes[$key] = $regexp; } @@ -153,7 +164,11 @@ public function matches(Request $request) } foreach ($this->attributes as $key => $pattern) { - if (!preg_match('{'.$pattern.'}', $request->attributes->get($key))) { + $requestAttribute = $request->attributes->get($key); + if (!\is_string($requestAttribute)) { + return false; + } + if (!preg_match('{'.$pattern.'}', $requestAttribute)) { return false; } } @@ -166,7 +181,11 @@ public function matches(Request $request) return false; } - if (IpUtils::checkIp($request->getClientIp(), $this->ips)) { + if (null !== $this->port && 0 < $this->port && $request->getPort() !== $this->port) { + return false; + } + + if (IpUtils::checkIp($request->getClientIp() ?? '', $this->ips)) { return true; } diff --git a/vendor/symfony/http-foundation/RequestMatcherInterface.php b/vendor/symfony/http-foundation/RequestMatcherInterface.php index c26db3e6..c2e14785 100644 --- a/vendor/symfony/http-foundation/RequestMatcherInterface.php +++ b/vendor/symfony/http-foundation/RequestMatcherInterface.php @@ -21,7 +21,7 @@ interface RequestMatcherInterface /** * Decides whether the rule(s) implemented by the strategy matches the supplied request. * - * @return bool true if the request matches, false otherwise + * @return bool */ public function matches(Request $request); } diff --git a/vendor/symfony/http-foundation/RequestStack.php b/vendor/symfony/http-foundation/RequestStack.php index 244a77d6..855b5181 100644 --- a/vendor/symfony/http-foundation/RequestStack.php +++ b/vendor/symfony/http-foundation/RequestStack.php @@ -11,6 +11,9 @@ namespace Symfony\Component\HttpFoundation; +use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException; +use Symfony\Component\HttpFoundation\Session\SessionInterface; + /** * Request stack that controls the lifecycle of requests. * @@ -62,15 +65,13 @@ public function getCurrentRequest() } /** - * Gets the master Request. + * Gets the main request. * - * Be warned that making your code aware of the master request + * Be warned that making your code aware of the main request * might make it un-compatible with other features of your framework * like ESI support. - * - * @return Request|null */ - public function getMasterRequest() + public function getMainRequest(): ?Request { if (!$this->requests) { return null; @@ -79,6 +80,20 @@ public function getMasterRequest() return $this->requests[0]; } + /** + * Gets the master request. + * + * @return Request|null + * + * @deprecated since symfony/http-foundation 5.3, use getMainRequest() instead + */ + public function getMasterRequest() + { + trigger_deprecation('symfony/http-foundation', '5.3', '"%s()" is deprecated, use "getMainRequest()" instead.', __METHOD__); + + return $this->getMainRequest(); + } + /** * Returns the parent request of the current. * @@ -86,7 +101,7 @@ public function getMasterRequest() * might make it un-compatible with other features of your framework * like ESI support. * - * If current Request is the master request, it returns null. + * If current Request is the main request, it returns null. * * @return Request|null */ @@ -94,10 +109,20 @@ public function getParentRequest() { $pos = \count($this->requests) - 2; - if (!isset($this->requests[$pos])) { - return null; + return $this->requests[$pos] ?? null; + } + + /** + * Gets the current session. + * + * @throws SessionNotFoundException + */ + public function getSession(): SessionInterface + { + if ((null !== $request = end($this->requests) ?: null) && $request->hasSession()) { + return $request->getSession(); } - return $this->requests[$pos]; + throw new SessionNotFoundException(); } } diff --git a/vendor/symfony/http-foundation/Response.php b/vendor/symfony/http-foundation/Response.php index 9544a671..23bfb219 100644 --- a/vendor/symfony/http-foundation/Response.php +++ b/vendor/symfony/http-foundation/Response.php @@ -11,6 +11,9 @@ namespace Symfony\Component\HttpFoundation; +// Help opcache.preload discover always-needed symbols +class_exists(ResponseHeaderBag::class); + /** * Response represents an HTTP response. * @@ -18,74 +21,87 @@ */ class Response { - const HTTP_CONTINUE = 100; - const HTTP_SWITCHING_PROTOCOLS = 101; - const HTTP_PROCESSING = 102; // RFC2518 - const HTTP_EARLY_HINTS = 103; // RFC8297 - const HTTP_OK = 200; - const HTTP_CREATED = 201; - const HTTP_ACCEPTED = 202; - const HTTP_NON_AUTHORITATIVE_INFORMATION = 203; - const HTTP_NO_CONTENT = 204; - const HTTP_RESET_CONTENT = 205; - const HTTP_PARTIAL_CONTENT = 206; - const HTTP_MULTI_STATUS = 207; // RFC4918 - const HTTP_ALREADY_REPORTED = 208; // RFC5842 - const HTTP_IM_USED = 226; // RFC3229 - const HTTP_MULTIPLE_CHOICES = 300; - const HTTP_MOVED_PERMANENTLY = 301; - const HTTP_FOUND = 302; - const HTTP_SEE_OTHER = 303; - const HTTP_NOT_MODIFIED = 304; - const HTTP_USE_PROXY = 305; - const HTTP_RESERVED = 306; - const HTTP_TEMPORARY_REDIRECT = 307; - const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238 - const HTTP_BAD_REQUEST = 400; - const HTTP_UNAUTHORIZED = 401; - const HTTP_PAYMENT_REQUIRED = 402; - const HTTP_FORBIDDEN = 403; - const HTTP_NOT_FOUND = 404; - const HTTP_METHOD_NOT_ALLOWED = 405; - const HTTP_NOT_ACCEPTABLE = 406; - const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; - const HTTP_REQUEST_TIMEOUT = 408; - const HTTP_CONFLICT = 409; - const HTTP_GONE = 410; - const HTTP_LENGTH_REQUIRED = 411; - const HTTP_PRECONDITION_FAILED = 412; - const HTTP_REQUEST_ENTITY_TOO_LARGE = 413; - const HTTP_REQUEST_URI_TOO_LONG = 414; - const HTTP_UNSUPPORTED_MEDIA_TYPE = 415; - const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; - const HTTP_EXPECTATION_FAILED = 417; - const HTTP_I_AM_A_TEAPOT = 418; // RFC2324 - const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540 - const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918 - const HTTP_LOCKED = 423; // RFC4918 - const HTTP_FAILED_DEPENDENCY = 424; // RFC4918 - - /** - * @deprecated - */ - const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817 - const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04 - const HTTP_UPGRADE_REQUIRED = 426; // RFC2817 - const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585 - const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585 - const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585 - const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; - const HTTP_INTERNAL_SERVER_ERROR = 500; - const HTTP_NOT_IMPLEMENTED = 501; - const HTTP_BAD_GATEWAY = 502; - const HTTP_SERVICE_UNAVAILABLE = 503; - const HTTP_GATEWAY_TIMEOUT = 504; - const HTTP_VERSION_NOT_SUPPORTED = 505; - const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295 - const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918 - const HTTP_LOOP_DETECTED = 508; // RFC5842 - const HTTP_NOT_EXTENDED = 510; // RFC2774 - const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585 + public const HTTP_CONTINUE = 100; + public const HTTP_SWITCHING_PROTOCOLS = 101; + public const HTTP_PROCESSING = 102; // RFC2518 + public const HTTP_EARLY_HINTS = 103; // RFC8297 + public const HTTP_OK = 200; + public const HTTP_CREATED = 201; + public const HTTP_ACCEPTED = 202; + public const HTTP_NON_AUTHORITATIVE_INFORMATION = 203; + public const HTTP_NO_CONTENT = 204; + public const HTTP_RESET_CONTENT = 205; + public const HTTP_PARTIAL_CONTENT = 206; + public const HTTP_MULTI_STATUS = 207; // RFC4918 + public const HTTP_ALREADY_REPORTED = 208; // RFC5842 + public const HTTP_IM_USED = 226; // RFC3229 + public const HTTP_MULTIPLE_CHOICES = 300; + public const HTTP_MOVED_PERMANENTLY = 301; + public const HTTP_FOUND = 302; + public const HTTP_SEE_OTHER = 303; + public const HTTP_NOT_MODIFIED = 304; + public const HTTP_USE_PROXY = 305; + public const HTTP_RESERVED = 306; + public const HTTP_TEMPORARY_REDIRECT = 307; + public const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238 + public const HTTP_BAD_REQUEST = 400; + public const HTTP_UNAUTHORIZED = 401; + public const HTTP_PAYMENT_REQUIRED = 402; + public const HTTP_FORBIDDEN = 403; + public const HTTP_NOT_FOUND = 404; + public const HTTP_METHOD_NOT_ALLOWED = 405; + public const HTTP_NOT_ACCEPTABLE = 406; + public const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407; + public const HTTP_REQUEST_TIMEOUT = 408; + public const HTTP_CONFLICT = 409; + public const HTTP_GONE = 410; + public const HTTP_LENGTH_REQUIRED = 411; + public const HTTP_PRECONDITION_FAILED = 412; + public const HTTP_REQUEST_ENTITY_TOO_LARGE = 413; + public const HTTP_REQUEST_URI_TOO_LONG = 414; + public const HTTP_UNSUPPORTED_MEDIA_TYPE = 415; + public const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + public const HTTP_EXPECTATION_FAILED = 417; + public const HTTP_I_AM_A_TEAPOT = 418; // RFC2324 + public const HTTP_MISDIRECTED_REQUEST = 421; // RFC7540 + public const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918 + public const HTTP_LOCKED = 423; // RFC4918 + public const HTTP_FAILED_DEPENDENCY = 424; // RFC4918 + public const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04 + public const HTTP_UPGRADE_REQUIRED = 426; // RFC2817 + public const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585 + public const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585 + public const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585 + public const HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451; // RFC7725 + public const HTTP_INTERNAL_SERVER_ERROR = 500; + public const HTTP_NOT_IMPLEMENTED = 501; + public const HTTP_BAD_GATEWAY = 502; + public const HTTP_SERVICE_UNAVAILABLE = 503; + public const HTTP_GATEWAY_TIMEOUT = 504; + public const HTTP_VERSION_NOT_SUPPORTED = 505; + public const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295 + public const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918 + public const HTTP_LOOP_DETECTED = 508; // RFC5842 + public const HTTP_NOT_EXTENDED = 510; // RFC2774 + public const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511; // RFC6585 + + /** + * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + */ + private const HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES = [ + 'must_revalidate' => false, + 'no_cache' => false, + 'no_store' => false, + 'no_transform' => false, + 'public' => false, + 'private' => false, + 'proxy_revalidate' => false, + 'max_age' => true, + 's_maxage' => true, + 'immutable' => false, + 'last_modified' => true, + 'etag' => true, + ]; /** * @var ResponseHeaderBag @@ -122,7 +138,7 @@ class Response * * The list of codes is complete according to the * {@link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml Hypertext Transfer Protocol (HTTP) Status Code Registry} - * (last updated 2016-03-01). + * (last updated 2021-10-01). * * Unless otherwise noted, the status code is defined in RFC2616. * @@ -164,14 +180,14 @@ class Response 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', - 413 => 'Payload Too Large', + 413 => 'Content Too Large', // RFC-ietf-httpbis-semantics 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', // RFC2324 421 => 'Misdirected Request', // RFC7540 - 422 => 'Unprocessable Entity', // RFC4918 + 422 => 'Unprocessable Content', // RFC-ietf-httpbis-semantics 423 => 'Locked', // RFC4918 424 => 'Failed Dependency', // RFC4918 425 => 'Too Early', // RFC-ietf-httpbis-replay-04 @@ -194,13 +210,9 @@ class Response ]; /** - * @param mixed $content The response content, see setContent() - * @param int $status The response status code - * @param array $headers An array of response headers - * * @throws \InvalidArgumentException When the HTTP status code is not valid */ - public function __construct($content = '', $status = 200, $headers = []) + public function __construct(?string $content = '', int $status = 200, array $headers = []) { $this->headers = new ResponseHeaderBag($headers); $this->setContent($content); @@ -216,14 +228,14 @@ public function __construct($content = '', $status = 200, $headers = []) * return Response::create($body, 200) * ->setSharedMaxAge(300); * - * @param mixed $content The response content, see setContent() - * @param int $status The response status code - * @param array $headers An array of response headers - * * @return static + * + * @deprecated since Symfony 5.1, use __construct() instead. */ - public static function create($content = '', $status = 200, $headers = []) + public static function create(?string $content = '', int $status = 200, array $headers = []) { + trigger_deprecation('symfony/http-foundation', '5.1', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class); + return new static($content, $status, $headers); } @@ -234,7 +246,7 @@ public static function create($content = '', $status = 200, $headers = []) * one that will be sent to the client only if the prepare() method * has been called before. * - * @return string The Response as an HTTP string + * @return string * * @see prepare() */ @@ -271,10 +283,12 @@ public function prepare(Request $request) $this->setContent(null); $headers->remove('Content-Type'); $headers->remove('Content-Length'); + // prevent PHP from sending the Content-Type header based on default_mimetype + ini_set('default_mimetype', ''); } else { // Content-type based on the Request if (!$headers->has('Content-Type')) { - $format = $request->getRequestFormat(); + $format = $request->getRequestFormat(null); if (null !== $format && $mimeType = $request->getMimeType($format)) { $headers->set('Content-Type', $mimeType); } @@ -284,7 +298,7 @@ public function prepare(Request $request) $charset = $this->charset ?: 'UTF-8'; if (!$headers->has('Content-Type')) { $headers->set('Content-Type', 'text/html; charset='.$charset); - } elseif (0 === stripos($headers->get('Content-Type'), 'text/') && false === stripos($headers->get('Content-Type'), 'charset')) { + } elseif (0 === stripos($headers->get('Content-Type') ?? '', 'text/') && false === stripos($headers->get('Content-Type') ?? '', 'charset')) { // add the charset $headers->set('Content-Type', $headers->get('Content-Type').'; charset='.$charset); } @@ -310,13 +324,19 @@ public function prepare(Request $request) } // Check if we need to send extra expire info headers - if ('1.0' == $this->getProtocolVersion() && false !== strpos($headers->get('Cache-Control'), 'no-cache')) { + if ('1.0' == $this->getProtocolVersion() && str_contains($headers->get('Cache-Control', ''), 'no-cache')) { $headers->set('pragma', 'no-cache'); $headers->set('expires', -1); } $this->ensureIEOverSSLCompatibility($request); + if ($request->isSecure()) { + foreach ($headers->getCookies() as $cookie) { + $cookie->setSecureDefault(true); + } + } + return $this; } @@ -375,8 +395,11 @@ public function send() if (\function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); + } elseif (\function_exists('litespeed_finish_request')) { + litespeed_finish_request(); } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { static::closeOutputBuffers(0, true); + flush(); } return $this; @@ -385,21 +408,11 @@ public function send() /** * Sets the response content. * - * Valid types are strings, numbers, null, and objects that implement a __toString() method. - * - * @param mixed $content Content that can be cast to string - * * @return $this - * - * @throws \UnexpectedValueException */ - public function setContent($content) + public function setContent(?string $content) { - if (null !== $content && !\is_string($content) && !is_numeric($content) && !\is_callable([$content, '__toString'])) { - throw new \UnexpectedValueException(sprintf('The Response content must be a string or object implementing __toString(), "%s" given.', \gettype($content))); - } - - $this->content = (string) $content; + $this->content = $content ?? ''; return $this; } @@ -417,13 +430,11 @@ public function getContent() /** * Sets the HTTP protocol version (1.0 or 1.1). * - * @param string $version The HTTP protocol version - * * @return $this * - * @final since version 3.2 + * @final */ - public function setProtocolVersion($version) + public function setProtocolVersion(string $version): object { $this->version = $version; @@ -433,11 +444,9 @@ public function setProtocolVersion($version) /** * Gets the HTTP protocol version. * - * @return string The HTTP protocol version - * - * @final since version 3.2 + * @final */ - public function getProtocolVersion() + public function getProtocolVersion(): string { return $this->version; } @@ -448,24 +457,21 @@ public function getProtocolVersion() * If the status text is null it will be automatically populated for the known * status codes and left empty otherwise. * - * @param int $code HTTP status code - * @param mixed $text HTTP status text - * * @return $this * * @throws \InvalidArgumentException When the HTTP status code is not valid * - * @final since version 3.2 + * @final */ - public function setStatusCode($code, $text = null) + public function setStatusCode(int $code, string $text = null): object { - $this->statusCode = $code = (int) $code; + $this->statusCode = $code; if ($this->isInvalid()) { throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); } if (null === $text) { - $this->statusText = isset(self::$statusTexts[$code]) ? self::$statusTexts[$code] : 'unknown status'; + $this->statusText = self::$statusTexts[$code] ?? 'unknown status'; return $this; } @@ -484,11 +490,9 @@ public function setStatusCode($code, $text = null) /** * Retrieves the status code for the current web response. * - * @return int Status code - * - * @final since version 3.2 + * @final */ - public function getStatusCode() + public function getStatusCode(): int { return $this->statusCode; } @@ -496,13 +500,11 @@ public function getStatusCode() /** * Sets the response charset. * - * @param string $charset Character set - * * @return $this * - * @final since version 3.2 + * @final */ - public function setCharset($charset) + public function setCharset(string $charset): object { $this->charset = $charset; @@ -512,11 +514,9 @@ public function setCharset($charset) /** * Retrieves the response charset. * - * @return string Character set - * - * @final since version 3.2 + * @final */ - public function getCharset() + public function getCharset(): ?string { return $this->charset; } @@ -536,11 +536,9 @@ public function getCharset() * can be reused by a cache with heuristic expiration unless otherwise indicated" * (https://tools.ietf.org/html/rfc7231#section-6.1) * - * @return bool true if the response is worth caching, false otherwise - * - * @final since version 3.3 + * @final */ - public function isCacheable() + public function isCacheable(): bool { if (!\in_array($this->statusCode, [200, 203, 300, 301, 302, 404, 410])) { return false; @@ -560,11 +558,9 @@ public function isCacheable() * origin. A response is considered fresh when it includes a Cache-Control/max-age * indicator or Expires header and the calculated age is less than the freshness lifetime. * - * @return bool true if the response is fresh, false otherwise - * - * @final since version 3.3 + * @final */ - public function isFresh() + public function isFresh(): bool { return $this->getTtl() > 0; } @@ -573,11 +569,9 @@ public function isFresh() * Returns true if the response includes headers that can be used to validate * the response with the origin server using a conditional GET request. * - * @return bool true if the response is validateable, false otherwise - * - * @final since version 3.3 + * @final */ - public function isValidateable() + public function isValidateable(): bool { return $this->headers->has('Last-Modified') || $this->headers->has('ETag'); } @@ -589,9 +583,9 @@ public function isValidateable() * * @return $this * - * @final since version 3.2 + * @final */ - public function setPrivate() + public function setPrivate(): object { $this->headers->removeCacheControlDirective('public'); $this->headers->addCacheControlDirective('private'); @@ -606,9 +600,9 @@ public function setPrivate() * * @return $this * - * @final since version 3.2 + * @final */ - public function setPublic() + public function setPublic(): object { $this->headers->addCacheControlDirective('public'); $this->headers->removeCacheControlDirective('private'); @@ -619,13 +613,11 @@ public function setPublic() /** * Marks the response as "immutable". * - * @param bool $immutable enables or disables the immutable directive - * * @return $this * * @final */ - public function setImmutable($immutable = true) + public function setImmutable(bool $immutable = true): object { if ($immutable) { $this->headers->addCacheControlDirective('immutable'); @@ -639,11 +631,9 @@ public function setImmutable($immutable = true) /** * Returns true if the response is marked as "immutable". * - * @return bool returns true if the response is marked as "immutable"; otherwise false - * * @final */ - public function isImmutable() + public function isImmutable(): bool { return $this->headers->hasCacheControlDirective('immutable'); } @@ -656,11 +646,9 @@ public function isImmutable() * When present, the TTL of the response should not be overridden to be * greater than the value provided by the origin. * - * @return bool true if the response must be revalidated by a cache, false otherwise - * - * @final since version 3.3 + * @final */ - public function mustRevalidate() + public function mustRevalidate(): bool { return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate'); } @@ -668,13 +656,11 @@ public function mustRevalidate() /** * Returns the Date header as a DateTime instance. * - * @return \DateTime A \DateTime instance - * * @throws \RuntimeException When the header is not parseable * - * @final since version 3.2 + * @final */ - public function getDate() + public function getDate(): ?\DateTimeInterface { return $this->headers->getDate('Date'); } @@ -684,24 +670,26 @@ public function getDate() * * @return $this * - * @final since version 3.2 + * @final */ - public function setDate(\DateTime $date) + public function setDate(\DateTimeInterface $date): object { - $date->setTimezone(new \DateTimeZone('UTC')); + if ($date instanceof \DateTime) { + $date = \DateTimeImmutable::createFromMutable($date); + } + + $date = $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT'); return $this; } /** - * Returns the age of the response. - * - * @return int The age of the response in seconds + * Returns the age of the response in seconds. * - * @final since version 3.2 + * @final */ - public function getAge() + public function getAge(): int { if (null !== $age = $this->headers->get('Age')) { return (int) $age; @@ -728,17 +716,15 @@ public function expire() /** * Returns the value of the Expires header as a DateTime instance. * - * @return \DateTime|null A DateTime instance or null if the header does not exist - * - * @final since version 3.2 + * @final */ - public function getExpires() + public function getExpires(): ?\DateTimeInterface { try { return $this->headers->getDate('Expires'); } catch (\RuntimeException $e) { // according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past - return \DateTime::createFromFormat(\DATE_RFC2822, 'Sat, 01 Jan 00 00:00:00 +0000'); + return \DateTime::createFromFormat('U', time() - 172800); } } @@ -747,22 +733,25 @@ public function getExpires() * * Passing null as value will remove the header. * - * @param \DateTime|null $date A \DateTime instance or null to remove the header - * * @return $this * - * @final since version 3.2 + * @final */ - public function setExpires(\DateTime $date = null) + public function setExpires(\DateTimeInterface $date = null): object { if (null === $date) { $this->headers->remove('Expires'); - } else { - $date = clone $date; - $date->setTimezone(new \DateTimeZone('UTC')); - $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); + + return $this; } + if ($date instanceof \DateTime) { + $date = \DateTimeImmutable::createFromMutable($date); + } + + $date = $date->setTimezone(new \DateTimeZone('UTC')); + $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); + return $this; } @@ -773,11 +762,9 @@ public function setExpires(\DateTime $date = null) * First, it checks for a s-maxage directive, then a max-age directive, and then it falls * back on an expires header. It returns null when no maximum age can be established. * - * @return int|null Number of seconds - * - * @final since version 3.2 + * @final */ - public function getMaxAge() + public function getMaxAge(): ?int { if ($this->headers->hasCacheControlDirective('s-maxage')) { return (int) $this->headers->getCacheControlDirective('s-maxage'); @@ -787,8 +774,10 @@ public function getMaxAge() return (int) $this->headers->getCacheControlDirective('max-age'); } - if (null !== $this->getExpires()) { - return (int) $this->getExpires()->format('U') - (int) $this->getDate()->format('U'); + if (null !== $expires = $this->getExpires()) { + $maxAge = (int) $expires->format('U') - (int) $this->getDate()->format('U'); + + return max($maxAge, 0); } return null; @@ -799,13 +788,11 @@ public function getMaxAge() * * This methods sets the Cache-Control max-age directive. * - * @param int $value Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setMaxAge($value) + public function setMaxAge(int $value): object { $this->headers->addCacheControlDirective('max-age', $value); @@ -817,13 +804,11 @@ public function setMaxAge($value) * * This methods sets the Cache-Control s-maxage directive. * - * @param int $value Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setSharedMaxAge($value) + public function setSharedMaxAge(int $value): object { $this->setPublic(); $this->headers->addCacheControlDirective('s-maxage', $value); @@ -836,34 +821,28 @@ public function setSharedMaxAge($value) * * It returns null when no freshness information is present in the response. * - * When the responses TTL is <= 0, the response may not be served from cache without first + * When the response's TTL is 0, the response may not be served from cache without first * revalidating with the origin. * - * @return int|null The TTL in seconds - * - * @final since version 3.2 + * @final */ - public function getTtl() + public function getTtl(): ?int { - if (null !== $maxAge = $this->getMaxAge()) { - return $maxAge - $this->getAge(); - } + $maxAge = $this->getMaxAge(); - return null; + return null !== $maxAge ? max($maxAge - $this->getAge(), 0) : null; } /** - * Sets the response's time-to-live for shared caches. + * Sets the response's time-to-live for shared caches in seconds. * * This method adjusts the Cache-Control/s-maxage directive. * - * @param int $seconds Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setTtl($seconds) + public function setTtl(int $seconds): object { $this->setSharedMaxAge($this->getAge() + $seconds); @@ -871,17 +850,15 @@ public function setTtl($seconds) } /** - * Sets the response's time-to-live for private/client caches. + * Sets the response's time-to-live for private/client caches in seconds. * * This method adjusts the Cache-Control/max-age directive. * - * @param int $seconds Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setClientTtl($seconds) + public function setClientTtl(int $seconds): object { $this->setMaxAge($this->getAge() + $seconds); @@ -891,13 +868,11 @@ public function setClientTtl($seconds) /** * Returns the Last-Modified HTTP header as a DateTime instance. * - * @return \DateTime|null A DateTime instance or null if the header does not exist - * * @throws \RuntimeException When the HTTP header is not parseable * - * @final since version 3.2 + * @final */ - public function getLastModified() + public function getLastModified(): ?\DateTimeInterface { return $this->headers->getDate('Last-Modified'); } @@ -907,33 +882,34 @@ public function getLastModified() * * Passing null as value will remove the header. * - * @param \DateTime|null $date A \DateTime instance or null to remove the header - * * @return $this * - * @final since version 3.2 + * @final */ - public function setLastModified(\DateTime $date = null) + public function setLastModified(\DateTimeInterface $date = null): object { if (null === $date) { $this->headers->remove('Last-Modified'); - } else { - $date = clone $date; - $date->setTimezone(new \DateTimeZone('UTC')); - $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); + + return $this; + } + + if ($date instanceof \DateTime) { + $date = \DateTimeImmutable::createFromMutable($date); } + $date = $date->setTimezone(new \DateTimeZone('UTC')); + $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); + return $this; } /** * Returns the literal value of the ETag HTTP header. * - * @return string|null The ETag HTTP header or null if it does not exist - * - * @final since version 3.2 + * @final */ - public function getEtag() + public function getEtag(): ?string { return $this->headers->get('ETag'); } @@ -946,14 +922,14 @@ public function getEtag() * * @return $this * - * @final since version 3.2 + * @final */ - public function setEtag($etag = null, $weak = false) + public function setEtag(string $etag = null, bool $weak = false): object { if (null === $etag) { $this->headers->remove('Etag'); } else { - if (0 !== strpos($etag, '"')) { + if (!str_starts_with($etag, '"')) { $etag = '"'.$etag.'"'; } @@ -966,19 +942,17 @@ public function setEtag($etag = null, $weak = false) /** * Sets the response's cache headers (validation and/or expiration). * - * Available options are: etag, last_modified, max_age, s_maxage, private, public and immutable. - * - * @param array $options An array of cache options + * Available options are: must_revalidate, no_cache, no_store, no_transform, public, private, proxy_revalidate, max_age, s_maxage, immutable, last_modified and etag. * * @return $this * * @throws \InvalidArgumentException * - * @final since version 3.3 + * @final */ - public function setCache(array $options) + public function setCache(array $options): object { - if ($diff = array_diff(array_keys($options), ['etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public', 'immutable'])) { + if ($diff = array_diff(array_keys($options), array_keys(self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES))) { throw new \InvalidArgumentException(sprintf('Response does not support the following options: "%s".', implode('", "', $diff))); } @@ -998,6 +972,16 @@ public function setCache(array $options) $this->setSharedMaxAge($options['s_maxage']); } + foreach (self::HTTP_RESPONSE_CACHE_CONTROL_DIRECTIVES as $directive => $hasValue) { + if (!$hasValue && isset($options[$directive])) { + if ($options[$directive]) { + $this->headers->addCacheControlDirective(str_replace('_', '-', $directive)); + } else { + $this->headers->removeCacheControlDirective(str_replace('_', '-', $directive)); + } + } + } + if (isset($options['public'])) { if ($options['public']) { $this->setPublic(); @@ -1014,10 +998,6 @@ public function setCache(array $options) } } - if (isset($options['immutable'])) { - $this->setImmutable((bool) $options['immutable']); - } - return $this; } @@ -1031,9 +1011,9 @@ public function setCache(array $options) * * @see https://tools.ietf.org/html/rfc2616#section-10.3.5 * - * @final since version 3.3 + * @final */ - public function setNotModified() + public function setNotModified(): object { $this->setStatusCode(304); $this->setContent(null); @@ -1049,11 +1029,9 @@ public function setNotModified() /** * Returns true if the response includes a Vary header. * - * @return bool true if the response includes a Vary header, false otherwise - * - * @final since version 3.2 + * @final */ - public function hasVary() + public function hasVary(): bool { return null !== $this->headers->get('Vary'); } @@ -1061,22 +1039,20 @@ public function hasVary() /** * Returns an array of header names given in the Vary header. * - * @return array An array of Vary names - * - * @final since version 3.2 + * @final */ - public function getVary() + public function getVary(): array { - if (!$vary = $this->headers->get('Vary', null, false)) { + if (!$vary = $this->headers->all('Vary')) { return []; } $ret = []; foreach ($vary as $item) { - $ret = array_merge($ret, preg_split('/[\s,]+/', $item)); + $ret[] = preg_split('/[\s,]+/', $item); } - return $ret; + return array_merge([], ...$ret); } /** @@ -1087,9 +1063,9 @@ public function getVary() * * @return $this * - * @final since version 3.2 + * @final */ - public function setVary($headers, $replace = true) + public function setVary($headers, bool $replace = true): object { $this->headers->set('Vary', $headers, $replace); @@ -1103,11 +1079,9 @@ public function setVary($headers, $replace = true) * If the Response is not modified, it sets the status code to 304 and * removes the actual content by calling the setNotModified() method. * - * @return bool true if the Response validators match the Request, false otherwise - * - * @final since version 3.3 + * @final */ - public function isNotModified(Request $request) + public function isNotModified(Request $request): bool { if (!$request->isMethodCacheable()) { return false; @@ -1117,12 +1091,26 @@ public function isNotModified(Request $request) $lastModified = $this->headers->get('Last-Modified'); $modifiedSince = $request->headers->get('If-Modified-Since'); - if ($etags = $request->getETags()) { - $notModified = \in_array($this->getEtag(), $etags) || \in_array('*', $etags); - } + if (($ifNoneMatchEtags = $request->getETags()) && (null !== $etag = $this->getEtag())) { + if (0 == strncmp($etag, 'W/', 2)) { + $etag = substr($etag, 2); + } - if ($modifiedSince && $lastModified) { - $notModified = strtotime($modifiedSince) >= strtotime($lastModified) && (!$etags || $notModified); + // Use weak comparison as per https://tools.ietf.org/html/rfc7232#section-3.2. + foreach ($ifNoneMatchEtags as $ifNoneMatchEtag) { + if (0 == strncmp($ifNoneMatchEtag, 'W/', 2)) { + $ifNoneMatchEtag = substr($ifNoneMatchEtag, 2); + } + + if ($ifNoneMatchEtag === $etag || '*' === $ifNoneMatchEtag) { + $notModified = true; + break; + } + } + } + // Only do If-Modified-Since date comparison when If-None-Match is not present as per https://tools.ietf.org/html/rfc7232#section-3.3. + elseif ($modifiedSince && $lastModified) { + $notModified = strtotime($modifiedSince) >= strtotime($lastModified); } if ($notModified) { @@ -1135,13 +1123,11 @@ public function isNotModified(Request $request) /** * Is response invalid? * - * @return bool - * * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html * - * @final since version 3.2 + * @final */ - public function isInvalid() + public function isInvalid(): bool { return $this->statusCode < 100 || $this->statusCode >= 600; } @@ -1149,11 +1135,9 @@ public function isInvalid() /** * Is response informative? * - * @return bool - * - * @final since version 3.3 + * @final */ - public function isInformational() + public function isInformational(): bool { return $this->statusCode >= 100 && $this->statusCode < 200; } @@ -1161,11 +1145,9 @@ public function isInformational() /** * Is response successful? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isSuccessful() + public function isSuccessful(): bool { return $this->statusCode >= 200 && $this->statusCode < 300; } @@ -1173,11 +1155,9 @@ public function isSuccessful() /** * Is the response a redirect? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isRedirection() + public function isRedirection(): bool { return $this->statusCode >= 300 && $this->statusCode < 400; } @@ -1185,11 +1165,9 @@ public function isRedirection() /** * Is there a client error? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isClientError() + public function isClientError(): bool { return $this->statusCode >= 400 && $this->statusCode < 500; } @@ -1197,11 +1175,9 @@ public function isClientError() /** * Was there a server side error? * - * @return bool - * - * @final since version 3.3 + * @final */ - public function isServerError() + public function isServerError(): bool { return $this->statusCode >= 500 && $this->statusCode < 600; } @@ -1209,11 +1185,9 @@ public function isServerError() /** * Is the response OK? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isOk() + public function isOk(): bool { return 200 === $this->statusCode; } @@ -1221,11 +1195,9 @@ public function isOk() /** * Is the response forbidden? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isForbidden() + public function isForbidden(): bool { return 403 === $this->statusCode; } @@ -1233,11 +1205,9 @@ public function isForbidden() /** * Is the response a not found error? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isNotFound() + public function isNotFound(): bool { return 404 === $this->statusCode; } @@ -1245,13 +1215,9 @@ public function isNotFound() /** * Is the response a redirect of some form? * - * @param string $location - * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isRedirect($location = null) + public function isRedirect(string $location = null): bool { return \in_array($this->statusCode, [201, 301, 302, 303, 307, 308]) && (null === $location ?: $location == $this->headers->get('Location')); } @@ -1259,11 +1225,9 @@ public function isRedirect($location = null) /** * Is the response empty? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isEmpty() + public function isEmpty(): bool { return \in_array($this->statusCode, [204, 304]); } @@ -1273,17 +1237,13 @@ public function isEmpty() * * Resulting level can be greater than target level if a non-removable buffer has been encountered. * - * @param int $targetLevel The target output buffering level - * @param bool $flush Whether to flush or clean the buffers - * - * @final since version 3.3 + * @final */ - public static function closeOutputBuffers($targetLevel, $flush) + public static function closeOutputBuffers(int $targetLevel, bool $flush): void { $status = ob_get_status(true); $level = \count($status); - // PHP_OUTPUT_HANDLER_* are not defined on HHVM 3.3 - $flags = \defined('PHP_OUTPUT_HANDLER_REMOVABLE') ? \PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? \PHP_OUTPUT_HANDLER_FLUSHABLE : \PHP_OUTPUT_HANDLER_CLEANABLE) : -1; + $flags = \PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? \PHP_OUTPUT_HANDLER_FLUSHABLE : \PHP_OUTPUT_HANDLER_CLEANABLE); while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) { if ($flush) { @@ -1294,16 +1254,32 @@ public static function closeOutputBuffers($targetLevel, $flush) } } + /** + * Marks a response as safe according to RFC8674. + * + * @see https://tools.ietf.org/html/rfc8674 + */ + public function setContentSafe(bool $safe = true): void + { + if ($safe) { + $this->headers->set('Preference-Applied', 'safe'); + } elseif ('safe' === $this->headers->get('Preference-Applied')) { + $this->headers->remove('Preference-Applied'); + } + + $this->setVary('Prefer', false); + } + /** * Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9. * * @see http://support.microsoft.com/kb/323308 * - * @final since version 3.3 + * @final */ - protected function ensureIEOverSSLCompatibility(Request $request) + protected function ensureIEOverSSLCompatibility(Request $request): void { - if (false !== stripos($this->headers->get('Content-Disposition'), 'attachment') && 1 == preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT'), $match) && true === $request->isSecure()) { + if (false !== stripos($this->headers->get('Content-Disposition') ?? '', 'attachment') && 1 == preg_match('/MSIE (.*?);/i', $request->server->get('HTTP_USER_AGENT') ?? '', $match) && true === $request->isSecure()) { if ((int) preg_replace('/(MSIE )(.*?);/', '$2', $match[0]) < 9) { $this->headers->remove('Cache-Control'); } diff --git a/vendor/symfony/http-foundation/ResponseHeaderBag.php b/vendor/symfony/http-foundation/ResponseHeaderBag.php index 9a6f8764..1df13fa2 100644 --- a/vendor/symfony/http-foundation/ResponseHeaderBag.php +++ b/vendor/symfony/http-foundation/ResponseHeaderBag.php @@ -18,11 +18,11 @@ */ class ResponseHeaderBag extends HeaderBag { - const COOKIES_FLAT = 'flat'; - const COOKIES_ARRAY = 'array'; + public const COOKIES_FLAT = 'flat'; + public const COOKIES_ARRAY = 'array'; - const DISPOSITION_ATTACHMENT = 'attachment'; - const DISPOSITION_INLINE = 'inline'; + public const DISPOSITION_ATTACHMENT = 'attachment'; + public const DISPOSITION_INLINE = 'inline'; protected $computedCacheControl = []; protected $cookies = []; @@ -45,13 +45,13 @@ public function __construct(array $headers = []) /** * Returns the headers, with original capitalizations. * - * @return array An array of headers + * @return array */ public function allPreserveCase() { $headers = []; foreach ($this->all() as $name => $value) { - $headers[isset($this->headerNames[$name]) ? $this->headerNames[$name] : $name] = $value; + $headers[$this->headerNames[$name] ?? $name] = $value; } return $headers; @@ -88,9 +88,16 @@ public function replace(array $headers = []) /** * {@inheritdoc} */ - public function all() + public function all(string $key = null) { $headers = parent::all(); + + if (null !== $key) { + $key = strtr($key, self::UPPER, self::LOWER); + + return 'set-cookie' !== $key ? $headers[$key] ?? [] : array_map('strval', $this->getCookies()); + } + foreach ($this->getCookies() as $cookie) { $headers['set-cookie'][] = (string) $cookie; } @@ -101,9 +108,9 @@ public function all() /** * {@inheritdoc} */ - public function set($key, $values, $replace = true) + public function set(string $key, $values, bool $replace = true) { - $uniqueKey = str_replace('_', '-', strtolower($key)); + $uniqueKey = strtr($key, self::UPPER, self::LOWER); if ('set-cookie' === $uniqueKey) { if ($replace) { @@ -122,8 +129,7 @@ public function set($key, $values, $replace = true) parent::set($key, $values, $replace); // ensure the cache-control header has sensible defaults - if (\in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'], true)) { - $computed = $this->computeCacheControlValue(); + if (\in_array($uniqueKey, ['cache-control', 'etag', 'last-modified', 'expires'], true) && '' !== $computed = $this->computeCacheControlValue()) { $this->headers['cache-control'] = [$computed]; $this->headerNames['cache-control'] = 'Cache-Control'; $this->computedCacheControl = $this->parseCacheControl($computed); @@ -133,9 +139,9 @@ public function set($key, $values, $replace = true) /** * {@inheritdoc} */ - public function remove($key) + public function remove(string $key) { - $uniqueKey = str_replace('_', '-', strtolower($key)); + $uniqueKey = strtr($key, self::UPPER, self::LOWER); unset($this->headerNames[$uniqueKey]); if ('set-cookie' === $uniqueKey) { @@ -158,7 +164,7 @@ public function remove($key) /** * {@inheritdoc} */ - public function hasCacheControlDirective($key) + public function hasCacheControlDirective(string $key) { return \array_key_exists($key, $this->computedCacheControl); } @@ -166,9 +172,9 @@ public function hasCacheControlDirective($key) /** * {@inheritdoc} */ - public function getCacheControlDirective($key) + public function getCacheControlDirective(string $key) { - return \array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null; + return $this->computedCacheControl[$key] ?? null; } public function setCookie(Cookie $cookie) @@ -179,12 +185,8 @@ public function setCookie(Cookie $cookie) /** * Removes a cookie from the array, but does not unset it in the browser. - * - * @param string $name - * @param string $path - * @param string $domain */ - public function removeCookie($name, $path = '/', $domain = null) + public function removeCookie(string $name, ?string $path = '/', string $domain = null) { if (null === $path) { $path = '/'; @@ -208,13 +210,11 @@ public function removeCookie($name, $path = '/', $domain = null) /** * Returns an array with all cookies. * - * @param string $format - * * @return Cookie[] * * @throws \InvalidArgumentException When the $format is invalid */ - public function getCookies($format = self::COOKIES_FLAT) + public function getCookies(string $format = self::COOKIES_FLAT) { if (!\in_array($format, [self::COOKIES_FLAT, self::COOKIES_ARRAY])) { throw new \InvalidArgumentException(sprintf('Format "%s" invalid (%s).', $format, implode(', ', [self::COOKIES_FLAT, self::COOKIES_ARRAY]))); @@ -238,68 +238,18 @@ public function getCookies($format = self::COOKIES_FLAT) /** * Clears a cookie in the browser. - * - * @param string $name - * @param string $path - * @param string $domain - * @param bool $secure - * @param bool $httpOnly - * @param string $sameSite */ - public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true/*, $sameSite = null*/) + public function clearCookie(string $name, ?string $path = '/', string $domain = null, bool $secure = false, bool $httpOnly = true, string $sameSite = null) { - $sameSite = \func_num_args() > 5 ? func_get_arg(5) : null; - $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, $sameSite)); } /** - * Generates a HTTP Content-Disposition field-value. - * - * @param string $disposition One of "inline" or "attachment" - * @param string $filename A unicode string - * @param string $filenameFallback A string containing only ASCII characters that - * is semantically equivalent to $filename. If the filename is already ASCII, - * it can be omitted, or just copied from $filename - * - * @return string A string suitable for use as a Content-Disposition field-value - * - * @throws \InvalidArgumentException - * - * @see RFC 6266 + * @see HeaderUtils::makeDisposition() */ - public function makeDisposition($disposition, $filename, $filenameFallback = '') + public function makeDisposition(string $disposition, string $filename, string $filenameFallback = '') { - if (!\in_array($disposition, [self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE])) { - throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); - } - - if ('' == $filenameFallback) { - $filenameFallback = $filename; - } - - // filenameFallback is not ASCII. - if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) { - throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.'); - } - - // percent characters aren't safe in fallback. - if (false !== strpos($filenameFallback, '%')) { - throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.'); - } - - // path separators aren't allowed in either. - if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) { - throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.'); - } - - $output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback)); - - if ($filename !== $filenameFallback) { - $output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename)); - } - - return $output; + return HeaderUtils::makeDisposition($disposition, $filename, $filenameFallback); } /** @@ -334,10 +284,8 @@ protected function computeCacheControlValue() return $header; } - private function initDate() + private function initDate(): void { - $now = \DateTime::createFromFormat('U', time()); - $now->setTimezone(new \DateTimeZone('UTC')); - $this->set('Date', $now->format('D, d M Y H:i:s').' GMT'); + $this->set('Date', gmdate('D, d M Y H:i:s').' GMT'); } } diff --git a/vendor/symfony/http-foundation/ServerBag.php b/vendor/symfony/http-foundation/ServerBag.php index f3b64023..004af570 100644 --- a/vendor/symfony/http-foundation/ServerBag.php +++ b/vendor/symfony/http-foundation/ServerBag.php @@ -28,20 +28,17 @@ class ServerBag extends ParameterBag public function getHeaders() { $headers = []; - $contentHeaders = ['CONTENT_LENGTH' => true, 'CONTENT_MD5' => true, 'CONTENT_TYPE' => true]; foreach ($this->parameters as $key => $value) { - if (0 === strpos($key, 'HTTP_')) { + if (str_starts_with($key, 'HTTP_')) { $headers[substr($key, 5)] = $value; - } - // CONTENT_* are not prefixed with HTTP_ - elseif (isset($contentHeaders[$key])) { + } elseif (\in_array($key, ['CONTENT_TYPE', 'CONTENT_LENGTH', 'CONTENT_MD5'], true)) { $headers[$key] = $value; } } if (isset($this->parameters['PHP_AUTH_USER'])) { $headers['PHP_AUTH_USER'] = $this->parameters['PHP_AUTH_USER']; - $headers['PHP_AUTH_PW'] = isset($this->parameters['PHP_AUTH_PW']) ? $this->parameters['PHP_AUTH_PW'] : ''; + $headers['PHP_AUTH_PW'] = $this->parameters['PHP_AUTH_PW'] ?? ''; } else { /* * php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default @@ -54,7 +51,7 @@ public function getHeaders() * RewriteCond %{HTTP:Authorization} .+ * RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0] * RewriteCond %{REQUEST_FILENAME} !-f - * RewriteRule ^(.*)$ app.php [QSA,L] + * RewriteRule ^(.*)$ index.php [QSA,L] */ $authorizationHeader = null; @@ -69,7 +66,7 @@ public function getHeaders() // Decode AUTHORIZATION header into PHP_AUTH_USER and PHP_AUTH_PW when authorization header is basic $exploded = explode(':', base64_decode(substr($authorizationHeader, 6)), 2); if (2 == \count($exploded)) { - list($headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']) = $exploded; + [$headers['PHP_AUTH_USER'], $headers['PHP_AUTH_PW']] = $exploded; } } elseif (empty($this->parameters['PHP_AUTH_DIGEST']) && (0 === stripos($authorizationHeader, 'digest '))) { // In some circumstances PHP_AUTH_DIGEST needs to be set @@ -92,7 +89,7 @@ public function getHeaders() // PHP_AUTH_USER/PHP_AUTH_PW if (isset($headers['PHP_AUTH_USER'])) { - $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.$headers['PHP_AUTH_PW']); + $headers['AUTHORIZATION'] = 'Basic '.base64_encode($headers['PHP_AUTH_USER'].':'.($headers['PHP_AUTH_PW'] ?? '')); } elseif (isset($headers['PHP_AUTH_DIGEST'])) { $headers['AUTHORIZATION'] = $headers['PHP_AUTH_DIGEST']; } diff --git a/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php b/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php index 07118e89..f4f051c7 100644 --- a/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php +++ b/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php @@ -13,6 +13,8 @@ /** * This class relates to session attribute storage. + * + * @implements \IteratorAggregate */ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Countable { @@ -24,7 +26,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta /** * @param string $storageKey The key used to store attributes in the session */ - public function __construct($storageKey = '_sf2_attributes') + public function __construct(string $storageKey = '_sf2_attributes') { $this->storageKey = $storageKey; } @@ -37,7 +39,7 @@ public function getName() return $this->name; } - public function setName($name) + public function setName(string $name) { $this->name = $name; } @@ -61,7 +63,7 @@ public function getStorageKey() /** * {@inheritdoc} */ - public function has($name) + public function has(string $name) { return \array_key_exists($name, $this->attributes); } @@ -69,7 +71,7 @@ public function has($name) /** * {@inheritdoc} */ - public function get($name, $default = null) + public function get(string $name, $default = null) { return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } @@ -77,7 +79,7 @@ public function get($name, $default = null) /** * {@inheritdoc} */ - public function set($name, $value) + public function set(string $name, $value) { $this->attributes[$name] = $value; } @@ -104,7 +106,7 @@ public function replace(array $attributes) /** * {@inheritdoc} */ - public function remove($name) + public function remove(string $name) { $retval = null; if (\array_key_exists($name, $this->attributes)) { @@ -129,8 +131,9 @@ public function clear() /** * Returns an iterator for attributes. * - * @return \ArrayIterator An \ArrayIterator instance + * @return \ArrayIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->attributes); @@ -139,8 +142,9 @@ public function getIterator() /** * Returns the number of attributes. * - * @return int The number of attributes + * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->attributes); diff --git a/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php b/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php index 0d8d1799..cb506968 100644 --- a/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php +++ b/vendor/symfony/http-foundation/Session/Attribute/AttributeBagInterface.php @@ -23,50 +23,39 @@ interface AttributeBagInterface extends SessionBagInterface /** * Checks if an attribute is defined. * - * @param string $name The attribute name - * - * @return bool true if the attribute is defined, false otherwise + * @return bool */ - public function has($name); + public function has(string $name); /** * Returns an attribute. * - * @param string $name The attribute name - * @param mixed $default The default value if not found + * @param mixed $default The default value if not found * * @return mixed */ - public function get($name, $default = null); + public function get(string $name, $default = null); /** * Sets an attribute. * - * @param string $name - * @param mixed $value + * @param mixed $value */ - public function set($name, $value); + public function set(string $name, $value); /** * Returns attributes. * - * @return array Attributes + * @return array */ public function all(); - /** - * Sets attributes. - * - * @param array $attributes Attributes - */ public function replace(array $attributes); /** * Removes an attribute. * - * @param string $name - * * @return mixed The removed value or null when it does not exist */ - public function remove($name); + public function remove(string $name); } diff --git a/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php b/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php index 07885e7f..864b35fb 100644 --- a/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php +++ b/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php @@ -11,11 +11,15 @@ namespace Symfony\Component\HttpFoundation\Session\Attribute; +trigger_deprecation('symfony/http-foundation', '5.3', 'The "%s" class is deprecated.', NamespacedAttributeBag::class); + /** * This class provides structured storage of session attributes using * a name spacing character in the key. * * @author Drak + * + * @deprecated since Symfony 5.3 */ class NamespacedAttributeBag extends AttributeBag { @@ -25,7 +29,7 @@ class NamespacedAttributeBag extends AttributeBag * @param string $storageKey Session storage key * @param string $namespaceCharacter Namespace character to use in keys */ - public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/') + public function __construct(string $storageKey = '_sf2_attributes', string $namespaceCharacter = '/') { $this->namespaceCharacter = $namespaceCharacter; parent::__construct($storageKey); @@ -34,7 +38,7 @@ public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter /** * {@inheritdoc} */ - public function has($name) + public function has(string $name) { // reference mismatch: if fixed, re-introduced in array_key_exists; keep as it is $attributes = $this->resolveAttributePath($name); @@ -50,7 +54,7 @@ public function has($name) /** * {@inheritdoc} */ - public function get($name, $default = null) + public function get(string $name, $default = null) { // reference mismatch: if fixed, re-introduced in array_key_exists; keep as it is $attributes = $this->resolveAttributePath($name); @@ -66,7 +70,7 @@ public function get($name, $default = null) /** * {@inheritdoc} */ - public function set($name, $value) + public function set(string $name, $value) { $attributes = &$this->resolveAttributePath($name, true); $name = $this->resolveKey($name); @@ -76,7 +80,7 @@ public function set($name, $value) /** * {@inheritdoc} */ - public function remove($name) + public function remove(string $name) { $retval = null; $attributes = &$this->resolveAttributePath($name); @@ -99,10 +103,10 @@ public function remove($name) * * @return array|null */ - protected function &resolveAttributePath($name, $writeContext = false) + protected function &resolveAttributePath(string $name, bool $writeContext = false) { $array = &$this->attributes; - $name = (0 === strpos($name, $this->namespaceCharacter)) ? substr($name, 1) : $name; + $name = (str_starts_with($name, $this->namespaceCharacter)) ? substr($name, 1) : $name; // Check if there is anything to do, else return if (!$name) { @@ -144,11 +148,9 @@ protected function &resolveAttributePath($name, $writeContext = false) * * This is the last part in a dot separated string. * - * @param string $name - * * @return string */ - protected function resolveKey($name) + protected function resolveKey(string $name) { if (false !== $pos = strrpos($name, $this->namespaceCharacter)) { $name = substr($name, $pos + 1); diff --git a/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php b/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php index 451c4a5a..8aab3a12 100644 --- a/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php +++ b/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php @@ -25,7 +25,7 @@ class AutoExpireFlashBag implements FlashBagInterface /** * @param string $storageKey The key used to store flashes in the session */ - public function __construct($storageKey = '_symfony_flashes') + public function __construct(string $storageKey = '_symfony_flashes') { $this->storageKey = $storageKey; } @@ -38,7 +38,7 @@ public function getName() return $this->name; } - public function setName($name) + public function setName(string $name) { $this->name = $name; } @@ -60,7 +60,7 @@ public function initialize(array &$flashes) /** * {@inheritdoc} */ - public function add($type, $message) + public function add(string $type, $message) { $this->flashes['new'][$type][] = $message; } @@ -68,7 +68,7 @@ public function add($type, $message) /** * {@inheritdoc} */ - public function peek($type, array $default = []) + public function peek(string $type, array $default = []) { return $this->has($type) ? $this->flashes['display'][$type] : $default; } @@ -78,13 +78,13 @@ public function peek($type, array $default = []) */ public function peekAll() { - return \array_key_exists('display', $this->flashes) ? (array) $this->flashes['display'] : []; + return \array_key_exists('display', $this->flashes) ? $this->flashes['display'] : []; } /** * {@inheritdoc} */ - public function get($type, array $default = []) + public function get(string $type, array $default = []) { $return = $default; @@ -122,7 +122,7 @@ public function setAll(array $messages) /** * {@inheritdoc} */ - public function set($type, $messages) + public function set(string $type, $messages) { $this->flashes['new'][$type] = (array) $messages; } @@ -130,7 +130,7 @@ public function set($type, $messages) /** * {@inheritdoc} */ - public function has($type) + public function has(string $type) { return \array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type]; } diff --git a/vendor/symfony/http-foundation/Session/Flash/FlashBag.php b/vendor/symfony/http-foundation/Session/Flash/FlashBag.php index f5d984af..88df7508 100644 --- a/vendor/symfony/http-foundation/Session/Flash/FlashBag.php +++ b/vendor/symfony/http-foundation/Session/Flash/FlashBag.php @@ -25,7 +25,7 @@ class FlashBag implements FlashBagInterface /** * @param string $storageKey The key used to store flashes in the session */ - public function __construct($storageKey = '_symfony_flashes') + public function __construct(string $storageKey = '_symfony_flashes') { $this->storageKey = $storageKey; } @@ -38,7 +38,7 @@ public function getName() return $this->name; } - public function setName($name) + public function setName(string $name) { $this->name = $name; } @@ -54,7 +54,7 @@ public function initialize(array &$flashes) /** * {@inheritdoc} */ - public function add($type, $message) + public function add(string $type, $message) { $this->flashes[$type][] = $message; } @@ -62,7 +62,7 @@ public function add($type, $message) /** * {@inheritdoc} */ - public function peek($type, array $default = []) + public function peek(string $type, array $default = []) { return $this->has($type) ? $this->flashes[$type] : $default; } @@ -78,7 +78,7 @@ public function peekAll() /** * {@inheritdoc} */ - public function get($type, array $default = []) + public function get(string $type, array $default = []) { if (!$this->has($type)) { return $default; @@ -105,7 +105,7 @@ public function all() /** * {@inheritdoc} */ - public function set($type, $messages) + public function set(string $type, $messages) { $this->flashes[$type] = (array) $messages; } @@ -121,7 +121,7 @@ public function setAll(array $messages) /** * {@inheritdoc} */ - public function has($type) + public function has(string $type) { return \array_key_exists($type, $this->flashes) && $this->flashes[$type]; } diff --git a/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php b/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php index 99e80742..8713e71d 100644 --- a/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php +++ b/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php @@ -23,18 +23,16 @@ interface FlashBagInterface extends SessionBagInterface /** * Adds a flash message for the given type. * - * @param string $type - * @param mixed $message + * @param mixed $message */ - public function add($type, $message); + public function add(string $type, $message); /** * Registers one or more messages for a given type. * - * @param string $type * @param string|array $messages */ - public function set($type, $messages); + public function set(string $type, $messages); /** * Gets flash messages for a given type. @@ -44,7 +42,7 @@ public function set($type, $messages); * * @return array */ - public function peek($type, array $default = []); + public function peek(string $type, array $default = []); /** * Gets all flash messages. @@ -56,12 +54,11 @@ public function peekAll(); /** * Gets and clears flash from the stack. * - * @param string $type - * @param array $default Default value if $type does not exist + * @param array $default Default value if $type does not exist * * @return array */ - public function get($type, array $default = []); + public function get(string $type, array $default = []); /** * Gets and clears flashes from the stack. @@ -78,11 +75,9 @@ public function setAll(array $messages); /** * Has flash messages for a given type? * - * @param string $type - * * @return bool */ - public function has($type); + public function has(string $type); /** * Returns a list of all defined types. diff --git a/vendor/symfony/http-foundation/Session/Session.php b/vendor/symfony/http-foundation/Session/Session.php index db0b9aeb..022e3986 100644 --- a/vendor/symfony/http-foundation/Session/Session.php +++ b/vendor/symfony/http-foundation/Session/Session.php @@ -18,9 +18,16 @@ use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface; +// Help opcache.preload discover always-needed symbols +class_exists(AttributeBag::class); +class_exists(FlashBag::class); +class_exists(SessionBagProxy::class); + /** * @author Fabien Potencier * @author Drak + * + * @implements \IteratorAggregate */ class Session implements SessionInterface, \IteratorAggregate, \Countable { @@ -30,21 +37,18 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable private $attributeName; private $data = []; private $usageIndex = 0; + private $usageReporter; - /** - * @param SessionStorageInterface $storage A SessionStorageInterface instance - * @param AttributeBagInterface $attributes An AttributeBagInterface instance, (defaults null for default AttributeBag) - * @param FlashBagInterface $flashes A FlashBagInterface instance (defaults null for default FlashBag) - */ - public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null) + public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null, callable $usageReporter = null) { - $this->storage = $storage ?: new NativeSessionStorage(); + $this->storage = $storage ?? new NativeSessionStorage(); + $this->usageReporter = $usageReporter; - $attributes = $attributes ?: new AttributeBag(); + $attributes = $attributes ?? new AttributeBag(); $this->attributeName = $attributes->getName(); $this->registerBag($attributes); - $flashes = $flashes ?: new FlashBag(); + $flashes = $flashes ?? new FlashBag(); $this->flashName = $flashes->getName(); $this->registerBag($flashes); } @@ -60,7 +64,7 @@ public function start() /** * {@inheritdoc} */ - public function has($name) + public function has(string $name) { return $this->getAttributeBag()->has($name); } @@ -68,7 +72,7 @@ public function has($name) /** * {@inheritdoc} */ - public function get($name, $default = null) + public function get(string $name, $default = null) { return $this->getAttributeBag()->get($name, $default); } @@ -76,7 +80,7 @@ public function get($name, $default = null) /** * {@inheritdoc} */ - public function set($name, $value) + public function set(string $name, $value) { $this->getAttributeBag()->set($name, $value); } @@ -100,7 +104,7 @@ public function replace(array $attributes) /** * {@inheritdoc} */ - public function remove($name) + public function remove(string $name) { return $this->getAttributeBag()->remove($name); } @@ -124,8 +128,9 @@ public function isStarted() /** * Returns an iterator for attributes. * - * @return \ArrayIterator An \ArrayIterator instance + * @return \ArrayIterator */ + #[\ReturnTypeWillChange] public function getIterator() { return new \ArrayIterator($this->getAttributeBag()->all()); @@ -134,32 +139,29 @@ public function getIterator() /** * Returns the number of attributes. * - * @return int The number of attributes + * @return int */ + #[\ReturnTypeWillChange] public function count() { return \count($this->getAttributeBag()->all()); } - /** - * @return int - * - * @internal - */ - public function getUsageIndex() + public function &getUsageIndex(): int { return $this->usageIndex; } /** - * @return bool - * * @internal */ - public function isEmpty() + public function isEmpty(): bool { if ($this->isStarted()) { ++$this->usageIndex; + if ($this->usageReporter && 0 <= $this->usageIndex) { + ($this->usageReporter)(); + } } foreach ($this->data as &$data) { if (!empty($data)) { @@ -173,7 +175,7 @@ public function isEmpty() /** * {@inheritdoc} */ - public function invalidate($lifetime = null) + public function invalidate(int $lifetime = null) { $this->storage->clear(); @@ -183,7 +185,7 @@ public function invalidate($lifetime = null) /** * {@inheritdoc} */ - public function migrate($destroy = false, $lifetime = null) + public function migrate(bool $destroy = false, int $lifetime = null) { return $this->storage->regenerate($destroy, $lifetime); } @@ -207,7 +209,7 @@ public function getId() /** * {@inheritdoc} */ - public function setId($id) + public function setId(string $id) { if ($this->storage->getId() !== $id) { $this->storage->setId($id); @@ -225,7 +227,7 @@ public function getName() /** * {@inheritdoc} */ - public function setName($name) + public function setName(string $name) { $this->storage->setName($name); } @@ -236,6 +238,9 @@ public function setName($name) public function getMetadataBag() { ++$this->usageIndex; + if ($this->usageReporter && 0 <= $this->usageIndex) { + ($this->usageReporter)(); + } return $this->storage->getMetadataBag(); } @@ -245,13 +250,13 @@ public function getMetadataBag() */ public function registerBag(SessionBagInterface $bag) { - $this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex)); + $this->storage->registerBag(new SessionBagProxy($bag, $this->data, $this->usageIndex, $this->usageReporter)); } /** * {@inheritdoc} */ - public function getBag($name) + public function getBag(string $name) { $bag = $this->storage->getBag($name); @@ -272,10 +277,8 @@ public function getFlashBag() * Gets the attributebag interface. * * Note that this method was added to help with IDE autocompletion. - * - * @return AttributeBagInterface */ - private function getAttributeBag() + private function getAttributeBag(): AttributeBagInterface { return $this->getBag($this->attributeName); } diff --git a/vendor/symfony/http-foundation/Session/SessionBagProxy.php b/vendor/symfony/http-foundation/Session/SessionBagProxy.php index 3504bdfe..90aa010c 100644 --- a/vendor/symfony/http-foundation/Session/SessionBagProxy.php +++ b/vendor/symfony/http-foundation/Session/SessionBagProxy.php @@ -21,33 +21,35 @@ final class SessionBagProxy implements SessionBagInterface private $bag; private $data; private $usageIndex; + private $usageReporter; - public function __construct(SessionBagInterface $bag, array &$data, &$usageIndex) + public function __construct(SessionBagInterface $bag, array &$data, ?int &$usageIndex, ?callable $usageReporter) { $this->bag = $bag; $this->data = &$data; $this->usageIndex = &$usageIndex; + $this->usageReporter = $usageReporter; } - /** - * @return SessionBagInterface - */ - public function getBag() + public function getBag(): SessionBagInterface { ++$this->usageIndex; + if ($this->usageReporter && 0 <= $this->usageIndex) { + ($this->usageReporter)(); + } return $this->bag; } - /** - * @return bool - */ - public function isEmpty() + public function isEmpty(): bool { if (!isset($this->data[$this->bag->getStorageKey()])) { return true; } ++$this->usageIndex; + if ($this->usageReporter && 0 <= $this->usageIndex) { + ($this->usageReporter)(); + } return empty($this->data[$this->bag->getStorageKey()]); } @@ -55,7 +57,7 @@ public function isEmpty() /** * {@inheritdoc} */ - public function getName() + public function getName(): string { return $this->bag->getName(); } @@ -63,9 +65,13 @@ public function getName() /** * {@inheritdoc} */ - public function initialize(array &$array) + public function initialize(array &$array): void { ++$this->usageIndex; + if ($this->usageReporter && 0 <= $this->usageIndex) { + ($this->usageReporter)(); + } + $this->data[$this->bag->getStorageKey()] = &$array; $this->bag->initialize($array); @@ -74,7 +80,7 @@ public function initialize(array &$array) /** * {@inheritdoc} */ - public function getStorageKey() + public function getStorageKey(): string { return $this->bag->getStorageKey(); } diff --git a/vendor/symfony/http-foundation/Session/SessionFactory.php b/vendor/symfony/http-foundation/Session/SessionFactory.php new file mode 100644 index 00000000..04c4b06a --- /dev/null +++ b/vendor/symfony/http-foundation/Session/SessionFactory.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session; + +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageFactoryInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(Session::class); + +/** + * @author Jérémy Derussé + */ +class SessionFactory implements SessionFactoryInterface +{ + private $requestStack; + private $storageFactory; + private $usageReporter; + + public function __construct(RequestStack $requestStack, SessionStorageFactoryInterface $storageFactory, callable $usageReporter = null) + { + $this->requestStack = $requestStack; + $this->storageFactory = $storageFactory; + $this->usageReporter = $usageReporter; + } + + public function createSession(): SessionInterface + { + return new Session($this->storageFactory->createStorage($this->requestStack->getMainRequest()), null, null, $this->usageReporter); + } +} diff --git a/vendor/symfony/http-foundation/Session/SessionFactoryInterface.php b/vendor/symfony/http-foundation/Session/SessionFactoryInterface.php new file mode 100644 index 00000000..b24fdc49 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/SessionFactoryInterface.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session; + +/** + * @author Kevin Bond + */ +interface SessionFactoryInterface +{ + public function createSession(): SessionInterface; +} diff --git a/vendor/symfony/http-foundation/Session/SessionInterface.php b/vendor/symfony/http-foundation/Session/SessionInterface.php index 95fca857..e6733833 100644 --- a/vendor/symfony/http-foundation/Session/SessionInterface.php +++ b/vendor/symfony/http-foundation/Session/SessionInterface.php @@ -23,7 +23,7 @@ interface SessionInterface /** * Starts the session storage. * - * @return bool True if session started + * @return bool * * @throws \RuntimeException if session fails to start */ @@ -32,30 +32,26 @@ public function start(); /** * Returns the session ID. * - * @return string The session ID + * @return string */ public function getId(); /** * Sets the session ID. - * - * @param string $id */ - public function setId($id); + public function setId(string $id); /** * Returns the session name. * - * @return mixed The session name + * @return string */ public function getName(); /** * Sets the session name. - * - * @param string $name */ - public function setName($name); + public function setName(string $name); /** * Invalidates the current session. @@ -63,28 +59,28 @@ public function setName($name); * Clears all session attributes and flashes and regenerates the * session and deletes the old session from persistence. * - * @param int $lifetime Sets the cookie lifetime for the session cookie. A null value - * will leave the system settings unchanged, 0 sets the cookie - * to expire with browser session. Time is in seconds, and is - * not a Unix timestamp. + * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value + * will leave the system settings unchanged, 0 sets the cookie + * to expire with browser session. Time is in seconds, and is + * not a Unix timestamp. * - * @return bool True if session invalidated, false if error + * @return bool */ - public function invalidate($lifetime = null); + public function invalidate(int $lifetime = null); /** * Migrates the current session to a new session id while maintaining all * session attributes. * - * @param bool $destroy Whether to delete the old session or leave it to garbage collection - * @param int $lifetime Sets the cookie lifetime for the session cookie. A null value - * will leave the system settings unchanged, 0 sets the cookie - * to expire with browser session. Time is in seconds, and is - * not a Unix timestamp. + * @param bool $destroy Whether to delete the old session or leave it to garbage collection + * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value + * will leave the system settings unchanged, 0 sets the cookie + * to expire with browser session. Time is in seconds, and is + * not a Unix timestamp. * - * @return bool True if session migrated, false if error + * @return bool */ - public function migrate($destroy = false, $lifetime = null); + public function migrate(bool $destroy = false, int $lifetime = null); /** * Force the session to be saved and closed. @@ -98,52 +94,44 @@ public function save(); /** * Checks if an attribute is defined. * - * @param string $name The attribute name - * - * @return bool true if the attribute is defined, false otherwise + * @return bool */ - public function has($name); + public function has(string $name); /** * Returns an attribute. * - * @param string $name The attribute name - * @param mixed $default The default value if not found + * @param mixed $default The default value if not found * * @return mixed */ - public function get($name, $default = null); + public function get(string $name, $default = null); /** * Sets an attribute. * - * @param string $name - * @param mixed $value + * @param mixed $value */ - public function set($name, $value); + public function set(string $name, $value); /** * Returns attributes. * - * @return array Attributes + * @return array */ public function all(); /** * Sets attributes. - * - * @param array $attributes Attributes */ public function replace(array $attributes); /** * Removes an attribute. * - * @param string $name - * * @return mixed The removed value or null when it does not exist */ - public function remove($name); + public function remove(string $name); /** * Clears all attributes. @@ -165,11 +153,9 @@ public function registerBag(SessionBagInterface $bag); /** * Gets a bag instance by name. * - * @param string $name - * * @return SessionBagInterface */ - public function getBag($name); + public function getBag(string $name); /** * Gets session meta. diff --git a/vendor/symfony/http-foundation/Session/SessionUtils.php b/vendor/symfony/http-foundation/Session/SessionUtils.php index 04a25f71..b5bce4a8 100644 --- a/vendor/symfony/http-foundation/Session/SessionUtils.php +++ b/vendor/symfony/http-foundation/Session/SessionUtils.php @@ -22,10 +22,10 @@ final class SessionUtils { /** - * Find the session header amongst the headers that are to be sent, remove it, and return + * Finds the session header amongst the headers that are to be sent, removes it, and returns * it so the caller can process it further. */ - public static function popSessionCookie($sessionName, $sessionId) + public static function popSessionCookie(string $sessionName, string $sessionId): ?string { $sessionCookie = null; $sessionCookiePrefix = sprintf(' %s=', urlencode($sessionName)); diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php index 455ced8c..35d7b4b8 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php @@ -31,41 +31,36 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess /** * @return bool */ + #[\ReturnTypeWillChange] public function open($savePath, $sessionName) { $this->sessionName = $sessionName; - if (!headers_sent() && !ini_get('session.cache_limiter') && '0' !== ini_get('session.cache_limiter')) { - header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) ini_get('session.cache_expire'))); + if (!headers_sent() && !\ini_get('session.cache_limiter') && '0' !== \ini_get('session.cache_limiter')) { + header(sprintf('Cache-Control: max-age=%d, private, must-revalidate', 60 * (int) \ini_get('session.cache_expire'))); } return true; } /** - * @param string $sessionId - * * @return string */ - abstract protected function doRead($sessionId); + abstract protected function doRead(string $sessionId); /** - * @param string $sessionId - * @param string $data - * * @return bool */ - abstract protected function doWrite($sessionId, $data); + abstract protected function doWrite(string $sessionId, string $data); /** - * @param string $sessionId - * * @return bool */ - abstract protected function doDestroy($sessionId); + abstract protected function doDestroy(string $sessionId); /** * @return bool */ + #[\ReturnTypeWillChange] public function validateId($sessionId) { $this->prefetchData = $this->read($sessionId); @@ -86,6 +81,7 @@ public function validateId($sessionId) /** * @return string */ + #[\ReturnTypeWillChange] public function read($sessionId) { if (null !== $this->prefetchId) { @@ -102,9 +98,6 @@ public function read($sessionId) $data = $this->doRead($sessionId); $this->newSessionId = '' === $data ? $sessionId : null; - if (\PHP_VERSION_ID < 70000) { - $this->prefetchData = $data; - } return $data; } @@ -112,16 +105,9 @@ public function read($sessionId) /** * @return bool */ + #[\ReturnTypeWillChange] public function write($sessionId, $data) { - if (\PHP_VERSION_ID < 70000 && $this->prefetchData) { - $readData = $this->prefetchData; - $this->prefetchData = null; - - if ($readData === $data) { - return $this->updateTimestamp($sessionId, $data); - } - } if (null === $this->igbinaryEmptyData) { // see https://github.com/igbinary/igbinary/issues/146 $this->igbinaryEmptyData = \function_exists('igbinary_serialize') ? igbinary_serialize([]) : ''; @@ -137,12 +123,10 @@ public function write($sessionId, $data) /** * @return bool */ + #[\ReturnTypeWillChange] public function destroy($sessionId) { - if (\PHP_VERSION_ID < 70000) { - $this->prefetchData = null; - } - if (!headers_sent() && filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN)) { + if (!headers_sent() && filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN)) { if (!$this->sessionName) { throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', static::class)); } @@ -157,7 +141,7 @@ public function destroy($sessionId) */ if (null === $cookie || isset($_COOKIE[$this->sessionName])) { if (\PHP_VERSION_ID < 70300) { - setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), \FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), \FILTER_VALIDATE_BOOLEAN)); + setcookie($this->sessionName, '', 0, \ini_get('session.cookie_path'), \ini_get('session.cookie_domain'), filter_var(\ini_get('session.cookie_secure'), \FILTER_VALIDATE_BOOLEAN), filter_var(\ini_get('session.cookie_httponly'), \FILTER_VALIDATE_BOOLEAN)); } else { $params = session_get_cookie_params(); unset($params['lifetime']); diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php b/vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php new file mode 100644 index 00000000..bea3a323 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/IdentityMarshaller.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; + +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Ahmed TAILOULOUTE + */ +class IdentityMarshaller implements MarshallerInterface +{ + /** + * {@inheritdoc} + */ + public function marshall(array $values, ?array &$failed): array + { + foreach ($values as $key => $value) { + if (!\is_string($value)) { + throw new \LogicException(sprintf('%s accepts only string as data.', __METHOD__)); + } + } + + return $values; + } + + /** + * {@inheritdoc} + */ + public function unmarshall(string $value): string + { + return $value; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php new file mode 100644 index 00000000..c321c8c9 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/MarshallingSessionHandler.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; + +use Symfony\Component\Cache\Marshaller\MarshallerInterface; + +/** + * @author Ahmed TAILOULOUTE + */ +class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface +{ + private $handler; + private $marshaller; + + public function __construct(AbstractSessionHandler $handler, MarshallerInterface $marshaller) + { + $this->handler = $handler; + $this->marshaller = $marshaller; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function open($savePath, $name) + { + return $this->handler->open($savePath, $name); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function close() + { + return $this->handler->close(); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function destroy($sessionId) + { + return $this->handler->destroy($sessionId); + } + + /** + * @return int|false + */ + #[\ReturnTypeWillChange] + public function gc($maxlifetime) + { + return $this->handler->gc($maxlifetime); + } + + /** + * @return string + */ + #[\ReturnTypeWillChange] + public function read($sessionId) + { + return $this->marshaller->unmarshall($this->handler->read($sessionId)); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function write($sessionId, $data) + { + $failed = []; + $marshalledData = $this->marshaller->marshall(['data' => $data], $failed); + + if (isset($failed['data'])) { + return false; + } + + return $this->handler->write($sessionId, $marshalledData['data']); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function validateId($sessionId) + { + return $this->handler->validateId($sessionId); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function updateTimestamp($sessionId, $data) + { + return $this->handler->updateTimestamp($sessionId, $data); + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php deleted file mode 100644 index ed74ce80..00000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php +++ /dev/null @@ -1,118 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; - -@trigger_error(sprintf('The class %s is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler instead.', MemcacheSessionHandler::class), \E_USER_DEPRECATED); - -/** - * @author Drak - * - * @deprecated since version 3.4, to be removed in 4.0. Use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler instead. - */ -class MemcacheSessionHandler implements \SessionHandlerInterface -{ - private $memcache; - - /** - * @var int Time to live in seconds - */ - private $ttl; - - /** - * @var string Key prefix for shared environments - */ - private $prefix; - - /** - * Constructor. - * - * List of available options: - * * prefix: The prefix to use for the memcache keys in order to avoid collision - * * expiretime: The time to live in seconds - * - * @param \Memcache $memcache A \Memcache instance - * @param array $options An associative array of Memcache options - * - * @throws \InvalidArgumentException When unsupported options are passed - */ - public function __construct(\Memcache $memcache, array $options = []) - { - if ($diff = array_diff(array_keys($options), ['prefix', 'expiretime'])) { - throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); - } - - $this->memcache = $memcache; - $this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400; - $this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s'; - } - - /** - * {@inheritdoc} - */ - public function open($savePath, $sessionName) - { - return true; - } - - /** - * {@inheritdoc} - */ - public function close() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function read($sessionId) - { - return $this->memcache->get($this->prefix.$sessionId) ?: ''; - } - - /** - * {@inheritdoc} - */ - public function write($sessionId, $data) - { - return $this->memcache->set($this->prefix.$sessionId, $data, 0, time() + $this->ttl); - } - - /** - * {@inheritdoc} - */ - public function destroy($sessionId) - { - $this->memcache->delete($this->prefix.$sessionId); - - return true; - } - - /** - * {@inheritdoc} - */ - public function gc($maxlifetime) - { - // not required here because memcache will auto expire the records anyhow. - return true; - } - - /** - * Return a Memcache instance. - * - * @return \Memcache - */ - protected function getMemcache() - { - return $this->memcache; - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php index 6711e0a5..e0ec4d2d 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/MemcachedSessionHandler.php @@ -38,7 +38,7 @@ class MemcachedSessionHandler extends AbstractSessionHandler * * List of available options: * * prefix: The prefix to use for the memcached keys in order to avoid collision - * * expiretime: The time to live in seconds. + * * ttl: The time to live in seconds. * * @throws \InvalidArgumentException When unsupported options are passed */ @@ -46,17 +46,18 @@ public function __construct(\Memcached $memcached, array $options = []) { $this->memcached = $memcached; - if ($diff = array_diff(array_keys($options), ['prefix', 'expiretime'])) { + if ($diff = array_diff(array_keys($options), ['prefix', 'expiretime', 'ttl'])) { throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); } - $this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400; - $this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s'; + $this->ttl = $options['expiretime'] ?? $options['ttl'] ?? null; + $this->prefix = $options['prefix'] ?? 'sf2s'; } /** * @return bool */ + #[\ReturnTypeWillChange] public function close() { return $this->memcached->quit(); @@ -65,7 +66,7 @@ public function close() /** * {@inheritdoc} */ - protected function doRead($sessionId) + protected function doRead(string $sessionId) { return $this->memcached->get($this->prefix.$sessionId) ?: ''; } @@ -73,9 +74,10 @@ protected function doRead($sessionId) /** * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { - $this->memcached->touch($this->prefix.$sessionId, time() + $this->ttl); + $this->memcached->touch($this->prefix.$sessionId, $this->getCompatibleTtl()); return true; } @@ -83,15 +85,28 @@ public function updateTimestamp($sessionId, $data) /** * {@inheritdoc} */ - protected function doWrite($sessionId, $data) + protected function doWrite(string $sessionId, string $data) { - return $this->memcached->set($this->prefix.$sessionId, $data, time() + $this->ttl); + return $this->memcached->set($this->prefix.$sessionId, $data, $this->getCompatibleTtl()); + } + + private function getCompatibleTtl(): int + { + $ttl = (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime')); + + // If the relative TTL that is used exceeds 30 days, memcached will treat the value as Unix time. + // We have to convert it to an absolute Unix time at this point, to make sure the TTL is correct. + if ($ttl > 60 * 60 * 24 * 30) { + $ttl += time(); + } + + return $ttl; } /** * {@inheritdoc} */ - protected function doDestroy($sessionId) + protected function doDestroy(string $sessionId) { $result = $this->memcached->delete($this->prefix.$sessionId); @@ -99,12 +114,13 @@ protected function doDestroy($sessionId) } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { // not required here because memcached will auto expire the records anyhow. - return true; + return 0; } /** diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php new file mode 100644 index 00000000..bf27ca6c --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; + +/** + * Migrating session handler for migrating from one handler to another. It reads + * from the current handler and writes both the current and new ones. + * + * It ignores errors from the new handler. + * + * @author Ross Motley + * @author Oliver Radwell + */ +class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface +{ + /** + * @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface + */ + private $currentHandler; + + /** + * @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface + */ + private $writeOnlyHandler; + + public function __construct(\SessionHandlerInterface $currentHandler, \SessionHandlerInterface $writeOnlyHandler) + { + if (!$currentHandler instanceof \SessionUpdateTimestampHandlerInterface) { + $currentHandler = new StrictSessionHandler($currentHandler); + } + if (!$writeOnlyHandler instanceof \SessionUpdateTimestampHandlerInterface) { + $writeOnlyHandler = new StrictSessionHandler($writeOnlyHandler); + } + + $this->currentHandler = $currentHandler; + $this->writeOnlyHandler = $writeOnlyHandler; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function close() + { + $result = $this->currentHandler->close(); + $this->writeOnlyHandler->close(); + + return $result; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function destroy($sessionId) + { + $result = $this->currentHandler->destroy($sessionId); + $this->writeOnlyHandler->destroy($sessionId); + + return $result; + } + + /** + * @return int|false + */ + #[\ReturnTypeWillChange] + public function gc($maxlifetime) + { + $result = $this->currentHandler->gc($maxlifetime); + $this->writeOnlyHandler->gc($maxlifetime); + + return $result; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function open($savePath, $sessionName) + { + $result = $this->currentHandler->open($savePath, $sessionName); + $this->writeOnlyHandler->open($savePath, $sessionName); + + return $result; + } + + /** + * @return string + */ + #[\ReturnTypeWillChange] + public function read($sessionId) + { + // No reading from new handler until switch-over + return $this->currentHandler->read($sessionId); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function write($sessionId, $sessionData) + { + $result = $this->currentHandler->write($sessionId, $sessionData); + $this->writeOnlyHandler->write($sessionId, $sessionData); + + return $result; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function validateId($sessionId) + { + // No reading from new handler until switch-over + return $this->currentHandler->validateId($sessionId); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function updateTimestamp($sessionId, $sessionData) + { + $result = $this->currentHandler->updateTimestamp($sessionId, $sessionData); + $this->writeOnlyHandler->updateTimestamp($sessionId, $sessionData); + + return $result; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php index 52dc15de..ef8f7194 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php @@ -11,6 +11,11 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; +use MongoDB\BSON\Binary; +use MongoDB\BSON\UTCDateTime; +use MongoDB\Client; +use MongoDB\Collection; + /** * Session handler using the mongodb/mongodb package and MongoDB driver extension. * @@ -24,7 +29,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler private $mongo; /** - * @var \MongoCollection + * @var Collection */ private $collection; @@ -51,7 +56,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler * A TTL collections can be used on MongoDB 2.2+ to cleanup expired sessions * automatically. Such an index can for example look like this: * - * db..ensureIndex( + * db..createIndex( * { "": 1 }, * { "expireAfterSeconds": 0 } * ) @@ -61,22 +66,10 @@ class MongoDbSessionHandler extends AbstractSessionHandler * If you use such an index, you can drop `gc_probability` to 0 since * no garbage-collection is required. * - * @param \MongoDB\Client $mongo A MongoDB\Client instance - * @param array $options An associative array of field options - * - * @throws \InvalidArgumentException When MongoClient or Mongo instance not provided * @throws \InvalidArgumentException When "database" or "collection" not provided */ - public function __construct($mongo, array $options) + public function __construct(Client $mongo, array $options) { - if ($mongo instanceof \MongoClient || $mongo instanceof \Mongo) { - @trigger_error(sprintf('Using %s with the legacy mongo extension is deprecated as of 3.4 and will be removed in 4.0. Use it with the mongodb/mongodb package and ext-mongodb instead.', __CLASS__), \E_USER_DEPRECATED); - } - - if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { - throw new \InvalidArgumentException('MongoClient or Mongo instance required.'); - } - if (!isset($options['database']) || !isset($options['collection'])) { throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler.'); } @@ -92,8 +85,9 @@ public function __construct($mongo, array $options) } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function close() { return true; @@ -102,11 +96,9 @@ public function close() /** * {@inheritdoc} */ - protected function doDestroy($sessionId) + protected function doDestroy(string $sessionId) { - $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove'; - - $this->getCollection()->$methodName([ + $this->getCollection()->deleteOne([ $this->options['id_field'] => $sessionId, ]); @@ -114,73 +106,52 @@ protected function doDestroy($sessionId) } /** - * {@inheritdoc} + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { - $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteMany' : 'remove'; - - $this->getCollection()->$methodName([ - $this->options['expiry_field'] => ['$lt' => $this->createDateTime()], - ]); - - return true; + return $this->getCollection()->deleteMany([ + $this->options['expiry_field'] => ['$lt' => new UTCDateTime()], + ])->getDeletedCount(); } /** * {@inheritdoc} */ - protected function doWrite($sessionId, $data) + protected function doWrite(string $sessionId, string $data) { - $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime')); + $expiry = new UTCDateTime((time() + (int) \ini_get('session.gc_maxlifetime')) * 1000); $fields = [ - $this->options['time_field'] => $this->createDateTime(), + $this->options['time_field'] => new UTCDateTime(), $this->options['expiry_field'] => $expiry, + $this->options['data_field'] => new Binary($data, Binary::TYPE_OLD_BINARY), ]; - $options = ['upsert' => true]; - - if ($this->mongo instanceof \MongoDB\Client) { - $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY); - } else { - $fields[$this->options['data_field']] = new \MongoBinData($data, \MongoBinData::BYTE_ARRAY); - $options['multiple'] = false; - } - - $methodName = $this->mongo instanceof \MongoDB\Client ? 'updateOne' : 'update'; - - $this->getCollection()->$methodName( + $this->getCollection()->updateOne( [$this->options['id_field'] => $sessionId], ['$set' => $fields], - $options + ['upsert' => true] ); return true; } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { - $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime')); - - if ($this->mongo instanceof \MongoDB\Client) { - $methodName = 'updateOne'; - $options = []; - } else { - $methodName = 'update'; - $options = ['multiple' => false]; - } + $expiry = new UTCDateTime((time() + (int) \ini_get('session.gc_maxlifetime')) * 1000); - $this->getCollection()->$methodName( + $this->getCollection()->updateOne( [$this->options['id_field'] => $sessionId], ['$set' => [ - $this->options['time_field'] => $this->createDateTime(), + $this->options['time_field'] => new UTCDateTime(), $this->options['expiry_field'] => $expiry, - ]], - $options + ]] ); return true; @@ -189,30 +160,21 @@ public function updateTimestamp($sessionId, $data) /** * {@inheritdoc} */ - protected function doRead($sessionId) + protected function doRead(string $sessionId) { $dbData = $this->getCollection()->findOne([ $this->options['id_field'] => $sessionId, - $this->options['expiry_field'] => ['$gte' => $this->createDateTime()], + $this->options['expiry_field'] => ['$gte' => new UTCDateTime()], ]); if (null === $dbData) { return ''; } - if ($dbData[$this->options['data_field']] instanceof \MongoDB\BSON\Binary) { - return $dbData[$this->options['data_field']]->getData(); - } - - return $dbData[$this->options['data_field']]->bin; + return $dbData[$this->options['data_field']]->getData(); } - /** - * Return a "MongoCollection" instance. - * - * @return \MongoCollection - */ - private function getCollection() + private function getCollection(): Collection { if (null === $this->collection) { $this->collection = $this->mongo->selectCollection($this->options['database'], $this->options['collection']); @@ -222,34 +184,10 @@ private function getCollection() } /** - * Return a Mongo instance. - * - * @return \Mongo|\MongoClient|\MongoDB\Client + * @return Client */ protected function getMongo() { return $this->mongo; } - - /** - * Create a date object using the class appropriate for the current mongo connection. - * - * Return an instance of a MongoDate or \MongoDB\BSON\UTCDateTime - * - * @param int $seconds An integer representing UTC seconds since Jan 1 1970. Defaults to now. - * - * @return \MongoDate|\MongoDB\BSON\UTCDateTime - */ - private function createDateTime($seconds = null) - { - if (null === $seconds) { - $seconds = time(); - } - - if ($this->mongo instanceof \MongoDB\Client) { - return new \MongoDB\BSON\UTCDateTime($seconds * 1000); - } - - return new \MongoDate($seconds); - } } diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php index f24271fb..52a10387 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php @@ -16,22 +16,22 @@ * * @author Drak */ -class NativeFileSessionHandler extends NativeSessionHandler +class NativeFileSessionHandler extends \SessionHandler { /** - * @param string $savePath Path of directory to save session files - * Default null will leave setting as defined by PHP. - * '/path', 'N;/path', or 'N;octal-mode;/path + * @param string|null $savePath Path of directory to save session files + * Default null will leave setting as defined by PHP. + * '/path', 'N;/path', or 'N;octal-mode;/path * * @see https://php.net/session.configuration#ini.session.save-path for further details. * * @throws \InvalidArgumentException On invalid $savePath * @throws \RuntimeException When failing to create the save directory */ - public function __construct($savePath = null) + public function __construct(string $savePath = null) { if (null === $savePath) { - $savePath = ini_get('session.save_path'); + $savePath = \ini_get('session.save_path'); } $baseDir = $savePath; @@ -49,7 +49,11 @@ public function __construct($savePath = null) throw new \RuntimeException(sprintf('Session Storage was not able to create directory "%s".', $baseDir)); } - ini_set('session.save_path', $savePath); - ini_set('session.save_handler', 'files'); + if ($savePath !== \ini_get('session.save_path')) { + ini_set('session.save_path', $savePath); + } + if ('files' !== \ini_get('session.save_handler')) { + ini_set('session.save_handler', 'files'); + } } } diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php deleted file mode 100644 index 280d0d6e..00000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php +++ /dev/null @@ -1,24 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; - -/** - * @deprecated since version 3.4, to be removed in 4.0. Use \SessionHandler instead. - * @see https://php.net/sessionhandler - */ -class NativeSessionHandler extends \SessionHandler -{ - public function __construct() - { - @trigger_error('The '.__NAMESPACE__.'\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead.', \E_USER_DEPRECATED); - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php index 3ba9378c..4331dbe5 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/NullSessionHandler.php @@ -19,16 +19,18 @@ class NullSessionHandler extends AbstractSessionHandler { /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function close() { return true; } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function validateId($sessionId) { return true; @@ -37,14 +39,15 @@ public function validateId($sessionId) /** * {@inheritdoc} */ - protected function doRead($sessionId) + protected function doRead(string $sessionId) { return ''; } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { return true; @@ -53,7 +56,7 @@ public function updateTimestamp($sessionId, $data) /** * {@inheritdoc} */ - protected function doWrite($sessionId, $data) + protected function doWrite(string $sessionId, string $data) { return true; } @@ -61,16 +64,17 @@ protected function doWrite($sessionId, $data) /** * {@inheritdoc} */ - protected function doDestroy($sessionId) + protected function doDestroy(string $sessionId) { return true; } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { - return true; + return 0; } } diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php index db32d549..cad7e0a7 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php @@ -46,7 +46,7 @@ class PdoSessionHandler extends AbstractSessionHandler * write will win in this case. It might be useful when you implement your own * logic to deal with this like an optimistic approach. */ - const LOCK_NONE = 0; + public const LOCK_NONE = 0; /** * Creates an application-level lock on a session. The disadvantage is that the @@ -55,7 +55,7 @@ class PdoSessionHandler extends AbstractSessionHandler * does not require a transaction. * This mode is not available for SQLite and not yet implemented for oci and sqlsrv. */ - const LOCK_ADVISORY = 1; + public const LOCK_ADVISORY = 1; /** * Issues a real row lock. Since it uses a transaction between opening and @@ -63,7 +63,9 @@ class PdoSessionHandler extends AbstractSessionHandler * that you also use for your application logic. This mode is the default because * it's the only reliable solution across DBMSs. */ - const LOCK_TRANSACTIONAL = 2; + public const LOCK_TRANSACTIONAL = 2; + + private const MAX_LIFETIME = 315576000; /** * @var \PDO|null PDO instance or null when not connected yet @@ -71,57 +73,67 @@ class PdoSessionHandler extends AbstractSessionHandler private $pdo; /** - * @var string|false|null DSN string or null for session.save_path or false when lazy connection disabled + * DSN string or null for session.save_path or false when lazy connection disabled. + * + * @var string|false|null */ private $dsn = false; /** - * @var string Database driver + * @var string|null */ private $driver; /** - * @var string Table name + * @var string */ private $table = 'sessions'; /** - * @var string Column for session id + * @var string */ private $idCol = 'sess_id'; /** - * @var string Column for session data + * @var string */ private $dataCol = 'sess_data'; /** - * @var string Column for lifetime + * @var string */ private $lifetimeCol = 'sess_lifetime'; /** - * @var string Column for timestamp + * @var string */ private $timeCol = 'sess_time'; /** - * @var string Username when lazy-connect + * Username when lazy-connect. + * + * @var string */ private $username = ''; /** - * @var string Password when lazy-connect + * Password when lazy-connect. + * + * @var string */ private $password = ''; /** - * @var array Connection options when lazy-connect + * Connection options when lazy-connect. + * + * @var array */ private $connectionOptions = []; /** - * @var int The strategy for locking, see constants + * The strategy for locking, see constants. + * + * @var int */ private $lockMode = self::LOCK_TRANSACTIONAL; @@ -133,17 +145,23 @@ class PdoSessionHandler extends AbstractSessionHandler private $unlockStatements = []; /** - * @var bool True when the current session exists but expired according to session.gc_maxlifetime + * True when the current session exists but expired according to session.gc_maxlifetime. + * + * @var bool */ private $sessionExpired = false; /** - * @var bool Whether a transaction is active + * Whether a transaction is active. + * + * @var bool */ private $inTransaction = false; /** - * @var bool Whether gc() has been called + * Whether gc() has been called. + * + * @var bool */ private $gcCalled = false; @@ -165,7 +183,6 @@ class PdoSessionHandler extends AbstractSessionHandler * * lock_mode: The strategy for locking, see constants [default: LOCK_TRANSACTIONAL] * * @param \PDO|string|null $pdoOrDsn A \PDO instance or DSN string or URL string or null - * @param array $options An associative array of options * * @throws \InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION */ @@ -178,21 +195,21 @@ public function __construct($pdoOrDsn = null, array $options = []) $this->pdo = $pdoOrDsn; $this->driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME); - } elseif (\is_string($pdoOrDsn) && false !== strpos($pdoOrDsn, '://')) { + } elseif (\is_string($pdoOrDsn) && str_contains($pdoOrDsn, '://')) { $this->dsn = $this->buildDsnFromUrl($pdoOrDsn); } else { $this->dsn = $pdoOrDsn; } - $this->table = isset($options['db_table']) ? $options['db_table'] : $this->table; - $this->idCol = isset($options['db_id_col']) ? $options['db_id_col'] : $this->idCol; - $this->dataCol = isset($options['db_data_col']) ? $options['db_data_col'] : $this->dataCol; - $this->lifetimeCol = isset($options['db_lifetime_col']) ? $options['db_lifetime_col'] : $this->lifetimeCol; - $this->timeCol = isset($options['db_time_col']) ? $options['db_time_col'] : $this->timeCol; - $this->username = isset($options['db_username']) ? $options['db_username'] : $this->username; - $this->password = isset($options['db_password']) ? $options['db_password'] : $this->password; - $this->connectionOptions = isset($options['db_connection_options']) ? $options['db_connection_options'] : $this->connectionOptions; - $this->lockMode = isset($options['lock_mode']) ? $options['lock_mode'] : $this->lockMode; + $this->table = $options['db_table'] ?? $this->table; + $this->idCol = $options['db_id_col'] ?? $this->idCol; + $this->dataCol = $options['db_data_col'] ?? $this->dataCol; + $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol; + $this->timeCol = $options['db_time_col'] ?? $this->timeCol; + $this->username = $options['db_username'] ?? $this->username; + $this->password = $options['db_password'] ?? $this->password; + $this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions; + $this->lockMode = $options['lock_mode'] ?? $this->lockMode; } /** @@ -238,6 +255,7 @@ public function createTable() try { $this->pdo->exec($sql); + $this->pdo->exec("CREATE INDEX EXPIRY ON $this->table ($this->lifetimeCol)"); } catch (\PDOException $e) { $this->rollback(); @@ -250,7 +268,7 @@ public function createTable() * * Can be used to distinguish between a new session and one that expired due to inactivity. * - * @return bool Whether current session expired + * @return bool */ public function isSessionExpired() { @@ -258,8 +276,9 @@ public function isSessionExpired() } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function open($savePath, $sessionName) { $this->sessionExpired = false; @@ -272,8 +291,9 @@ public function open($savePath, $sessionName) } /** - * {@inheritdoc} + * @return string */ + #[\ReturnTypeWillChange] public function read($sessionId) { try { @@ -286,21 +306,22 @@ public function read($sessionId) } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { // We delay gc() to close() so that it is executed outside the transactional and blocking read-write process. // This way, pruning expired sessions does not block them from being started while the current session is used. $this->gcCalled = true; - return true; + return 0; } /** * {@inheritdoc} */ - protected function doDestroy($sessionId) + protected function doDestroy(string $sessionId) { // delete the record associated with this id $sql = "DELETE FROM $this->table WHERE $this->idCol = :id"; @@ -321,9 +342,9 @@ protected function doDestroy($sessionId) /** * {@inheritdoc} */ - protected function doWrite($sessionId, $data) + protected function doWrite(string $sessionId, string $data) { - $maxlifetime = (int) ini_get('session.gc_maxlifetime'); + $maxlifetime = (int) \ini_get('session.gc_maxlifetime'); try { // We use a single MERGE SQL query when supported by the database. @@ -348,7 +369,7 @@ protected function doWrite($sessionId, $data) $insertStmt->execute(); } catch (\PDOException $e) { // Handle integrity violation SQLSTATE 23000 (or a subclass like 23505 in Postgres) for duplicate keys - if (0 === strpos($e->getCode(), '23')) { + if (str_starts_with($e->getCode(), '23')) { $updateStmt->execute(); } else { throw $e; @@ -365,18 +386,19 @@ protected function doWrite($sessionId, $data) } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { - $maxlifetime = (int) ini_get('session.gc_maxlifetime'); + $expiry = time() + (int) \ini_get('session.gc_maxlifetime'); try { $updateStmt = $this->pdo->prepare( - "UPDATE $this->table SET $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id" + "UPDATE $this->table SET $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id" ); - $updateStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); - $updateStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT); + $updateStmt->bindValue(':id', $sessionId, \PDO::PARAM_STR); + $updateStmt->bindValue(':expiry', $expiry, \PDO::PARAM_INT); $updateStmt->bindValue(':time', time(), \PDO::PARAM_INT); $updateStmt->execute(); } catch (\PDOException $e) { @@ -389,8 +411,9 @@ public function updateTimestamp($sessionId, $data) } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function close() { $this->commit(); @@ -403,19 +426,27 @@ public function close() $this->gcCalled = false; // delete the session records that have expired + $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol < :time AND $this->lifetimeCol > :min"; + $stmt = $this->pdo->prepare($sql); + $stmt->bindValue(':time', time(), \PDO::PARAM_INT); + $stmt->bindValue(':min', self::MAX_LIFETIME, \PDO::PARAM_INT); + $stmt->execute(); + // to be removed in 6.0 if ('mysql' === $this->driver) { - $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol < :time"; + $legacySql = "DELETE FROM $this->table WHERE $this->lifetimeCol <= :min AND $this->lifetimeCol + $this->timeCol < :time"; } else { - $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol < :time - $this->timeCol"; + $legacySql = "DELETE FROM $this->table WHERE $this->lifetimeCol <= :min AND $this->lifetimeCol < :time - $this->timeCol"; } - $stmt = $this->pdo->prepare($sql); + $stmt = $this->pdo->prepare($legacySql); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); + $stmt->bindValue(':min', self::MAX_LIFETIME, \PDO::PARAM_INT); $stmt->execute(); } if (false !== $this->dsn) { $this->pdo = null; // only close lazy-connection + $this->driver = null; } return true; @@ -423,10 +454,8 @@ public function close() /** * Lazy-connects to the database. - * - * @param string $dsn DSN string */ - private function connect($dsn) + private function connect(string $dsn): void { $this->pdo = new \PDO($dsn, $this->username, $this->password, $this->connectionOptions); $this->pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); @@ -436,13 +465,9 @@ private function connect($dsn) /** * Builds a PDO DSN from a URL-like connection string. * - * @param string $dsnOrUrl - * - * @return string - * * @todo implement missing support for oci DSN (which look totally different from other PDO ones) */ - private function buildDsnFromUrl($dsnOrUrl) + private function buildDsnFromUrl(string $dsnOrUrl): string { // (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid $url = preg_replace('#^((?:pdo_)?sqlite3?):///#', '$1://localhost/', $dsnOrUrl); @@ -476,17 +501,39 @@ private function buildDsnFromUrl($dsnOrUrl) 'sqlite3' => 'sqlite', ]; - $driver = isset($driverAliasMap[$params['scheme']]) ? $driverAliasMap[$params['scheme']] : $params['scheme']; + $driver = $driverAliasMap[$params['scheme']] ?? $params['scheme']; // Doctrine DBAL supports passing its internal pdo_* driver names directly too (allowing both dashes and underscores). This allows supporting the same here. - if (0 === strpos($driver, 'pdo_') || 0 === strpos($driver, 'pdo-')) { + if (str_starts_with($driver, 'pdo_') || str_starts_with($driver, 'pdo-')) { $driver = substr($driver, 4); } + $dsn = null; switch ($driver) { case 'mysql': + $dsn = 'mysql:'; + if ('' !== ($params['query'] ?? '')) { + $queryParams = []; + parse_str($params['query'], $queryParams); + if ('' !== ($queryParams['charset'] ?? '')) { + $dsn .= 'charset='.$queryParams['charset'].';'; + } + + if ('' !== ($queryParams['unix_socket'] ?? '')) { + $dsn .= 'unix_socket='.$queryParams['unix_socket'].';'; + + if (isset($params['path'])) { + $dbName = substr($params['path'], 1); // Remove the leading slash + $dsn .= 'dbname='.$dbName.';'; + } + + return $dsn; + } + } + // If "unix_socket" is not in the query, we continue with the same process as pgsql + // no break case 'pgsql': - $dsn = $driver.':'; + $dsn ?? $dsn = 'pgsql:'; if (isset($params['host']) && '' !== $params['host']) { $dsn .= 'host='.$params['host'].';'; @@ -541,7 +588,7 @@ private function buildDsnFromUrl($dsnOrUrl) * due to https://percona.com/blog/2013/12/12/one-more-innodb-gap-lock-to-avoid/ . * So we change it to READ COMMITTED. */ - private function beginTransaction() + private function beginTransaction(): void { if (!$this->inTransaction) { if ('sqlite' === $this->driver) { @@ -559,7 +606,7 @@ private function beginTransaction() /** * Helper method to commit a transaction. */ - private function commit() + private function commit(): void { if ($this->inTransaction) { try { @@ -581,7 +628,7 @@ private function commit() /** * Helper method to rollback a transaction. */ - private function rollback() + private function rollback(): void { // We only need to rollback if we are in a transaction. Otherwise the resulting // error would hide the real problem why rollback was called. We might not be @@ -603,11 +650,9 @@ private function rollback() * We need to make sure we do not return session data that is already considered garbage according * to the session.gc_maxlifetime setting because gc() is called after read() and only sometimes. * - * @param string $sessionId Session ID - * - * @return string The session data + * @return string */ - protected function doRead($sessionId) + protected function doRead(string $sessionId) { if (self::LOCK_ADVISORY === $this->lockMode) { $this->unlockStatements[] = $this->doAdvisoryLock($sessionId); @@ -618,12 +663,17 @@ protected function doRead($sessionId) $selectStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $insertStmt = null; - do { + while (true) { $selectStmt->execute(); $sessionRows = $selectStmt->fetchAll(\PDO::FETCH_NUM); if ($sessionRows) { - if ($sessionRows[0][1] + $sessionRows[0][2] < time()) { + $expiry = (int) $sessionRows[0][1]; + if ($expiry <= self::MAX_LIFETIME) { + $expiry += $sessionRows[0][2]; + } + + if ($expiry < time()) { $this->sessionExpired = true; return ''; @@ -637,7 +687,7 @@ protected function doRead($sessionId) throw new \RuntimeException('Failed to read session: INSERT reported a duplicate id but next SELECT did not return any data.'); } - if (!filter_var(ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { + if (!filter_var(\ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { // In strict mode, session fixation is not possible: new sessions always start with a unique // random id, so that concurrency is not possible and this code path can be skipped. // Exclusive-reading of non-existent rows does not block, so we need to do an insert to block @@ -648,7 +698,7 @@ protected function doRead($sessionId) } catch (\PDOException $e) { // Catch duplicate key error because other connection created the session already. // It would only not be the case when the other connection destroyed the session. - if (0 === strpos($e->getCode(), '23')) { + if (str_starts_with($e->getCode(), '23')) { // Retrieve finished session data written by concurrent connection by restarting the loop. // We have to start a new transaction as a failed query will mark the current transaction as // aborted in PostgreSQL and disallow further queries within it. @@ -662,14 +712,12 @@ protected function doRead($sessionId) } return ''; - } while (true); + } } /** * Executes an application-level lock on the database. * - * @param string $sessionId Session ID - * * @return \PDOStatement The statement that needs to be executed later to release the lock * * @throws \DomainException When an unsupported PDO driver is used @@ -678,7 +726,7 @@ protected function doRead($sessionId) * - for oci using DBMS_LOCK.REQUEST * - for sqlsrv using sp_getapplock with LockOwner = Session */ - private function doAdvisoryLock($sessionId) + private function doAdvisoryLock(string $sessionId): \PDOStatement { switch ($this->driver) { case 'mysql': @@ -733,12 +781,8 @@ private function doAdvisoryLock($sessionId) * Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer. * * Keep in mind, PHP integers are signed. - * - * @param string $string - * - * @return int */ - private function convertStringToInt($string) + private function convertStringToInt(string $string): int { if (4 === \PHP_INT_SIZE) { return (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]); @@ -753,15 +797,14 @@ private function convertStringToInt($string) /** * Return a locking or nonlocking SQL query to read session information. * - * @return string The SQL string - * * @throws \DomainException When an unsupported PDO driver is used */ - private function getSelectSql() + private function getSelectSql(): string { if (self::LOCK_TRANSACTIONAL === $this->lockMode) { $this->beginTransaction(); + // selecting the time column should be removed in 6.0 switch ($this->driver) { case 'mysql': case 'oci': @@ -782,32 +825,26 @@ private function getSelectSql() /** * Returns an insert statement supported by the database for writing session data. - * - * @param string $sessionId Session ID - * @param string $sessionData Encoded session data - * @param int $maxlifetime session.gc_maxlifetime - * - * @return \PDOStatement The insert statement */ - private function getInsertStatement($sessionId, $sessionData, $maxlifetime) + private function getInsertStatement(string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement { switch ($this->driver) { case 'oci': $data = fopen('php://memory', 'r+'); fwrite($data, $sessionData); rewind($data); - $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :lifetime, :time) RETURNING $this->dataCol into :data"; + $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :expiry, :time) RETURNING $this->dataCol into :data"; break; default: $data = $sessionData; - $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; + $sql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)"; break; } $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $stmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT); + $stmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); return $stmt; @@ -815,32 +852,26 @@ private function getInsertStatement($sessionId, $sessionData, $maxlifetime) /** * Returns an update statement supported by the database for writing session data. - * - * @param string $sessionId Session ID - * @param string $sessionData Encoded session data - * @param int $maxlifetime session.gc_maxlifetime - * - * @return \PDOStatement The update statement */ - private function getUpdateStatement($sessionId, $sessionData, $maxlifetime) + private function getUpdateStatement(string $sessionId, string $sessionData, int $maxlifetime): \PDOStatement { switch ($this->driver) { case 'oci': $data = fopen('php://memory', 'r+'); fwrite($data, $sessionData); rewind($data); - $sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data"; + $sql = "UPDATE $this->table SET $this->dataCol = EMPTY_BLOB(), $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id RETURNING $this->dataCol into :data"; break; default: $data = $sessionData; - $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id"; + $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :expiry, $this->timeCol = :time WHERE $this->idCol = :id"; break; } $stmt = $this->pdo->prepare($sql); $stmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $stmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT); + $stmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT); $stmt->bindValue(':time', time(), \PDO::PARAM_INT); return $stmt; @@ -848,18 +879,12 @@ private function getUpdateStatement($sessionId, $sessionData, $maxlifetime) /** * Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data. - * - * @param string $sessionId Session ID - * @param string $data Encoded session data - * @param int $maxlifetime session.gc_maxlifetime - * - * @return \PDOStatement|null The merge statement or null when not supported */ - private function getMergeStatement($sessionId, $data, $maxlifetime) + private function getMergeStatement(string $sessionId, string $data, int $maxlifetime): ?\PDOStatement { switch (true) { case 'mysql' === $this->driver: - $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". + $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time) ". "ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)"; break; case 'sqlsrv' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '10', '>='): @@ -870,10 +895,10 @@ private function getMergeStatement($sessionId, $data, $maxlifetime) "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;"; break; case 'sqlite' === $this->driver: - $mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; + $mergeSql = "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time)"; break; case 'pgsql' === $this->driver && version_compare($this->pdo->getAttribute(\PDO::ATTR_SERVER_VERSION), '9.5', '>='): - $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time) ". + $mergeSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :expiry, :time) ". "ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)"; break; default: @@ -887,15 +912,15 @@ private function getMergeStatement($sessionId, $data, $maxlifetime) $mergeStmt->bindParam(1, $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(2, $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(3, $data, \PDO::PARAM_LOB); - $mergeStmt->bindParam(4, $maxlifetime, \PDO::PARAM_INT); + $mergeStmt->bindValue(4, time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(5, time(), \PDO::PARAM_INT); $mergeStmt->bindParam(6, $data, \PDO::PARAM_LOB); - $mergeStmt->bindParam(7, $maxlifetime, \PDO::PARAM_INT); + $mergeStmt->bindValue(7, time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(8, time(), \PDO::PARAM_INT); } else { $mergeStmt->bindParam(':id', $sessionId, \PDO::PARAM_STR); $mergeStmt->bindParam(':data', $data, \PDO::PARAM_LOB); - $mergeStmt->bindParam(':lifetime', $maxlifetime, \PDO::PARAM_INT); + $mergeStmt->bindValue(':expiry', time() + $maxlifetime, \PDO::PARAM_INT); $mergeStmt->bindValue(':time', time(), \PDO::PARAM_INT); } @@ -910,7 +935,7 @@ private function getMergeStatement($sessionId, $data, $maxlifetime) protected function getConnection() { if (null === $this->pdo) { - $this->connect($this->dsn ?: ini_get('session.save_path')); + $this->connect($this->dsn ?: \ini_get('session.save_path')); } return $this->pdo; diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php new file mode 100644 index 00000000..31954e67 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; + +use Predis\Response\ErrorInterface; +use Symfony\Component\Cache\Traits\RedisClusterProxy; +use Symfony\Component\Cache\Traits\RedisProxy; + +/** + * Redis based session storage handler based on the Redis class + * provided by the PHP redis extension. + * + * @author Dalibor Karlović + */ +class RedisSessionHandler extends AbstractSessionHandler +{ + private $redis; + + /** + * @var string Key prefix for shared environments + */ + private $prefix; + + /** + * @var int Time to live in seconds + */ + private $ttl; + + /** + * List of available options: + * * prefix: The prefix to use for the keys in order to avoid collision on the Redis server + * * ttl: The time to live in seconds. + * + * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy $redis + * + * @throws \InvalidArgumentException When unsupported client or options are passed + */ + public function __construct($redis, array $options = []) + { + if ( + !$redis instanceof \Redis && + !$redis instanceof \RedisArray && + !$redis instanceof \RedisCluster && + !$redis instanceof \Predis\ClientInterface && + !$redis instanceof RedisProxy && + !$redis instanceof RedisClusterProxy + ) { + throw new \InvalidArgumentException(sprintf('"%s()" expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\ClientInterface, "%s" given.', __METHOD__, get_debug_type($redis))); + } + + if ($diff = array_diff(array_keys($options), ['prefix', 'ttl'])) { + throw new \InvalidArgumentException(sprintf('The following options are not supported "%s".', implode(', ', $diff))); + } + + $this->redis = $redis; + $this->prefix = $options['prefix'] ?? 'sf_s'; + $this->ttl = $options['ttl'] ?? null; + } + + /** + * {@inheritdoc} + */ + protected function doRead(string $sessionId): string + { + return $this->redis->get($this->prefix.$sessionId) ?: ''; + } + + /** + * {@inheritdoc} + */ + protected function doWrite(string $sessionId, string $data): bool + { + $result = $this->redis->setEx($this->prefix.$sessionId, (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime')), $data); + + return $result && !$result instanceof ErrorInterface; + } + + /** + * {@inheritdoc} + */ + protected function doDestroy(string $sessionId): bool + { + static $unlink = true; + + if ($unlink) { + try { + $unlink = false !== $this->redis->unlink($this->prefix.$sessionId); + } catch (\Throwable $e) { + $unlink = false; + } + } + + if (!$unlink) { + $this->redis->del($this->prefix.$sessionId); + } + + return true; + } + + /** + * {@inheritdoc} + */ + #[\ReturnTypeWillChange] + public function close(): bool + { + return true; + } + + /** + * {@inheritdoc} + * + * @return int|false + */ + #[\ReturnTypeWillChange] + public function gc($maxlifetime) + { + return 0; + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function updateTimestamp($sessionId, $data) + { + return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ($this->ttl ?? \ini_get('session.gc_maxlifetime'))); + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php b/vendor/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php new file mode 100644 index 00000000..39dc30c6 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/SessionHandlerFactory.php @@ -0,0 +1,102 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; + +use Doctrine\DBAL\Configuration; +use Doctrine\DBAL\DriverManager; +use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; +use Doctrine\DBAL\Tools\DsnParser; +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Traits\RedisClusterProxy; +use Symfony\Component\Cache\Traits\RedisProxy; + +/** + * @author Nicolas Grekas + */ +class SessionHandlerFactory +{ + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\ClientInterface|RedisProxy|RedisClusterProxy|\Memcached|\PDO|string $connection Connection or DSN + */ + public static function createHandler($connection): AbstractSessionHandler + { + if (!\is_string($connection) && !\is_object($connection)) { + throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be a string or a connection object, "%s" given.', __METHOD__, get_debug_type($connection))); + } + + if ($options = \is_string($connection) ? parse_url($connection) : false) { + parse_str($options['query'] ?? '', $options); + } + + switch (true) { + case $connection instanceof \Redis: + case $connection instanceof \RedisArray: + case $connection instanceof \RedisCluster: + case $connection instanceof \Predis\ClientInterface: + case $connection instanceof RedisProxy: + case $connection instanceof RedisClusterProxy: + return new RedisSessionHandler($connection); + + case $connection instanceof \Memcached: + return new MemcachedSessionHandler($connection); + + case $connection instanceof \PDO: + return new PdoSessionHandler($connection); + + case !\is_string($connection): + throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', get_debug_type($connection))); + case str_starts_with($connection, 'file://'): + $savePath = substr($connection, 7); + + return new StrictSessionHandler(new NativeFileSessionHandler('' === $savePath ? null : $savePath)); + + case str_starts_with($connection, 'redis:'): + case str_starts_with($connection, 'rediss:'): + case str_starts_with($connection, 'memcached:'): + if (!class_exists(AbstractAdapter::class)) { + throw new \InvalidArgumentException(sprintf('Unsupported DSN "%s". Try running "composer require symfony/cache".', $connection)); + } + $handlerClass = str_starts_with($connection, 'memcached:') ? MemcachedSessionHandler::class : RedisSessionHandler::class; + $connection = AbstractAdapter::createConnection($connection, ['lazy' => true]); + + return new $handlerClass($connection, array_intersect_key($options ?: [], ['prefix' => 1, 'ttl' => 1])); + + case str_starts_with($connection, 'pdo_oci://'): + if (!class_exists(DriverManager::class)) { + throw new \InvalidArgumentException(sprintf('Unsupported DSN "%s". Try running "composer require doctrine/dbal".', $connection)); + } + $connection[3] = '-'; + $params = class_exists(DsnParser::class) ? (new DsnParser())->parse($connection) : ['url' => $connection]; + $config = new Configuration(); + if (class_exists(DefaultSchemaManagerFactory::class)) { + $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory()); + } + + $connection = DriverManager::getConnection($params, $config); + $connection = method_exists($connection, 'getNativeConnection') ? $connection->getNativeConnection() : $connection->getWrappedConnection(); + // no break; + + case str_starts_with($connection, 'mssql://'): + case str_starts_with($connection, 'mysql://'): + case str_starts_with($connection, 'mysql2://'): + case str_starts_with($connection, 'pgsql://'): + case str_starts_with($connection, 'postgres://'): + case str_starts_with($connection, 'postgresql://'): + case str_starts_with($connection, 'sqlsrv://'): + case str_starts_with($connection, 'sqlite://'): + case str_starts_with($connection, 'sqlite3://'): + return new PdoSessionHandler($connection, $options ?: []); + } + + throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', $connection)); + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php index fab8e9a1..f7c385f6 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/StrictSessionHandler.php @@ -24,15 +24,26 @@ class StrictSessionHandler extends AbstractSessionHandler public function __construct(\SessionHandlerInterface $handler) { if ($handler instanceof \SessionUpdateTimestampHandlerInterface) { - throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', \get_class($handler), self::class)); + throw new \LogicException(sprintf('"%s" is already an instance of "SessionUpdateTimestampHandlerInterface", you cannot wrap it with "%s".', get_debug_type($handler), self::class)); } $this->handler = $handler; } /** - * {@inheritdoc} + * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. + * + * @internal + */ + public function isWrapper(): bool + { + return $this->handler instanceof \SessionHandler; + } + + /** + * @return bool */ + #[\ReturnTypeWillChange] public function open($savePath, $sessionName) { parent::open($savePath, $sessionName); @@ -43,14 +54,15 @@ public function open($savePath, $sessionName) /** * {@inheritdoc} */ - protected function doRead($sessionId) + protected function doRead(string $sessionId) { return $this->handler->read($sessionId); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { return $this->write($sessionId, $data); @@ -59,14 +71,15 @@ public function updateTimestamp($sessionId, $data) /** * {@inheritdoc} */ - protected function doWrite($sessionId, $data) + protected function doWrite(string $sessionId, string $data) { return $this->handler->write($sessionId, $data); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function destroy($sessionId) { $this->doDestroy = true; @@ -78,7 +91,7 @@ public function destroy($sessionId) /** * {@inheritdoc} */ - protected function doDestroy($sessionId) + protected function doDestroy(string $sessionId) { $this->doDestroy = false; @@ -86,16 +99,18 @@ protected function doDestroy($sessionId) } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function close() { return $this->handler->close(); } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { return $this->handler->gc($maxlifetime); diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php deleted file mode 100644 index d1e5c140..00000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php +++ /dev/null @@ -1,92 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; - -/** - * Wraps another SessionHandlerInterface to only write the session when it has been modified. - * - * @author Adrien Brault - * - * @deprecated since version 3.4, to be removed in 4.0. Implement `SessionUpdateTimestampHandlerInterface` or extend `AbstractSessionHandler` instead. - */ -class WriteCheckSessionHandler implements \SessionHandlerInterface -{ - private $wrappedSessionHandler; - - /** - * @var array sessionId => session - */ - private $readSessions; - - public function __construct(\SessionHandlerInterface $wrappedSessionHandler) - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Implement `SessionUpdateTimestampHandlerInterface` or extend `AbstractSessionHandler` instead.', self::class), \E_USER_DEPRECATED); - - $this->wrappedSessionHandler = $wrappedSessionHandler; - } - - /** - * {@inheritdoc} - */ - public function close() - { - return $this->wrappedSessionHandler->close(); - } - - /** - * {@inheritdoc} - */ - public function destroy($sessionId) - { - return $this->wrappedSessionHandler->destroy($sessionId); - } - - /** - * {@inheritdoc} - */ - public function gc($maxlifetime) - { - return $this->wrappedSessionHandler->gc($maxlifetime); - } - - /** - * {@inheritdoc} - */ - public function open($savePath, $sessionName) - { - return $this->wrappedSessionHandler->open($savePath, $sessionName); - } - - /** - * {@inheritdoc} - */ - public function read($sessionId) - { - $session = $this->wrappedSessionHandler->read($sessionId); - - $this->readSessions[$sessionId] = $session; - - return $session; - } - - /** - * {@inheritdoc} - */ - public function write($sessionId, $data) - { - if (isset($this->readSessions[$sessionId]) && $data === $this->readSessions[$sessionId]) { - return true; - } - - return $this->wrappedSessionHandler->write($sessionId, $data); - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php b/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php index a62f108b..52d33209 100644 --- a/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php +++ b/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php @@ -22,9 +22,9 @@ */ class MetadataBag implements SessionBagInterface { - const CREATED = 'c'; - const UPDATED = 'u'; - const LIFETIME = 'l'; + public const CREATED = 'c'; + public const UPDATED = 'u'; + public const LIFETIME = 'l'; /** * @var string @@ -57,7 +57,7 @@ class MetadataBag implements SessionBagInterface * @param string $storageKey The key used to store bag in the session * @param int $updateThreshold The time to wait between two UPDATED updates */ - public function __construct($storageKey = '_sf2_meta', $updateThreshold = 0) + public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0) { $this->storageKey = $storageKey; $this->updateThreshold = $updateThreshold; @@ -95,12 +95,12 @@ public function getLifetime() /** * Stamps a new session's metadata. * - * @param int $lifetime Sets the cookie lifetime for the session cookie. A null value - * will leave the system settings unchanged, 0 sets the cookie - * to expire with browser session. Time is in seconds, and is - * not a Unix timestamp. + * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value + * will leave the system settings unchanged, 0 sets the cookie + * to expire with browser session. Time is in seconds, and is + * not a Unix timestamp. */ - public function stampNew($lifetime = null) + public function stampNew(int $lifetime = null) { $this->stampCreated($lifetime); } @@ -139,6 +139,7 @@ public function getLastUsed() public function clear() { // nothing to do + return null; } /** @@ -151,18 +152,16 @@ public function getName() /** * Sets name. - * - * @param string $name */ - public function setName($name) + public function setName(string $name) { $this->name = $name; } - private function stampCreated($lifetime = null) + private function stampCreated(int $lifetime = null): void { $timeStamp = time(); $this->meta[self::CREATED] = $this->meta[self::UPDATED] = $this->lastUsed = $timeStamp; - $this->meta[self::LIFETIME] = (null === $lifetime) ? ini_get('session.cookie_lifetime') : $lifetime; + $this->meta[self::LIFETIME] = $lifetime ?? (int) \ini_get('session.cookie_lifetime'); } } diff --git a/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php index 5474d92e..c5c2bb07 100644 --- a/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php @@ -62,11 +62,7 @@ class MockArraySessionStorage implements SessionStorageInterface */ protected $bags = []; - /** - * @param string $name Session name - * @param MetadataBag $metaBag MetadataBag instance - */ - public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null) + public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { $this->name = $name; $this->setMetadataBag($metaBag); @@ -98,7 +94,7 @@ public function start() /** * {@inheritdoc} */ - public function regenerate($destroy = false, $lifetime = null) + public function regenerate(bool $destroy = false, int $lifetime = null) { if (!$this->started) { $this->start(); @@ -121,7 +117,7 @@ public function getId() /** * {@inheritdoc} */ - public function setId($id) + public function setId(string $id) { if ($this->started) { throw new \LogicException('Cannot set session ID after the session has started.'); @@ -141,7 +137,7 @@ public function getName() /** * {@inheritdoc} */ - public function setName($name) + public function setName(string $name) { $this->name = $name; } @@ -187,7 +183,7 @@ public function registerBag(SessionBagInterface $bag) /** * {@inheritdoc} */ - public function getBag($name) + public function getBag(string $name) { if (!isset($this->bags[$name])) { throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); @@ -246,7 +242,7 @@ protected function loadSession() foreach ($bags as $bag) { $key = $bag->getStorageKey(); - $this->data[$key] = isset($this->data[$key]) ? $this->data[$key] : []; + $this->data[$key] = $this->data[$key] ?? []; $bag->initialize($this->data[$key]); } diff --git a/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php index c5b1d1a3..8e32a45e 100644 --- a/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php @@ -13,7 +13,8 @@ /** * MockFileSessionStorage is used to mock sessions for - * functional testing when done in a single PHP process. + * functional testing where you may need to persist session data + * across separate PHP processes. * * No PHP session is actually started since a session can be initialized * and shutdown only once per PHP execution cycle and this class does @@ -27,11 +28,9 @@ class MockFileSessionStorage extends MockArraySessionStorage private $savePath; /** - * @param string $savePath Path of directory to save session files - * @param string $name Session name - * @param MetadataBag $metaBag MetadataBag instance + * @param string|null $savePath Path of directory to save session files */ - public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null) + public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { if (null === $savePath) { $savePath = sys_get_temp_dir(); @@ -69,7 +68,7 @@ public function start() /** * {@inheritdoc} */ - public function regenerate($destroy = false, $lifetime = null) + public function regenerate(bool $destroy = false, int $lifetime = null) { if (!$this->started) { $this->start(); @@ -104,7 +103,10 @@ public function save() try { if ($data) { - file_put_contents($this->getFilePath(), serialize($data)); + $path = $this->getFilePath(); + $tmp = $path.bin2hex(random_bytes(6)); + file_put_contents($tmp, serialize($data)); + rename($tmp, $path); } else { $this->destroy(); } @@ -112,9 +114,8 @@ public function save() $this->data = $data; } - // this is needed for Silex, where the session object is re-used across requests - // in functional tests. In Symfony, the container is rebooted, so we don't have - // this issue + // this is needed when the session object is re-used across multiple requests + // in functional tests. $this->started = false; } @@ -122,19 +123,20 @@ public function save() * Deletes a session from persistent storage. * Deliberately leaves session data in memory intact. */ - private function destroy() + private function destroy(): void { - if (is_file($this->getFilePath())) { + set_error_handler(static function () {}); + try { unlink($this->getFilePath()); + } finally { + restore_error_handler(); } } /** * Calculate path to file. - * - * @return string File path */ - private function getFilePath() + private function getFilePath(): string { return $this->savePath.'/'.$this->id.'.mocksess'; } @@ -142,10 +144,16 @@ private function getFilePath() /** * Reads session from storage and loads session. */ - private function read() + private function read(): void { - $filePath = $this->getFilePath(); - $this->data = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : []; + set_error_handler(static function () {}); + try { + $data = file_get_contents($this->getFilePath()); + } finally { + restore_error_handler(); + } + + $this->data = $data ? unserialize($data) : []; $this->loadSession(); } diff --git a/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorageFactory.php b/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorageFactory.php new file mode 100644 index 00000000..d0da1e16 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorageFactory.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage; + +use Symfony\Component\HttpFoundation\Request; + +// Help opcache.preload discover always-needed symbols +class_exists(MockFileSessionStorage::class); + +/** + * @author Jérémy Derussé + */ +class MockFileSessionStorageFactory implements SessionStorageFactoryInterface +{ + private $savePath; + private $name; + private $metaBag; + + /** + * @see MockFileSessionStorage constructor. + */ + public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null) + { + $this->savePath = $savePath; + $this->name = $name; + $this->metaBag = $metaBag; + } + + public function createStorage(?Request $request): SessionStorageInterface + { + return new MockFileSessionStorage($this->savePath, $this->name, $this->metaBag); + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php index be84c6dc..242478c4 100644 --- a/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php @@ -17,6 +17,11 @@ use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; +// Help opcache.preload discover always-needed symbols +class_exists(MetadataBag::class); +class_exists(StrictSessionHandler::class); +class_exists(SessionHandlerProxy::class); + /** * This provides a base class for session attribute storage. * @@ -74,28 +79,17 @@ class NativeSessionStorage implements SessionStorageInterface * cookie_path, "/" * cookie_secure, "" * cookie_samesite, null - * entropy_file, "" - * entropy_length, "0" * gc_divisor, "100" * gc_maxlifetime, "1440" * gc_probability, "1" - * hash_bits_per_character, "4" - * hash_function, "0" * lazy_write, "1" * name, "PHPSESSID" * referer_check, "" * serialize_handler, "php" - * use_strict_mode, "0" + * use_strict_mode, "1" * use_cookies, "1" * use_only_cookies, "1" * use_trans_sid, "0" - * upload_progress.enabled, "1" - * upload_progress.cleanup, "1" - * upload_progress.prefix, "upload_progress_" - * upload_progress.name, "PHP_SESSION_UPLOAD_PROGRESS" - * upload_progress.freq, "1%" - * upload_progress.min-freq, "1" - * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset=" * sid_length, "32" * sid_bits_per_character, "5" * trans_sid_hosts, $_SERVER['HTTP_HOST'] @@ -114,6 +108,7 @@ public function __construct(array $options = [], $handler = null, MetadataBag $m 'cache_expire' => 0, 'use_cookies' => 1, 'lazy_write' => 1, + 'use_strict_mode' => 1, ]; session_register_shutdown(); @@ -146,10 +141,46 @@ public function start() throw new \RuntimeException('Failed to start the session: already started by PHP.'); } - if (filter_var(ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) { + if (filter_var(\ini_get('session.use_cookies'), \FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) { throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line)); } + $sessionId = $_COOKIE[session_name()] ?? null; + /* + * Explanation of the session ID regular expression: `/^[a-zA-Z0-9,-]{22,250}$/`. + * + * ---------- Part 1 + * + * The part `[a-zA-Z0-9,-]` is related to the PHP ini directive `session.sid_bits_per_character` defined as 6. + * See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-bits-per-character. + * Allowed values are integers such as: + * - 4 for range `a-f0-9` + * - 5 for range `a-v0-9` + * - 6 for range `a-zA-Z0-9,-` + * + * ---------- Part 2 + * + * The part `{22,250}` is related to the PHP ini directive `session.sid_length`. + * See https://www.php.net/manual/en/session.configuration.php#ini.session.sid-length. + * Allowed values are integers between 22 and 256, but we use 250 for the max. + * + * Where does the 250 come from? + * - The length of Windows and Linux filenames is limited to 255 bytes. Then the max must not exceed 255. + * - The session filename prefix is `sess_`, a 5 bytes string. Then the max must not exceed 255 - 5 = 250. + * + * ---------- Conclusion + * + * The parts 1 and 2 prevent the warning below: + * `PHP Warning: SessionHandler::read(): Session ID is too long or contains illegal characters. Only the A-Z, a-z, 0-9, "-", and "," characters are allowed.` + * + * The part 2 prevents the warning below: + * `PHP Warning: SessionHandler::read(): open(filepath, O_RDWR) failed: No such file or directory (2).` + */ + if ($sessionId && $this->saveHandler instanceof AbstractProxy && 'files' === $this->saveHandler->getSaveHandlerName() && !preg_match('/^[a-zA-Z0-9,-]{22,250}$/', $sessionId)) { + // the session ID in the header is invalid, create a new one + session_id(session_create_id()); + } + // ok to try and start the session if (!session_start()) { throw new \RuntimeException('Failed to start the session.'); @@ -178,7 +209,7 @@ public function getId() /** * {@inheritdoc} */ - public function setId($id) + public function setId(string $id) { $this->saveHandler->setId($id); } @@ -194,7 +225,7 @@ public function getName() /** * {@inheritdoc} */ - public function setName($name) + public function setName(string $name) { $this->saveHandler->setName($name); } @@ -202,7 +233,7 @@ public function setName($name) /** * {@inheritdoc} */ - public function regenerate($destroy = false, $lifetime = null) + public function regenerate(bool $destroy = false, int $lifetime = null) { // Cannot regenerate the session ID for non-active sessions. if (\PHP_SESSION_ACTIVE !== session_status()) { @@ -213,7 +244,7 @@ public function regenerate($destroy = false, $lifetime = null) return false; } - if (null !== $lifetime && $lifetime != ini_get('session.cookie_lifetime')) { + if (null !== $lifetime && $lifetime != \ini_get('session.cookie_lifetime')) { $this->save(); ini_set('session.cookie_lifetime', $lifetime); $this->start(); @@ -248,13 +279,13 @@ public function save() unset($_SESSION[$key]); } } - if ([$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) { + if ($_SESSION && [$key = $this->metadataBag->getStorageKey()] === array_keys($_SESSION)) { unset($_SESSION[$key]); } // Register error handler to add information about the current save handler $previousHandler = set_error_handler(function ($type, $msg, $file, $line) use (&$previousHandler) { - if (\E_WARNING === $type && 0 === strpos($msg, 'session_write_close():')) { + if (\E_WARNING === $type && str_starts_with($msg, 'session_write_close():')) { $handler = $this->saveHandler instanceof SessionHandlerProxy ? $this->saveHandler->getHandler() : $this->saveHandler; $msg = sprintf('session_write_close(): Failed to write session data with "%s" handler', \get_class($handler)); } @@ -309,7 +340,7 @@ public function registerBag(SessionBagInterface $bag) /** * {@inheritdoc} */ - public function getBag($name) + public function getBag(string $name) { if (!isset($this->bags[$name])) { throw new \InvalidArgumentException(sprintf('The SessionBagInterface "%s" is not registered.', $name)); @@ -370,9 +401,8 @@ public function setOptions(array $options) $validOptions = array_flip([ 'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly', 'cookie_lifetime', 'cookie_path', 'cookie_secure', 'cookie_samesite', - 'entropy_file', 'entropy_length', 'gc_divisor', - 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', - 'hash_function', 'lazy_write', 'name', 'referer_check', + 'gc_divisor', 'gc_maxlifetime', 'gc_probability', + 'lazy_write', 'name', 'referer_check', 'serialize_handler', 'use_strict_mode', 'use_cookies', 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled', 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name', @@ -382,12 +412,22 @@ public function setOptions(array $options) foreach ($options as $key => $value) { if (isset($validOptions[$key])) { + if (str_starts_with($key, 'upload_progress.')) { + trigger_deprecation('symfony/http-foundation', '5.4', 'Support for the "%s" session option is deprecated. The settings prefixed with "session.upload_progress." can not be changed at runtime.', $key); + continue; + } + if ('url_rewriter.tags' === $key) { + trigger_deprecation('symfony/http-foundation', '5.4', 'Support for the "%s" session option is deprecated. Use "trans_sid_tags" instead.', $key); + } if ('cookie_samesite' === $key && \PHP_VERSION_ID < 70300) { // PHP < 7.3 does not support same_site cookies. We will emulate it in // the start() method instead. $this->emulateSameSite = $value; continue; } + if ('cookie_secure' === $key && 'auto' === $value) { + continue; + } ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value); } } @@ -415,9 +455,10 @@ public function setOptions(array $options) */ public function setSaveHandler($saveHandler = null) { - if (!$saveHandler instanceof AbstractProxy && - !$saveHandler instanceof \SessionHandlerInterface && - null !== $saveHandler) { + if (!$saveHandler instanceof AbstractProxy + && !$saveHandler instanceof \SessionHandlerInterface + && null !== $saveHandler + ) { throw new \InvalidArgumentException('Must be instance of AbstractProxy; implement \SessionHandlerInterface; or be null.'); } diff --git a/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorageFactory.php b/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorageFactory.php new file mode 100644 index 00000000..a7d7411f --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorageFactory.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage; + +use Symfony\Component\HttpFoundation\Request; + +// Help opcache.preload discover always-needed symbols +class_exists(NativeSessionStorage::class); + +/** + * @author Jérémy Derussé + */ +class NativeSessionStorageFactory implements SessionStorageFactoryInterface +{ + private $options; + private $handler; + private $metaBag; + private $secure; + + /** + * @see NativeSessionStorage constructor. + */ + public function __construct(array $options = [], $handler = null, MetadataBag $metaBag = null, bool $secure = false) + { + $this->options = $options; + $this->handler = $handler; + $this->metaBag = $metaBag; + $this->secure = $secure; + } + + public function createStorage(?Request $request): SessionStorageInterface + { + $storage = new NativeSessionStorage($this->options, $this->handler, $this->metaBag); + if ($this->secure && $request && $request->isSecure()) { + $storage->setOptions(['cookie_secure' => true]); + } + + return $storage; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php index 8969e609..72dbef13 100644 --- a/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorage.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; +use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; + /** * Allows session to be started by PHP and managed by Symfony. * @@ -19,8 +21,7 @@ class PhpBridgeSessionStorage extends NativeSessionStorage { /** - * @param \SessionHandlerInterface|null $handler - * @param MetadataBag $metaBag MetadataBag + * @param AbstractProxy|\SessionHandlerInterface|null $handler */ public function __construct($handler = null, MetadataBag $metaBag = null) { diff --git a/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php b/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php new file mode 100644 index 00000000..173ef71d --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/PhpBridgeSessionStorageFactory.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage; + +use Symfony\Component\HttpFoundation\Request; + +// Help opcache.preload discover always-needed symbols +class_exists(PhpBridgeSessionStorage::class); + +/** + * @author Jérémy Derussé + */ +class PhpBridgeSessionStorageFactory implements SessionStorageFactoryInterface +{ + private $handler; + private $metaBag; + private $secure; + + /** + * @see PhpBridgeSessionStorage constructor. + */ + public function __construct($handler = null, MetadataBag $metaBag = null, bool $secure = false) + { + $this->handler = $handler; + $this->metaBag = $metaBag; + $this->secure = $secure; + } + + public function createStorage(?Request $request): SessionStorageInterface + { + $storage = new PhpBridgeSessionStorage($this->handler, $this->metaBag); + if ($this->secure && $request && $request->isSecure()) { + $storage->setOptions(['cookie_secure' => true]); + } + + return $storage; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php b/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php index 9e1c94dd..edd04dff 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php +++ b/vendor/symfony/http-foundation/Session/Storage/Proxy/AbstractProxy.php @@ -81,11 +81,9 @@ public function getId() /** * Sets the session ID. * - * @param string $id - * * @throws \LogicException */ - public function setId($id) + public function setId(string $id) { if ($this->isActive()) { throw new \LogicException('Cannot change the ID of an active session.'); @@ -107,11 +105,9 @@ public function getName() /** * Sets the session name. * - * @param string $name - * * @throws \LogicException */ - public function setName($name) + public function setName(string $name) { if ($this->isActive()) { throw new \LogicException('Cannot change the name of an active session.'); diff --git a/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php b/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php deleted file mode 100644 index 9d94ba97..00000000 --- a/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; - -@trigger_error('The '.__NAMESPACE__.'\NativeProxy class is deprecated since Symfony 3.4 and will be removed in 4.0. Use your session handler implementation directly.', \E_USER_DEPRECATED); - -/** - * This proxy is built-in session handlers in PHP 5.3.x. - * - * @deprecated since version 3.4, to be removed in 4.0. Use your session handler implementation directly. - * - * @author Drak - */ -class NativeProxy extends AbstractProxy -{ - public function __construct() - { - // this makes an educated guess as to what the handler is since it should already be set. - $this->saveHandlerName = ini_get('session.save_handler'); - } - - /** - * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. - * - * @return bool False - */ - public function isWrapper() - { - return false; - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php b/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php index e40712d9..0defa4a7 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php +++ b/vendor/symfony/http-foundation/Session/Storage/Proxy/SessionHandlerProxy.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Proxy; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; + /** * @author Drak */ @@ -21,8 +23,8 @@ class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterf public function __construct(\SessionHandlerInterface $handler) { $this->handler = $handler; - $this->wrapper = ($handler instanceof \SessionHandler); - $this->saveHandlerName = $this->wrapper ? ini_get('session.save_handler') : 'user'; + $this->wrapper = $handler instanceof \SessionHandler; + $this->saveHandlerName = $this->wrapper || ($handler instanceof StrictSessionHandler && $handler->isWrapper()) ? \ini_get('session.save_handler') : 'user'; } /** @@ -36,64 +38,72 @@ public function getHandler() // \SessionHandlerInterface /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function open($savePath, $sessionName) { - return (bool) $this->handler->open($savePath, $sessionName); + return $this->handler->open($savePath, $sessionName); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function close() { - return (bool) $this->handler->close(); + return $this->handler->close(); } /** - * {@inheritdoc} + * @return string|false */ + #[\ReturnTypeWillChange] public function read($sessionId) { - return (string) $this->handler->read($sessionId); + return $this->handler->read($sessionId); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function write($sessionId, $data) { - return (bool) $this->handler->write($sessionId, $data); + return $this->handler->write($sessionId, $data); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function destroy($sessionId) { - return (bool) $this->handler->destroy($sessionId); + return $this->handler->destroy($sessionId); } /** - * @return bool + * @return int|false */ + #[\ReturnTypeWillChange] public function gc($maxlifetime) { - return (bool) $this->handler->gc($maxlifetime); + return $this->handler->gc($maxlifetime); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function validateId($sessionId) { return !$this->handler instanceof \SessionUpdateTimestampHandlerInterface || $this->handler->validateId($sessionId); } /** - * {@inheritdoc} + * @return bool */ + #[\ReturnTypeWillChange] public function updateTimestamp($sessionId, $data) { return $this->handler instanceof \SessionUpdateTimestampHandlerInterface ? $this->handler->updateTimestamp($sessionId, $data) : $this->write($sessionId, $data); diff --git a/vendor/symfony/http-foundation/Session/Storage/ServiceSessionFactory.php b/vendor/symfony/http-foundation/Session/Storage/ServiceSessionFactory.php new file mode 100644 index 00000000..d17c60ae --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/ServiceSessionFactory.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage; + +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Jérémy Derussé + * + * @internal to be removed in Symfony 6 + */ +final class ServiceSessionFactory implements SessionStorageFactoryInterface +{ + private $storage; + + public function __construct(SessionStorageInterface $storage) + { + $this->storage = $storage; + } + + public function createStorage(?Request $request): SessionStorageInterface + { + if ($this->storage instanceof NativeSessionStorage && $request && $request->isSecure()) { + $this->storage->setOptions(['cookie_secure' => true]); + } + + return $this->storage; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/SessionStorageFactoryInterface.php b/vendor/symfony/http-foundation/Session/Storage/SessionStorageFactoryInterface.php new file mode 100644 index 00000000..d03f0da4 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/SessionStorageFactoryInterface.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Session\Storage; + +use Symfony\Component\HttpFoundation\Request; + +/** + * @author Jérémy Derussé + */ +interface SessionStorageFactoryInterface +{ + /** + * Creates a new instance of SessionStorageInterface. + */ + public function createStorage(?Request $request): SessionStorageInterface; +} diff --git a/vendor/symfony/http-foundation/Session/Storage/SessionStorageInterface.php b/vendor/symfony/http-foundation/Session/Storage/SessionStorageInterface.php index eeb396a2..70537455 100644 --- a/vendor/symfony/http-foundation/Session/Storage/SessionStorageInterface.php +++ b/vendor/symfony/http-foundation/Session/Storage/SessionStorageInterface.php @@ -24,7 +24,7 @@ interface SessionStorageInterface /** * Starts the session. * - * @return bool True if started + * @return bool * * @throws \RuntimeException if something goes wrong starting the session */ @@ -33,37 +33,33 @@ public function start(); /** * Checks if the session is started. * - * @return bool True if started, false otherwise + * @return bool */ public function isStarted(); /** * Returns the session ID. * - * @return string The session ID or empty + * @return string */ public function getId(); /** * Sets the session ID. - * - * @param string $id */ - public function setId($id); + public function setId(string $id); /** * Returns the session name. * - * @return mixed The session name + * @return string */ public function getName(); /** * Sets the session name. - * - * @param string $name */ - public function setName($name); + public function setName(string $name); /** * Regenerates id that represents this storage. @@ -84,17 +80,17 @@ public function setName($name); * Otherwise session data could get lost again for concurrent requests with the * new ID. One result could be that you get logged out after just logging in. * - * @param bool $destroy Destroy session when regenerating? - * @param int $lifetime Sets the cookie lifetime for the session cookie. A null value - * will leave the system settings unchanged, 0 sets the cookie - * to expire with browser session. Time is in seconds, and is - * not a Unix timestamp. + * @param bool $destroy Destroy session when regenerating? + * @param int|null $lifetime Sets the cookie lifetime for the session cookie. A null value + * will leave the system settings unchanged, 0 sets the cookie + * to expire with browser session. Time is in seconds, and is + * not a Unix timestamp. * - * @return bool True if session regenerated, false if error + * @return bool * * @throws \RuntimeException If an error occurs while regenerating this storage */ - public function regenerate($destroy = false, $lifetime = null); + public function regenerate(bool $destroy = false, int $lifetime = null); /** * Force the session to be saved and closed. @@ -117,13 +113,11 @@ public function clear(); /** * Gets a SessionBagInterface by name. * - * @param string $name - * * @return SessionBagInterface * * @throws \InvalidArgumentException If the bag does not exist */ - public function getBag($name); + public function getBag(string $name); /** * Registers a SessionBagInterface for use. diff --git a/vendor/symfony/http-foundation/StreamedResponse.php b/vendor/symfony/http-foundation/StreamedResponse.php index b9148ea8..0599bd1e 100644 --- a/vendor/symfony/http-foundation/StreamedResponse.php +++ b/vendor/symfony/http-foundation/StreamedResponse.php @@ -30,12 +30,7 @@ class StreamedResponse extends Response protected $streamed; private $headersSent; - /** - * @param callable|null $callback A valid PHP callback or null to set it later - * @param int $status The response status code - * @param array $headers An array of response headers - */ - public function __construct(callable $callback = null, $status = 200, $headers = []) + public function __construct(callable $callback = null, int $status = 200, array $headers = []) { parent::__construct(null, $status, $headers); @@ -50,21 +45,21 @@ public function __construct(callable $callback = null, $status = 200, $headers = * Factory method for chainability. * * @param callable|null $callback A valid PHP callback or null to set it later - * @param int $status The response status code - * @param array $headers An array of response headers * * @return static + * + * @deprecated since Symfony 5.1, use __construct() instead. */ - public static function create($callback = null, $status = 200, $headers = []) + public static function create($callback = null, int $status = 200, array $headers = []) { + trigger_deprecation('symfony/http-foundation', '5.1', 'The "%s()" method is deprecated, use "new %s()" instead.', __METHOD__, static::class); + return new static($callback, $status, $headers); } /** * Sets the PHP callback associated with this Response. * - * @param callable $callback A valid PHP callback - * * @return $this */ public function setCallback(callable $callback) @@ -111,7 +106,7 @@ public function sendContent() throw new \LogicException('The Response callback must not be null.'); } - \call_user_func($this->callback); + ($this->callback)(); return $this; } @@ -119,11 +114,11 @@ public function sendContent() /** * {@inheritdoc} * - * @throws \LogicException when the content is not null - * * @return $this + * + * @throws \LogicException when the content is not null */ - public function setContent($content) + public function setContent(?string $content) { if (null !== $content) { throw new \LogicException('The content cannot be set on a StreamedResponse instance.'); diff --git a/vendor/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php b/vendor/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php new file mode 100644 index 00000000..cb216ea1 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Request; + +final class RequestAttributeValueSame extends Constraint +{ + private $name; + private $value; + + public function __construct(string $name, string $value) + { + $this->name = $name; + $this->value = $value; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has attribute "%s" with value "%s"', $this->name, $this->value); + } + + /** + * @param Request $request + * + * {@inheritdoc} + */ + protected function matches($request): bool + { + return $this->value === $request->attributes->get($this->name); + } + + /** + * @param Request $request + * + * {@inheritdoc} + */ + protected function failureDescription($request): string + { + return 'the Request '.$this->toString(); + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php new file mode 100644 index 00000000..eb9c26a3 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseCookieValueSame extends Constraint +{ + private $name; + private $value; + private $path; + private $domain; + + public function __construct(string $name, string $value, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->value = $value; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + $str .= sprintf(' with value "%s"', $this->value); + + return $str; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + $cookie = $this->getCookie($response); + if (!$cookie) { + return false; + } + + return $this->value === (string) $cookie->getValue(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + protected function getCookie(Response $response): ?Cookie + { + $cookies = $response->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) { + return $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain; + }); + + return reset($filteredCookies) ?: null; + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php new file mode 100644 index 00000000..f73aedfa --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseFormatSame.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Asserts that the response is in the given format. + * + * @author Kévin Dunglas + */ +final class ResponseFormatSame extends Constraint +{ + private $request; + private $format; + + public function __construct(Request $request, ?string $format) + { + $this->request = $request; + $this->format = $format; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'format is '.($this->format ?? 'null'); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->format === $this->request->getFormat($response->headers->get('Content-Type')); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php new file mode 100644 index 00000000..eae9e271 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHasCookie extends Constraint +{ + private $name; + private $path; + private $domain; + + public function __construct(string $name, string $path = '/', string $domain = null) + { + $this->name = $name; + $this->path = $path; + $this->domain = $domain; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + $str = sprintf('has cookie "%s"', $this->name); + if ('/' !== $this->path) { + $str .= sprintf(' with path "%s"', $this->path); + } + if ($this->domain) { + $str .= sprintf(' for domain "%s"', $this->domain); + } + + return $str; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return null !== $this->getCookie($response); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + private function getCookie(Response $response): ?Cookie + { + $cookies = $response->headers->getCookies(); + + $filteredCookies = array_filter($cookies, function (Cookie $cookie) { + return $cookie->getName() === $this->name && $cookie->getPath() === $this->path && $cookie->getDomain() === $this->domain; + }); + + return reset($filteredCookies) ?: null; + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php new file mode 100644 index 00000000..68ad8273 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHasHeader extends Constraint +{ + private $headerName; + + public function __construct(string $headerName) + { + $this->headerName = $headerName; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s"', $this->headerName); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->headers->has($this->headerName); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php new file mode 100644 index 00000000..a27d0c73 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseHeaderSame extends Constraint +{ + private $headerName; + private $expectedValue; + + public function __construct(string $headerName, string $expectedValue) + { + $this->headerName = $headerName; + $this->expectedValue = $expectedValue; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return sprintf('has header "%s" with value "%s"', $this->headerName, $this->expectedValue); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->expectedValue === $response->headers->get($this->headerName, null); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php new file mode 100644 index 00000000..8c4b883f --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsRedirected extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is redirected'; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->isRedirect(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php new file mode 100644 index 00000000..9c665589 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsSuccessful extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is successful'; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $response->isSuccessful(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php new file mode 100644 index 00000000..880c7818 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsUnprocessable.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseIsUnprocessable extends Constraint +{ + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'is unprocessable'; + } + + /** + * @param Response $other + * + * {@inheritdoc} + */ + protected function matches($other): bool + { + return Response::HTTP_UNPROCESSABLE_ENTITY === $other->getStatusCode(); + } + + /** + * @param Response $other + * + * {@inheritdoc} + */ + protected function failureDescription($other): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $other + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($other): string + { + return (string) $other; + } +} diff --git a/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php new file mode 100644 index 00000000..72bb000b --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Test\Constraint; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\HttpFoundation\Response; + +final class ResponseStatusCodeSame extends Constraint +{ + private $statusCode; + + public function __construct(int $statusCode) + { + $this->statusCode = $statusCode; + } + + /** + * {@inheritdoc} + */ + public function toString(): string + { + return 'status code is '.$this->statusCode; + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function matches($response): bool + { + return $this->statusCode === $response->getStatusCode(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function failureDescription($response): string + { + return 'the Response '.$this->toString(); + } + + /** + * @param Response $response + * + * {@inheritdoc} + */ + protected function additionalFailureDescription($response): string + { + return (string) $response; + } +} diff --git a/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php b/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php deleted file mode 100644 index a40a7621..00000000 --- a/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\AcceptHeaderItem; - -class AcceptHeaderItemTest extends TestCase -{ - /** - * @dataProvider provideFromStringData - */ - public function testFromString($string, $value, array $attributes) - { - $item = AcceptHeaderItem::fromString($string); - $this->assertEquals($value, $item->getValue()); - $this->assertEquals($attributes, $item->getAttributes()); - } - - public function provideFromStringData() - { - return [ - [ - 'text/html', - 'text/html', [], - ], - [ - '"this;should,not=matter"', - 'this;should,not=matter', [], - ], - [ - "text/plain; charset=utf-8;param=\"this;should,not=matter\";\tfootnotes=true", - 'text/plain', ['charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true'], - ], - [ - '"this;should,not=matter";charset=utf-8', - 'this;should,not=matter', ['charset' => 'utf-8'], - ], - ]; - } - - /** - * @dataProvider provideToStringData - */ - public function testToString($value, array $attributes, $string) - { - $item = new AcceptHeaderItem($value, $attributes); - $this->assertEquals($string, (string) $item); - } - - public function provideToStringData() - { - return [ - [ - 'text/html', [], - 'text/html', - ], - [ - 'text/plain', ['charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true'], - 'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true', - ], - ]; - } - - public function testValue() - { - $item = new AcceptHeaderItem('value', []); - $this->assertEquals('value', $item->getValue()); - - $item->setValue('new value'); - $this->assertEquals('new value', $item->getValue()); - - $item->setValue(1); - $this->assertEquals('1', $item->getValue()); - } - - public function testQuality() - { - $item = new AcceptHeaderItem('value', []); - $this->assertEquals(1.0, $item->getQuality()); - - $item->setQuality(0.5); - $this->assertEquals(0.5, $item->getQuality()); - - $item->setAttribute('q', 0.75); - $this->assertEquals(0.75, $item->getQuality()); - $this->assertFalse($item->hasAttribute('q')); - } - - public function testAttribute() - { - $item = new AcceptHeaderItem('value', []); - $this->assertEquals([], $item->getAttributes()); - $this->assertFalse($item->hasAttribute('test')); - $this->assertNull($item->getAttribute('test')); - $this->assertEquals('default', $item->getAttribute('test', 'default')); - - $item->setAttribute('test', 'value'); - $this->assertEquals(['test' => 'value'], $item->getAttributes()); - $this->assertTrue($item->hasAttribute('test')); - $this->assertEquals('value', $item->getAttribute('test')); - $this->assertEquals('value', $item->getAttribute('test', 'default')); - } -} diff --git a/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php b/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php deleted file mode 100644 index 31998696..00000000 --- a/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php +++ /dev/null @@ -1,103 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\AcceptHeader; -use Symfony\Component\HttpFoundation\AcceptHeaderItem; - -class AcceptHeaderTest extends TestCase -{ - public function testFirst() - { - $header = AcceptHeader::fromString('text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c'); - $this->assertSame('text/html', $header->first()->getValue()); - } - - /** - * @dataProvider provideFromStringData - */ - public function testFromString($string, array $items) - { - $header = AcceptHeader::fromString($string); - $parsed = array_values($header->all()); - // reset index since the fixtures don't have them set - foreach ($parsed as $item) { - $item->setIndex(0); - } - $this->assertEquals($items, $parsed); - } - - public function provideFromStringData() - { - return [ - ['', []], - ['gzip', [new AcceptHeaderItem('gzip')]], - ['gzip,deflate,sdch', [new AcceptHeaderItem('gzip'), new AcceptHeaderItem('deflate'), new AcceptHeaderItem('sdch')]], - ["gzip, deflate\t,sdch", [new AcceptHeaderItem('gzip'), new AcceptHeaderItem('deflate'), new AcceptHeaderItem('sdch')]], - ['"this;should,not=matter"', [new AcceptHeaderItem('this;should,not=matter')]], - ]; - } - - /** - * @dataProvider provideToStringData - */ - public function testToString(array $items, $string) - { - $header = new AcceptHeader($items); - $this->assertEquals($string, (string) $header); - } - - public function provideToStringData() - { - return [ - [[], ''], - [[new AcceptHeaderItem('gzip')], 'gzip'], - [[new AcceptHeaderItem('gzip'), new AcceptHeaderItem('deflate'), new AcceptHeaderItem('sdch')], 'gzip,deflate,sdch'], - [[new AcceptHeaderItem('this;should,not=matter')], 'this;should,not=matter'], - ]; - } - - /** - * @dataProvider provideFilterData - */ - public function testFilter($string, $filter, array $values) - { - $header = AcceptHeader::fromString($string)->filter($filter); - $this->assertEquals($values, array_keys($header->all())); - } - - public function provideFilterData() - { - return [ - ['fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4', '/fr.*/', ['fr-FR', 'fr']], - ]; - } - - /** - * @dataProvider provideSortingData - */ - public function testSorting($string, array $values) - { - $header = AcceptHeader::fromString($string); - $this->assertEquals($values, array_keys($header->all())); - } - - public function provideSortingData() - { - return [ - 'quality has priority' => ['*;q=0.3,ISO-8859-1,utf-8;q=0.7', ['ISO-8859-1', 'utf-8', '*']], - 'order matters when q is equal' => ['*;q=0.3,ISO-8859-1;q=0.7,utf-8;q=0.7', ['ISO-8859-1', 'utf-8', '*']], - 'order matters when q is equal2' => ['*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', ['utf-8', 'ISO-8859-1', '*']], - ]; - } -} diff --git a/vendor/symfony/http-foundation/Tests/ApacheRequestTest.php b/vendor/symfony/http-foundation/Tests/ApacheRequestTest.php deleted file mode 100644 index 6fa3b889..00000000 --- a/vendor/symfony/http-foundation/Tests/ApacheRequestTest.php +++ /dev/null @@ -1,93 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\ApacheRequest; - -class ApacheRequestTest extends TestCase -{ - /** - * @dataProvider provideServerVars - */ - public function testUriMethods($server, $expectedRequestUri, $expectedBaseUrl, $expectedPathInfo) - { - $request = new ApacheRequest(); - $request->server->replace($server); - - $this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct'); - $this->assertEquals($expectedBaseUrl, $request->getBaseUrl(), '->getBaseUrl() is correct'); - $this->assertEquals($expectedPathInfo, $request->getPathInfo(), '->getPathInfo() is correct'); - } - - public function provideServerVars() - { - return [ - [ - [ - 'REQUEST_URI' => '/foo/app_dev.php/bar', - 'SCRIPT_NAME' => '/foo/app_dev.php', - 'PATH_INFO' => '/bar', - ], - '/foo/app_dev.php/bar', - '/foo/app_dev.php', - '/bar', - ], - [ - [ - 'REQUEST_URI' => '/foo/bar', - 'SCRIPT_NAME' => '/foo/app_dev.php', - ], - '/foo/bar', - '/foo', - '/bar', - ], - [ - [ - 'REQUEST_URI' => '/app_dev.php/foo/bar', - 'SCRIPT_NAME' => '/app_dev.php', - 'PATH_INFO' => '/foo/bar', - ], - '/app_dev.php/foo/bar', - '/app_dev.php', - '/foo/bar', - ], - [ - [ - 'REQUEST_URI' => '/foo/bar', - 'SCRIPT_NAME' => '/app_dev.php', - ], - '/foo/bar', - '', - '/foo/bar', - ], - [ - [ - 'REQUEST_URI' => '/app_dev.php', - 'SCRIPT_NAME' => '/app_dev.php', - ], - '/app_dev.php', - '/app_dev.php', - '/', - ], - [ - [ - 'REQUEST_URI' => '/', - 'SCRIPT_NAME' => '/app_dev.php', - ], - '/', - '', - '/', - ], - ]; - } -} diff --git a/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php b/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php deleted file mode 100644 index 38cc8442..00000000 --- a/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php +++ /dev/null @@ -1,387 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use Symfony\Component\HttpFoundation\BinaryFileResponse; -use Symfony\Component\HttpFoundation\File\Stream; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\ResponseHeaderBag; -use Symfony\Component\HttpFoundation\Tests\File\FakeFile; - -class BinaryFileResponseTest extends ResponseTestCase -{ - public function testConstruction() - { - $file = __DIR__.'/../README.md'; - $response = new BinaryFileResponse($file, 404, ['X-Header' => 'Foo'], true, null, true, true); - $this->assertEquals(404, $response->getStatusCode()); - $this->assertEquals('Foo', $response->headers->get('X-Header')); - $this->assertTrue($response->headers->has('ETag')); - $this->assertTrue($response->headers->has('Last-Modified')); - $this->assertFalse($response->headers->has('Content-Disposition')); - - $response = BinaryFileResponse::create($file, 404, [], true, ResponseHeaderBag::DISPOSITION_INLINE); - $this->assertEquals(404, $response->getStatusCode()); - $this->assertFalse($response->headers->has('ETag')); - $this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition')); - } - - public function testConstructWithNonAsciiFilename() - { - touch(sys_get_temp_dir().'/fööö.html'); - - $response = new BinaryFileResponse(sys_get_temp_dir().'/fööö.html', 200, [], true, 'attachment'); - - @unlink(sys_get_temp_dir().'/fööö.html'); - - $this->assertSame('fööö.html', $response->getFile()->getFilename()); - } - - public function testSetContent() - { - $this->expectException('LogicException'); - $response = new BinaryFileResponse(__FILE__); - $response->setContent('foo'); - } - - public function testGetContent() - { - $response = new BinaryFileResponse(__FILE__); - $this->assertFalse($response->getContent()); - } - - public function testSetContentDispositionGeneratesSafeFallbackFilename() - { - $response = new BinaryFileResponse(__FILE__); - $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html'); - - $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition')); - } - - public function testSetContentDispositionGeneratesSafeFallbackFilenameForWronglyEncodedFilename() - { - $response = new BinaryFileResponse(__FILE__); - - $iso88591EncodedFilename = utf8_decode('föö.html'); - $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $iso88591EncodedFilename); - - // the parameter filename* is invalid in this case (rawurldecode('f%F6%F6') does not provide a UTF-8 string but an ISO-8859-1 encoded one) - $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition')); - } - - /** - * @dataProvider provideRanges - */ - public function testRequests($requestRange, $offset, $length, $responseRange) - { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream'])->setAutoEtag(); - - // do a request to get the ETag - $request = Request::create('/'); - $response->prepare($request); - $etag = $response->headers->get('ETag'); - - // prepare a request for a range of the testing file - $request = Request::create('/'); - $request->headers->set('If-Range', $etag); - $request->headers->set('Range', $requestRange); - - $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); - fseek($file, $offset); - $data = fread($file, $length); - fclose($file); - - $this->expectOutputString($data); - $response = clone $response; - $response->prepare($request); - $response->sendContent(); - - $this->assertEquals(206, $response->getStatusCode()); - $this->assertEquals($responseRange, $response->headers->get('Content-Range')); - $this->assertSame((string) $length, $response->headers->get('Content-Length')); - } - - /** - * @dataProvider provideRanges - */ - public function testRequestsWithoutEtag($requestRange, $offset, $length, $responseRange) - { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); - - // do a request to get the LastModified - $request = Request::create('/'); - $response->prepare($request); - $lastModified = $response->headers->get('Last-Modified'); - - // prepare a request for a range of the testing file - $request = Request::create('/'); - $request->headers->set('If-Range', $lastModified); - $request->headers->set('Range', $requestRange); - - $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); - fseek($file, $offset); - $data = fread($file, $length); - fclose($file); - - $this->expectOutputString($data); - $response = clone $response; - $response->prepare($request); - $response->sendContent(); - - $this->assertEquals(206, $response->getStatusCode()); - $this->assertEquals($responseRange, $response->headers->get('Content-Range')); - } - - public function provideRanges() - { - return [ - ['bytes=1-4', 1, 4, 'bytes 1-4/35'], - ['bytes=-5', 30, 5, 'bytes 30-34/35'], - ['bytes=30-', 30, 5, 'bytes 30-34/35'], - ['bytes=30-30', 30, 1, 'bytes 30-30/35'], - ['bytes=30-34', 30, 5, 'bytes 30-34/35'], - ['bytes=30-40', 30, 5, 'bytes 30-34/35'], - ]; - } - - public function testRangeRequestsWithoutLastModifiedDate() - { - // prevent auto last modified - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream'], true, null, false, false); - - // prepare a request for a range of the testing file - $request = Request::create('/'); - $request->headers->set('If-Range', date('D, d M Y H:i:s').' GMT'); - $request->headers->set('Range', 'bytes=1-4'); - - $this->expectOutputString(file_get_contents(__DIR__.'/File/Fixtures/test.gif')); - $response = clone $response; - $response->prepare($request); - $response->sendContent(); - - $this->assertEquals(200, $response->getStatusCode()); - $this->assertNull($response->headers->get('Content-Range')); - } - - /** - * @dataProvider provideFullFileRanges - */ - public function testFullFileRequests($requestRange) - { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream'])->setAutoEtag(); - - // prepare a request for a range of the testing file - $request = Request::create('/'); - $request->headers->set('Range', $requestRange); - - $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); - $data = fread($file, 35); - fclose($file); - - $this->expectOutputString($data); - $response = clone $response; - $response->prepare($request); - $response->sendContent(); - - $this->assertEquals(200, $response->getStatusCode()); - } - - public function provideFullFileRanges() - { - return [ - ['bytes=0-'], - ['bytes=0-34'], - ['bytes=-35'], - // Syntactical invalid range-request should also return the full resource - ['bytes=20-10'], - ['bytes=50-40'], - // range units other than bytes must be ignored - ['unknown=10-20'], - ]; - } - - public function testRangeOnPostMethod() - { - $request = Request::create('/', 'POST'); - $request->headers->set('Range', 'bytes=10-20'); - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); - - $file = fopen(__DIR__.'/File/Fixtures/test.gif', 'r'); - $data = fread($file, 35); - fclose($file); - - $this->expectOutputString($data); - $response = clone $response; - $response->prepare($request); - $response->sendContent(); - - $this->assertSame(200, $response->getStatusCode()); - $this->assertSame('35', $response->headers->get('Content-Length')); - $this->assertNull($response->headers->get('Content-Range')); - } - - public function testUnpreparedResponseSendsFullFile() - { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200); - - $data = file_get_contents(__DIR__.'/File/Fixtures/test.gif'); - - $this->expectOutputString($data); - $response = clone $response; - $response->sendContent(); - - $this->assertEquals(200, $response->getStatusCode()); - } - - /** - * @dataProvider provideInvalidRanges - */ - public function testInvalidRequests($requestRange) - { - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream'])->setAutoEtag(); - - // prepare a request for a range of the testing file - $request = Request::create('/'); - $request->headers->set('Range', $requestRange); - - $response = clone $response; - $response->prepare($request); - $response->sendContent(); - - $this->assertEquals(416, $response->getStatusCode()); - $this->assertEquals('bytes */35', $response->headers->get('Content-Range')); - } - - public function provideInvalidRanges() - { - return [ - ['bytes=-40'], - ['bytes=40-50'], - ]; - } - - /** - * @dataProvider provideXSendfileFiles - */ - public function testXSendfile($file) - { - $request = Request::create('/'); - $request->headers->set('X-Sendfile-Type', 'X-Sendfile'); - - BinaryFileResponse::trustXSendfileTypeHeader(); - $response = BinaryFileResponse::create($file, 200, ['Content-Type' => 'application/octet-stream']); - $response->prepare($request); - - $this->expectOutputString(''); - $response->sendContent(); - - $this->assertStringContainsString('README.md', $response->headers->get('X-Sendfile')); - } - - public function provideXSendfileFiles() - { - return [ - [__DIR__.'/../README.md'], - ['file://'.__DIR__.'/../README.md'], - ]; - } - - /** - * @dataProvider getSampleXAccelMappings - */ - public function testXAccelMapping($realpath, $mapping, $virtual) - { - $request = Request::create('/'); - $request->headers->set('X-Sendfile-Type', 'X-Accel-Redirect'); - $request->headers->set('X-Accel-Mapping', $mapping); - - $file = new FakeFile($realpath, __DIR__.'/File/Fixtures/test'); - - BinaryFileResponse::trustXSendfileTypeHeader(); - $response = new BinaryFileResponse($file, 200, ['Content-Type' => 'application/octet-stream']); - $reflection = new \ReflectionObject($response); - $property = $reflection->getProperty('file'); - $property->setAccessible(true); - $property->setValue($response, $file); - - $response->prepare($request); - $this->assertEquals($virtual, $response->headers->get('X-Accel-Redirect')); - } - - public function testDeleteFileAfterSend() - { - $request = Request::create('/'); - - $path = __DIR__.'/File/Fixtures/to_delete'; - touch($path); - $realPath = realpath($path); - $this->assertFileExists($realPath); - - $response = new BinaryFileResponse($realPath, 200, ['Content-Type' => 'application/octet-stream']); - $response->deleteFileAfterSend(true); - - $response->prepare($request); - $response->sendContent(); - - $this->assertFileDoesNotExist($path); - } - - public function testAcceptRangeOnUnsafeMethods() - { - $request = Request::create('/', 'POST'); - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); - $response->prepare($request); - - $this->assertEquals('none', $response->headers->get('Accept-Ranges')); - } - - public function testAcceptRangeNotOverriden() - { - $request = Request::create('/', 'POST'); - $response = BinaryFileResponse::create(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); - $response->headers->set('Accept-Ranges', 'foo'); - $response->prepare($request); - - $this->assertEquals('foo', $response->headers->get('Accept-Ranges')); - } - - public function getSampleXAccelMappings() - { - return [ - ['/var/www/var/www/files/foo.txt', '/var/www/=/files/', '/files/var/www/files/foo.txt'], - ['/home/foo/bar.txt', '/var/www/=/files/,/home/foo/=/baz/', '/baz/bar.txt'], - ['/tmp/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', null], - ]; - } - - public function testStream() - { - $request = Request::create('/'); - $response = new BinaryFileResponse(new Stream(__DIR__.'/../README.md'), 200, ['Content-Type' => 'text/plain']); - $response->prepare($request); - - $this->assertNull($response->headers->get('Content-Length')); - } - - protected function provideResponse() - { - return new BinaryFileResponse(__DIR__.'/../README.md', 200, ['Content-Type' => 'application/octet-stream']); - } - - public static function tearDownAfterClass() - { - $path = __DIR__.'/../Fixtures/to_delete'; - if (file_exists($path)) { - @unlink($path); - } - } -} diff --git a/vendor/symfony/http-foundation/Tests/CookieTest.php b/vendor/symfony/http-foundation/Tests/CookieTest.php deleted file mode 100644 index 637cff0d..00000000 --- a/vendor/symfony/http-foundation/Tests/CookieTest.php +++ /dev/null @@ -1,243 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Cookie; - -/** - * CookieTest. - * - * @author John Kary - * @author Hugo Hamon - * - * @group time-sensitive - */ -class CookieTest extends TestCase -{ - public function namesWithSpecialCharacters() - { - return [ - [',MyName'], - [';MyName'], - [' MyName'], - ["\tMyName"], - ["\rMyName"], - ["\nMyName"], - ["\013MyName"], - ["\014MyName"], - ]; - } - - /** - * @dataProvider namesWithSpecialCharacters - */ - public function testInstantiationThrowsExceptionIfRawCookieNameContainsSpecialCharacters($name) - { - $this->expectException('InvalidArgumentException'); - new Cookie($name, null, 0, null, null, null, false, true); - } - - /** - * @dataProvider namesWithSpecialCharacters - */ - public function testInstantiationSucceedNonRawCookieNameContainsSpecialCharacters($name) - { - $this->assertInstanceOf(Cookie::class, new Cookie($name)); - } - - public function testInstantiationThrowsExceptionIfCookieNameIsEmpty() - { - $this->expectException('InvalidArgumentException'); - new Cookie(''); - } - - public function testInvalidExpiration() - { - $this->expectException('InvalidArgumentException'); - new Cookie('MyCookie', 'foo', 'bar'); - } - - public function testNegativeExpirationIsNotPossible() - { - $cookie = new Cookie('foo', 'bar', -100); - - $this->assertSame(0, $cookie->getExpiresTime()); - } - - public function testGetValue() - { - $value = 'MyValue'; - $cookie = new Cookie('MyCookie', $value); - - $this->assertSame($value, $cookie->getValue(), '->getValue() returns the proper value'); - } - - public function testGetPath() - { - $cookie = new Cookie('foo', 'bar'); - - $this->assertSame('/', $cookie->getPath(), '->getPath() returns / as the default path'); - } - - public function testGetExpiresTime() - { - $cookie = new Cookie('foo', 'bar'); - - $this->assertEquals(0, $cookie->getExpiresTime(), '->getExpiresTime() returns the default expire date'); - - $cookie = new Cookie('foo', 'bar', $expire = time() + 3600); - - $this->assertEquals($expire, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); - } - - public function testGetExpiresTimeIsCastToInt() - { - $cookie = new Cookie('foo', 'bar', 3600.9); - - $this->assertSame(3600, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date as an integer'); - } - - public function testConstructorWithDateTime() - { - $expire = new \DateTime(); - $cookie = new Cookie('foo', 'bar', $expire); - - $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); - } - - public function testConstructorWithDateTimeImmutable() - { - $expire = new \DateTimeImmutable(); - $cookie = new Cookie('foo', 'bar', $expire); - - $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); - } - - public function testGetExpiresTimeWithStringValue() - { - $value = '+1 day'; - $cookie = new Cookie('foo', 'bar', $value); - $expire = strtotime($value); - - $this->assertEqualsWithDelta($expire, $cookie->getExpiresTime(), 1, '->getExpiresTime() returns the expire date'); - } - - public function testGetDomain() - { - $cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com'); - - $this->assertEquals('.myfoodomain.com', $cookie->getDomain(), '->getDomain() returns the domain name on which the cookie is valid'); - } - - public function testIsSecure() - { - $cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com', true); - - $this->assertTrue($cookie->isSecure(), '->isSecure() returns whether the cookie is transmitted over HTTPS'); - } - - public function testIsHttpOnly() - { - $cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com', false, true); - - $this->assertTrue($cookie->isHttpOnly(), '->isHttpOnly() returns whether the cookie is only transmitted over HTTP'); - } - - public function testCookieIsNotCleared() - { - $cookie = new Cookie('foo', 'bar', time() + 3600 * 24); - - $this->assertFalse($cookie->isCleared(), '->isCleared() returns false if the cookie did not expire yet'); - } - - public function testCookieIsCleared() - { - $cookie = new Cookie('foo', 'bar', time() - 20); - - $this->assertTrue($cookie->isCleared(), '->isCleared() returns true if the cookie has expired'); - - $cookie = new Cookie('foo', 'bar'); - - $this->assertFalse($cookie->isCleared()); - - $cookie = new Cookie('foo', 'bar', 0); - - $this->assertFalse($cookie->isCleared()); - - $cookie = new Cookie('foo', 'bar', -1); - - $this->assertFalse($cookie->isCleared()); - } - - public function testToString() - { - $cookie = new Cookie('foo', 'bar', $expire = strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true); - $this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie'); - - $cookie = new Cookie('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true); - $this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)'); - - $cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com'); - $this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', $expire = time() - 31536001).'; Max-Age=0; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL'); - - $cookie = new Cookie('foo', 'bar', 0, '/', ''); - $this->assertEquals('foo=bar; path=/; httponly', (string) $cookie); - } - - public function testRawCookie() - { - $cookie = new Cookie('foo', 'b a r', 0, '/', null, false, false); - $this->assertFalse($cookie->isRaw()); - $this->assertEquals('foo=b%20a%20r; path=/', (string) $cookie); - - $cookie = new Cookie('foo', 'b+a+r', 0, '/', null, false, false, true); - $this->assertTrue($cookie->isRaw()); - $this->assertEquals('foo=b+a+r; path=/', (string) $cookie); - } - - public function testGetMaxAge() - { - $cookie = new Cookie('foo', 'bar'); - $this->assertEquals(0, $cookie->getMaxAge()); - - $cookie = new Cookie('foo', 'bar', $expire = time() + 100); - $this->assertEquals($expire - time(), $cookie->getMaxAge()); - - $cookie = new Cookie('foo', 'bar', $expire = time() - 100); - $this->assertEquals(0, $cookie->getMaxAge()); - } - - public function testFromString() - { - $cookie = Cookie::fromString('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure; httponly'); - $this->assertEquals(new Cookie('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true, true, true), $cookie); - - $cookie = Cookie::fromString('foo=bar', true); - $this->assertEquals(new Cookie('foo', 'bar', 0, '/', null, false, false), $cookie); - } - - public function testFromStringWithHttpOnly() - { - $cookie = Cookie::fromString('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure; httponly'); - $this->assertTrue($cookie->isHttpOnly()); - - $cookie = Cookie::fromString('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure'); - $this->assertFalse($cookie->isHttpOnly()); - } - - public function testSameSiteAttributeIsCaseInsensitive() - { - $cookie = new Cookie('foo', 'bar', 0, '/', null, false, true, false, 'Lax'); - $this->assertEquals('lax', $cookie->getSameSite()); - } -} diff --git a/vendor/symfony/http-foundation/Tests/ExpressionRequestMatcherTest.php b/vendor/symfony/http-foundation/Tests/ExpressionRequestMatcherTest.php deleted file mode 100644 index 8a389329..00000000 --- a/vendor/symfony/http-foundation/Tests/ExpressionRequestMatcherTest.php +++ /dev/null @@ -1,67 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ExpressionLanguage\ExpressionLanguage; -use Symfony\Component\HttpFoundation\ExpressionRequestMatcher; -use Symfony\Component\HttpFoundation\Request; - -class ExpressionRequestMatcherTest extends TestCase -{ - public function testWhenNoExpressionIsSet() - { - $this->expectException('LogicException'); - $expressionRequestMatcher = new ExpressionRequestMatcher(); - $expressionRequestMatcher->matches(new Request()); - } - - /** - * @dataProvider provideExpressions - */ - public function testMatchesWhenParentMatchesIsTrue($expression, $expected) - { - $request = Request::create('/foo'); - $expressionRequestMatcher = new ExpressionRequestMatcher(); - - $expressionRequestMatcher->setExpression(new ExpressionLanguage(), $expression); - $this->assertSame($expected, $expressionRequestMatcher->matches($request)); - } - - /** - * @dataProvider provideExpressions - */ - public function testMatchesWhenParentMatchesIsFalse($expression) - { - $request = Request::create('/foo'); - $request->attributes->set('foo', 'foo'); - $expressionRequestMatcher = new ExpressionRequestMatcher(); - $expressionRequestMatcher->matchAttribute('foo', 'bar'); - - $expressionRequestMatcher->setExpression(new ExpressionLanguage(), $expression); - $this->assertFalse($expressionRequestMatcher->matches($request)); - } - - public function provideExpressions() - { - return [ - ['request.getMethod() == method', true], - ['request.getPathInfo() == path', true], - ['request.getHost() == host', true], - ['request.getClientIp() == ip', true], - ['request.attributes.all() == attributes', true], - ['request.getMethod() == method && request.getPathInfo() == path && request.getHost() == host && request.getClientIp() == ip && request.attributes.all() == attributes', true], - ['request.getMethod() != method', false], - ['request.getMethod() != method && request.getPathInfo() == path && request.getHost() == host && request.getClientIp() == ip && request.attributes.all() == attributes', false], - ]; - } -} diff --git a/vendor/symfony/http-foundation/Tests/File/FakeFile.php b/vendor/symfony/http-foundation/Tests/File/FakeFile.php deleted file mode 100644 index c415989f..00000000 --- a/vendor/symfony/http-foundation/Tests/File/FakeFile.php +++ /dev/null @@ -1,45 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\File; - -use Symfony\Component\HttpFoundation\File\File as OrigFile; - -class FakeFile extends OrigFile -{ - private $realpath; - - public function __construct($realpath, $path) - { - $this->realpath = $realpath; - parent::__construct($path, false); - } - - public function isReadable() - { - return true; - } - - public function getRealpath() - { - return $this->realpath; - } - - public function getSize() - { - return 42; - } - - public function getMTime() - { - return time(); - } -} diff --git a/vendor/symfony/http-foundation/Tests/File/FileTest.php b/vendor/symfony/http-foundation/Tests/File/FileTest.php deleted file mode 100644 index 06a4ad8b..00000000 --- a/vendor/symfony/http-foundation/Tests/File/FileTest.php +++ /dev/null @@ -1,180 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\File; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\File\File; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; - -class FileTest extends TestCase -{ - protected $file; - - public function testGetMimeTypeUsesMimeTypeGuessers() - { - $file = new File(__DIR__.'/Fixtures/test.gif'); - $guesser = $this->createMockGuesser($file->getPathname(), 'image/gif'); - - MimeTypeGuesser::getInstance()->register($guesser); - - $this->assertEquals('image/gif', $file->getMimeType()); - } - - public function testGuessExtensionWithoutGuesser() - { - $file = new File(__DIR__.'/Fixtures/directory/.empty'); - - $this->assertNull($file->guessExtension()); - } - - public function testGuessExtensionIsBasedOnMimeType() - { - $file = new File(__DIR__.'/Fixtures/test'); - $guesser = $this->createMockGuesser($file->getPathname(), 'image/gif'); - - MimeTypeGuesser::getInstance()->register($guesser); - - $this->assertEquals('gif', $file->guessExtension()); - } - - /** - * @requires extension fileinfo - */ - public function testGuessExtensionWithReset() - { - $file = new File(__DIR__.'/Fixtures/other-file.example'); - $guesser = $this->createMockGuesser($file->getPathname(), 'image/gif'); - MimeTypeGuesser::getInstance()->register($guesser); - - $this->assertEquals('gif', $file->guessExtension()); - - MimeTypeGuesser::reset(); - - $this->assertNull($file->guessExtension()); - } - - public function testConstructWhenFileNotExists() - { - $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); - - new File(__DIR__.'/Fixtures/not_here'); - } - - public function testMove() - { - $path = __DIR__.'/Fixtures/test.copy.gif'; - $targetDir = __DIR__.'/Fixtures/directory'; - $targetPath = $targetDir.'/test.copy.gif'; - @unlink($path); - @unlink($targetPath); - copy(__DIR__.'/Fixtures/test.gif', $path); - - $file = new File($path); - $movedFile = $file->move($targetDir); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile); - - $this->assertFileExists($targetPath); - $this->assertFileDoesNotExist($path); - $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); - - @unlink($targetPath); - } - - public function testMoveWithNewName() - { - $path = __DIR__.'/Fixtures/test.copy.gif'; - $targetDir = __DIR__.'/Fixtures/directory'; - $targetPath = $targetDir.'/test.newname.gif'; - @unlink($path); - @unlink($targetPath); - copy(__DIR__.'/Fixtures/test.gif', $path); - - $file = new File($path); - $movedFile = $file->move($targetDir, 'test.newname.gif'); - - $this->assertFileExists($targetPath); - $this->assertFileDoesNotExist($path); - $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); - - @unlink($targetPath); - } - - public function getFilenameFixtures() - { - return [ - ['original.gif', 'original.gif'], - ['..\\..\\original.gif', 'original.gif'], - ['../../original.gif', 'original.gif'], - ['файлfile.gif', 'файлfile.gif'], - ['..\\..\\файлfile.gif', 'файлfile.gif'], - ['../../файлfile.gif', 'файлfile.gif'], - ]; - } - - /** - * @dataProvider getFilenameFixtures - */ - public function testMoveWithNonLatinName($filename, $sanitizedFilename) - { - $path = __DIR__.'/Fixtures/'.$sanitizedFilename; - $targetDir = __DIR__.'/Fixtures/directory/'; - $targetPath = $targetDir.$sanitizedFilename; - @unlink($path); - @unlink($targetPath); - copy(__DIR__.'/Fixtures/test.gif', $path); - - $file = new File($path); - $movedFile = $file->move($targetDir, $filename); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile); - - $this->assertFileExists($targetPath); - $this->assertFileDoesNotExist($path); - $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); - - @unlink($targetPath); - } - - public function testMoveToAnUnexistentDirectory() - { - $sourcePath = __DIR__.'/Fixtures/test.copy.gif'; - $targetDir = __DIR__.'/Fixtures/directory/sub'; - $targetPath = $targetDir.'/test.copy.gif'; - @unlink($sourcePath); - @unlink($targetPath); - @rmdir($targetDir); - copy(__DIR__.'/Fixtures/test.gif', $sourcePath); - - $file = new File($sourcePath); - $movedFile = $file->move($targetDir); - - $this->assertFileExists($targetPath); - $this->assertFileDoesNotExist($sourcePath); - $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); - - @unlink($sourcePath); - @unlink($targetPath); - @rmdir($targetDir); - } - - protected function createMockGuesser($path, $mimeType) - { - $guesser = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface')->getMock(); - $guesser - ->expects($this->once()) - ->method('guess') - ->with($this->equalTo($path)) - ->willReturn($mimeType) - ; - - return $guesser; - } -} diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/-test b/vendor/symfony/http-foundation/Tests/File/Fixtures/-test deleted file mode 100644 index b636f4b8..00000000 Binary files a/vendor/symfony/http-foundation/Tests/File/Fixtures/-test and /dev/null differ diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/.unknownextension b/vendor/symfony/http-foundation/Tests/File/Fixtures/.unknownextension deleted file mode 100644 index 4d1ae35b..00000000 --- a/vendor/symfony/http-foundation/Tests/File/Fixtures/.unknownextension +++ /dev/null @@ -1 +0,0 @@ -f \ No newline at end of file diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/case-sensitive-mime-type.xlsm b/vendor/symfony/http-foundation/Tests/File/Fixtures/case-sensitive-mime-type.xlsm deleted file mode 100644 index 94d85e61..00000000 Binary files a/vendor/symfony/http-foundation/Tests/File/Fixtures/case-sensitive-mime-type.xlsm and /dev/null differ diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/directory/.empty b/vendor/symfony/http-foundation/Tests/File/Fixtures/directory/.empty deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/other-file.example b/vendor/symfony/http-foundation/Tests/File/Fixtures/other-file.example deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/test b/vendor/symfony/http-foundation/Tests/File/Fixtures/test deleted file mode 100644 index b636f4b8..00000000 Binary files a/vendor/symfony/http-foundation/Tests/File/Fixtures/test and /dev/null differ diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/test.docx b/vendor/symfony/http-foundation/Tests/File/Fixtures/test.docx deleted file mode 100644 index 2e86b6fc..00000000 Binary files a/vendor/symfony/http-foundation/Tests/File/Fixtures/test.docx and /dev/null differ diff --git a/vendor/symfony/http-foundation/Tests/File/Fixtures/test.gif b/vendor/symfony/http-foundation/Tests/File/Fixtures/test.gif deleted file mode 100644 index b636f4b8..00000000 Binary files a/vendor/symfony/http-foundation/Tests/File/Fixtures/test.gif and /dev/null differ diff --git a/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php b/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php deleted file mode 100644 index aca05f2d..00000000 --- a/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\File\MimeType; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; - -/** - * @requires extension fileinfo - */ -class MimeTypeTest extends TestCase -{ - public function testGuessWithLeadingDash() - { - $cwd = getcwd(); - chdir(__DIR__.'/../Fixtures'); - try { - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess('-test')); - } finally { - chdir($cwd); - } - } - - public function testGuessImageWithoutExtension() - { - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); - } - - public function testGuessImageWithDirectory() - { - $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); - - MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/directory'); - } - - public function testGuessImageWithFileBinaryMimeTypeGuesser() - { - $guesser = MimeTypeGuesser::getInstance(); - $guesser->register(new FileBinaryMimeTypeGuesser()); - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); - } - - public function testGuessImageWithKnownExtension() - { - $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.gif')); - } - - public function testGuessFileWithUnknownExtension() - { - $this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension')); - } - - /** - * @requires PHP 7.0 - */ - public function testGuessWithDuplicatedFileType() - { - if ('application/zip' === MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')) { - $this->addToAssertionCount(1); - - return; - } - - $this->assertSame('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); - } - - public function testGuessWithIncorrectPath() - { - $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); - MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/not_here'); - } - - public function testGuessWithNonReadablePath() - { - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Can not verify chmod operations on Windows'); - } - - if (!getenv('USER') || 'root' === getenv('USER')) { - $this->markTestSkipped('This test will fail if run under superuser'); - } - - $path = __DIR__.'/../Fixtures/to_delete'; - touch($path); - @chmod($path, 0333); - - if ('0333' == substr(sprintf('%o', fileperms($path)), -4)) { - $this->expectException('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException'); - MimeTypeGuesser::getInstance()->guess($path); - } else { - $this->markTestSkipped('Can not verify chmod operations, change of file permissions failed'); - } - } - - public static function tearDownAfterClass() - { - $path = __DIR__.'/../Fixtures/to_delete'; - if (file_exists($path)) { - @chmod($path, 0666); - @unlink($path); - } - } -} diff --git a/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php b/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php deleted file mode 100644 index 9d260e7a..00000000 --- a/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php +++ /dev/null @@ -1,298 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\File; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\File\UploadedFile; - -class UploadedFileTest extends TestCase -{ - protected function setUp() - { - if (!ini_get('file_uploads')) { - $this->markTestSkipped('file_uploads is disabled in php.ini'); - } - } - - public function testConstructWhenFileNotExists() - { - $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); - - new UploadedFile( - __DIR__.'/Fixtures/not_here', - 'original.gif', - null - ); - } - - public function testFileUploadsWithNoMimeType() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - null, - filesize(__DIR__.'/Fixtures/test.gif'), - \UPLOAD_ERR_OK - ); - - $this->assertEquals('application/octet-stream', $file->getClientMimeType()); - - if (\extension_loaded('fileinfo')) { - $this->assertEquals('image/gif', $file->getMimeType()); - } - } - - public function testFileUploadsWithUnknownMimeType() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/.unknownextension', - 'original.gif', - null, - filesize(__DIR__.'/Fixtures/.unknownextension'), - \UPLOAD_ERR_OK - ); - - $this->assertEquals('application/octet-stream', $file->getClientMimeType()); - } - - public function testGuessClientExtension() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals('gif', $file->guessClientExtension()); - } - - public function testGuessClientExtensionWithIncorrectMimeType() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/png', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals('png', $file->guessClientExtension()); - } - - public function testCaseSensitiveMimeType() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/case-sensitive-mime-type.xlsm', - 'test.xlsm', - 'application/vnd.ms-excel.sheet.macroEnabled.12', - filesize(__DIR__.'/Fixtures/case-sensitive-mime-type.xlsm'), - null - ); - - $this->assertEquals('xlsm', $file->guessClientExtension()); - } - - public function testErrorIsOkByDefault() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals(\UPLOAD_ERR_OK, $file->getError()); - } - - public function testGetClientOriginalName() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals('original.gif', $file->getClientOriginalName()); - } - - public function testGetClientOriginalExtension() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals('gif', $file->getClientOriginalExtension()); - } - - public function testMoveLocalFileIsNotAllowed() - { - $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileException'); - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - \UPLOAD_ERR_OK - ); - - $file->move(__DIR__.'/Fixtures/directory'); - } - - public function testMoveLocalFileIsAllowedInTestMode() - { - $path = __DIR__.'/Fixtures/test.copy.gif'; - $targetDir = __DIR__.'/Fixtures/directory'; - $targetPath = $targetDir.'/test.copy.gif'; - @unlink($path); - @unlink($targetPath); - copy(__DIR__.'/Fixtures/test.gif', $path); - - $file = new UploadedFile( - $path, - 'original.gif', - 'image/gif', - filesize($path), - \UPLOAD_ERR_OK, - true - ); - - $movedFile = $file->move(__DIR__.'/Fixtures/directory'); - - $this->assertFileExists($targetPath); - $this->assertFileDoesNotExist($path); - $this->assertEquals(realpath($targetPath), $movedFile->getRealPath()); - - @unlink($targetPath); - } - - public function testGetClientOriginalNameSanitizeFilename() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - '../../original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals('original.gif', $file->getClientOriginalName()); - } - - public function testGetSize() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null - ); - - $this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize()); - - $file = new UploadedFile( - __DIR__.'/Fixtures/test', - 'original.gif', - 'image/gif' - ); - - $this->assertEquals(filesize(__DIR__.'/Fixtures/test'), $file->getSize()); - } - - public function testGetExtension() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - null - ); - - $this->assertEquals('gif', $file->getExtension()); - } - - public function testIsValid() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - null, - filesize(__DIR__.'/Fixtures/test.gif'), - \UPLOAD_ERR_OK, - true - ); - - $this->assertTrue($file->isValid()); - } - - /** - * @dataProvider uploadedFileErrorProvider - */ - public function testIsInvalidOnUploadError($error) - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - null, - filesize(__DIR__.'/Fixtures/test.gif'), - $error - ); - - $this->assertFalse($file->isValid()); - } - - public function uploadedFileErrorProvider() - { - return [ - [\UPLOAD_ERR_INI_SIZE], - [\UPLOAD_ERR_FORM_SIZE], - [\UPLOAD_ERR_PARTIAL], - [\UPLOAD_ERR_NO_TMP_DIR], - [\UPLOAD_ERR_EXTENSION], - ]; - } - - public function testIsInvalidIfNotHttpUpload() - { - $file = new UploadedFile( - __DIR__.'/Fixtures/test.gif', - 'original.gif', - null, - filesize(__DIR__.'/Fixtures/test.gif'), - \UPLOAD_ERR_OK - ); - - $this->assertFalse($file->isValid()); - } - - public function testGetMaxFilesize() - { - $size = UploadedFile::getMaxFilesize(); - - $this->assertIsInt($size); - $this->assertGreaterThan(0, $size); - - if (0 === (int) ini_get('post_max_size') && 0 === (int) ini_get('upload_max_filesize')) { - $this->assertSame(\PHP_INT_MAX, $size); - } else { - $this->assertLessThan(\PHP_INT_MAX, $size); - } - } -} diff --git a/vendor/symfony/http-foundation/Tests/FileBagTest.php b/vendor/symfony/http-foundation/Tests/FileBagTest.php deleted file mode 100644 index 5415dfb0..00000000 --- a/vendor/symfony/http-foundation/Tests/FileBagTest.php +++ /dev/null @@ -1,173 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Component\HttpFoundation\FileBag; - -/** - * FileBagTest. - * - * @author Fabien Potencier - * @author Bulat Shakirzyanov - */ -class FileBagTest extends TestCase -{ - public function testFileMustBeAnArrayOrUploadedFile() - { - $this->expectException('InvalidArgumentException'); - new FileBag(['file' => 'foo']); - } - - public function testShouldConvertsUploadedFiles() - { - $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); - - $bag = new FileBag(['file' => [ - 'name' => basename($tmpFile), - 'type' => 'text/plain', - 'tmp_name' => $tmpFile, - 'error' => 0, - 'size' => 100, - ]]); - - $this->assertEquals($file, $bag->get('file')); - } - - public function testShouldSetEmptyUploadedFilesToNull() - { - $bag = new FileBag(['file' => [ - 'name' => '', - 'type' => '', - 'tmp_name' => '', - 'error' => \UPLOAD_ERR_NO_FILE, - 'size' => 0, - ]]); - - $this->assertNull($bag->get('file')); - } - - public function testShouldRemoveEmptyUploadedFilesForMultiUpload() - { - $bag = new FileBag(['files' => [ - 'name' => [''], - 'type' => [''], - 'tmp_name' => [''], - 'error' => [\UPLOAD_ERR_NO_FILE], - 'size' => [0], - ]]); - - $this->assertSame([], $bag->get('files')); - } - - public function testShouldNotRemoveEmptyUploadedFilesForAssociativeArray() - { - $bag = new FileBag(['files' => [ - 'name' => ['file1' => ''], - 'type' => ['file1' => ''], - 'tmp_name' => ['file1' => ''], - 'error' => ['file1' => \UPLOAD_ERR_NO_FILE], - 'size' => ['file1' => 0], - ]]); - - $this->assertSame(['file1' => null], $bag->get('files')); - } - - public function testShouldConvertUploadedFilesWithPhpBug() - { - $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); - - $bag = new FileBag([ - 'child' => [ - 'name' => [ - 'file' => basename($tmpFile), - ], - 'type' => [ - 'file' => 'text/plain', - ], - 'tmp_name' => [ - 'file' => $tmpFile, - ], - 'error' => [ - 'file' => 0, - ], - 'size' => [ - 'file' => 100, - ], - ], - ]); - - $files = $bag->all(); - $this->assertEquals($file, $files['child']['file']); - } - - public function testShouldConvertNestedUploadedFilesWithPhpBug() - { - $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); - - $bag = new FileBag([ - 'child' => [ - 'name' => [ - 'sub' => ['file' => basename($tmpFile)], - ], - 'type' => [ - 'sub' => ['file' => 'text/plain'], - ], - 'tmp_name' => [ - 'sub' => ['file' => $tmpFile], - ], - 'error' => [ - 'sub' => ['file' => 0], - ], - 'size' => [ - 'sub' => ['file' => 100], - ], - ], - ]); - - $files = $bag->all(); - $this->assertEquals($file, $files['child']['sub']['file']); - } - - public function testShouldNotConvertNestedUploadedFiles() - { - $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); - $bag = new FileBag(['image' => ['file' => $file]]); - - $files = $bag->all(); - $this->assertEquals($file, $files['image']['file']); - } - - protected function createTempFile() - { - return tempnam(sys_get_temp_dir().'/form_test', 'FormTest'); - } - - protected function setUp() - { - mkdir(sys_get_temp_dir().'/form_test', 0777, true); - } - - protected function tearDown() - { - foreach (glob(sys_get_temp_dir().'/form_test/*') as $file) { - @unlink($file); - } - - @rmdir(sys_get_temp_dir().'/form_test'); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc deleted file mode 100644 index 0bdf9e4b..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc +++ /dev/null @@ -1,43 +0,0 @@ -headers->set('Date', 'Sat, 12 Nov 1955 20:04:00 GMT'); - -return $r; diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.expected b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.expected deleted file mode 100644 index bdb9d023..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.expected +++ /dev/null @@ -1,11 +0,0 @@ - -Warning: Expiry date cannot have a year greater than 9999 in %scookie_max_age.php on line 10 - -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: no-cache, private - [2] => Date: Sat, 12 Nov 1955 20:04:00 GMT - [3] => Set-Cookie: foo=bar; expires=Sat, 01-Jan-10000 02:46:40 GMT; Max-Age=%d; path=/ -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php deleted file mode 100644 index 8775a5cc..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php +++ /dev/null @@ -1,10 +0,0 @@ -headers->setCookie(new Cookie('foo', 'bar', 253402310800, '', null, false, false)); -$r->sendHeaders(); - -setcookie('foo2', 'bar', 253402310800, '/'); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.expected b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.expected deleted file mode 100644 index 0c097972..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.expected +++ /dev/null @@ -1,10 +0,0 @@ - -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: no-cache, private - [2] => Date: Sat, 12 Nov 1955 20:04:00 GMT - [3] => Set-Cookie: ?*():@&+$/%#[]=?*():@&+$/%#[]; path=/ - [4] => Set-Cookie: ?*():@&+$/%#[]=?*():@&+$/%#[]; path=/ -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php deleted file mode 100644 index 2ca5b59f..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php +++ /dev/null @@ -1,12 +0,0 @@ -headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true)); -$r->sendHeaders(); - -setrawcookie($str, $str, 0, '/', null, false, false); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_lax.expected b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_lax.expected deleted file mode 100644 index cbde2cbf..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_lax.expected +++ /dev/null @@ -1,9 +0,0 @@ - -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: no-cache, private - [2] => Date: Sat, 12 Nov 1955 20:04:00 GMT - [3] => Set-Cookie: CookieSamesiteLaxTest=LaxValue; path=/; httponly; samesite=lax -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_lax.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_lax.php deleted file mode 100644 index 9a476f1d..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_lax.php +++ /dev/null @@ -1,8 +0,0 @@ -headers->setCookie(new Cookie('CookieSamesiteLaxTest', 'LaxValue', 0, '/', null, false, true, false, Cookie::SAMESITE_LAX)); -$r->sendHeaders(); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_strict.expected b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_strict.expected deleted file mode 100644 index adc491fd..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_strict.expected +++ /dev/null @@ -1,9 +0,0 @@ - -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: no-cache, private - [2] => Date: Sat, 12 Nov 1955 20:04:00 GMT - [3] => Set-Cookie: CookieSamesiteStrictTest=StrictValue; path=/; httponly; samesite=strict -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_strict.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_strict.php deleted file mode 100644 index 3bcb41f8..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_samesite_strict.php +++ /dev/null @@ -1,8 +0,0 @@ -headers->setCookie(new Cookie('CookieSamesiteStrictTest', 'StrictValue', 0, '/', null, false, true, false, Cookie::SAMESITE_STRICT)); -$r->sendHeaders(); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.expected b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.expected deleted file mode 100644 index 17a9efc6..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.expected +++ /dev/null @@ -1,11 +0,0 @@ - -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: no-cache, private - [2] => Date: Sat, 12 Nov 1955 20:04:00 GMT - [3] => Set-Cookie: %3D%2C%3B%20%09%0D%0A%0B%0C=%3D%2C%3B%20%09%0D%0A%0B%0C; path=/ - [4] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/ - [5] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/ -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php deleted file mode 100644 index 9ffb0dfe..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php +++ /dev/null @@ -1,15 +0,0 @@ -headers->setCookie(new Cookie($str1, $str1, 0, '', null, false, false, false, null)); - -$str2 = '?*():@&+$/%#[]'; - -$r->headers->setCookie(new Cookie($str2, $str2, 0, '', null, false, false, false, null)); -$r->sendHeaders(); - -setcookie($str2, $str2, 0, '/'); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.expected b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.expected deleted file mode 100644 index 2b560f0b..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.expected +++ /dev/null @@ -1,6 +0,0 @@ -The cookie name "Hello + world" contains invalid characters. -Array -( - [0] => Content-Type: text/plain; charset=utf-8 -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php deleted file mode 100644 index 3acf8603..00000000 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php +++ /dev/null @@ -1,11 +0,0 @@ -headers->setCookie(new Cookie('Hello + world', 'hodor', 0, null, null, null, false, true)); -} catch (\InvalidArgumentException $e) { - echo $e->getMessage(); -} diff --git a/vendor/symfony/http-foundation/Tests/HeaderBagTest.php b/vendor/symfony/http-foundation/Tests/HeaderBagTest.php deleted file mode 100644 index cabe038b..00000000 --- a/vendor/symfony/http-foundation/Tests/HeaderBagTest.php +++ /dev/null @@ -1,213 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\HeaderBag; - -class HeaderBagTest extends TestCase -{ - public function testConstructor() - { - $bag = new HeaderBag(['foo' => 'bar']); - $this->assertTrue($bag->has('foo')); - } - - public function testToStringNull() - { - $bag = new HeaderBag(); - $this->assertEquals('', $bag->__toString()); - } - - public function testToStringNotNull() - { - $bag = new HeaderBag(['foo' => 'bar']); - $this->assertEquals("Foo: bar\r\n", $bag->__toString()); - } - - public function testKeys() - { - $bag = new HeaderBag(['foo' => 'bar']); - $keys = $bag->keys(); - $this->assertEquals('foo', $keys[0]); - } - - public function testGetDate() - { - $bag = new HeaderBag(['foo' => 'Tue, 4 Sep 2012 20:00:00 +0200']); - $headerDate = $bag->getDate('foo'); - $this->assertInstanceOf('DateTime', $headerDate); - } - - public function testGetDateNull() - { - $bag = new HeaderBag(['foo' => null]); - $headerDate = $bag->getDate('foo'); - $this->assertNull($headerDate); - } - - public function testGetDateException() - { - $this->expectException('RuntimeException'); - $bag = new HeaderBag(['foo' => 'Tue']); - $bag->getDate('foo'); - } - - public function testGetCacheControlHeader() - { - $bag = new HeaderBag(); - $bag->addCacheControlDirective('public', '#a'); - $this->assertTrue($bag->hasCacheControlDirective('public')); - $this->assertEquals('#a', $bag->getCacheControlDirective('public')); - } - - public function testAll() - { - $bag = new HeaderBag(['foo' => 'bar']); - $this->assertEquals(['foo' => ['bar']], $bag->all(), '->all() gets all the input'); - - $bag = new HeaderBag(['FOO' => 'BAR']); - $this->assertEquals(['foo' => ['BAR']], $bag->all(), '->all() gets all the input key are lower case'); - } - - public function testReplace() - { - $bag = new HeaderBag(['foo' => 'bar']); - - $bag->replace(['NOPE' => 'BAR']); - $this->assertEquals(['nope' => ['BAR']], $bag->all(), '->replace() replaces the input with the argument'); - $this->assertFalse($bag->has('foo'), '->replace() overrides previously set the input'); - } - - public function testGet() - { - $bag = new HeaderBag(['foo' => 'bar', 'fuzz' => 'bizz']); - $this->assertEquals('bar', $bag->get('foo'), '->get return current value'); - $this->assertEquals('bar', $bag->get('FoO'), '->get key in case insensitive'); - $this->assertEquals(['bar'], $bag->get('foo', 'nope', false), '->get return the value as array'); - - // defaults - $this->assertNull($bag->get('none'), '->get unknown values returns null'); - $this->assertEquals('default', $bag->get('none', 'default'), '->get unknown values returns default'); - $this->assertEquals(['default'], $bag->get('none', 'default', false), '->get unknown values returns default as array'); - - $bag->set('foo', 'bor', false); - $this->assertEquals('bar', $bag->get('foo'), '->get return first value'); - $this->assertEquals(['bar', 'bor'], $bag->get('foo', 'nope', false), '->get return all values as array'); - - $bag->set('baz', null); - $this->assertNull($bag->get('baz', 'nope'), '->get return null although different default value is given'); - } - - public function testSetAssociativeArray() - { - $bag = new HeaderBag(); - $bag->set('foo', ['bad-assoc-index' => 'value']); - $this->assertSame('value', $bag->get('foo')); - $this->assertEquals(['value'], $bag->get('foo', 'nope', false), 'assoc indices of multi-valued headers are ignored'); - } - - public function testContains() - { - $bag = new HeaderBag(['foo' => 'bar', 'fuzz' => 'bizz']); - $this->assertTrue($bag->contains('foo', 'bar'), '->contains first value'); - $this->assertTrue($bag->contains('fuzz', 'bizz'), '->contains second value'); - $this->assertFalse($bag->contains('nope', 'nope'), '->contains unknown value'); - $this->assertFalse($bag->contains('foo', 'nope'), '->contains unknown value'); - - // Multiple values - $bag->set('foo', 'bor', false); - $this->assertTrue($bag->contains('foo', 'bar'), '->contains first value'); - $this->assertTrue($bag->contains('foo', 'bor'), '->contains second value'); - $this->assertFalse($bag->contains('foo', 'nope'), '->contains unknown value'); - } - - public function testCacheControlDirectiveAccessors() - { - $bag = new HeaderBag(); - $bag->addCacheControlDirective('public'); - - $this->assertTrue($bag->hasCacheControlDirective('public')); - $this->assertTrue($bag->getCacheControlDirective('public')); - $this->assertEquals('public', $bag->get('cache-control')); - - $bag->addCacheControlDirective('max-age', 10); - $this->assertTrue($bag->hasCacheControlDirective('max-age')); - $this->assertEquals(10, $bag->getCacheControlDirective('max-age')); - $this->assertEquals('max-age=10, public', $bag->get('cache-control')); - - $bag->removeCacheControlDirective('max-age'); - $this->assertFalse($bag->hasCacheControlDirective('max-age')); - } - - public function testCacheControlDirectiveParsing() - { - $bag = new HeaderBag(['cache-control' => 'public, max-age=10']); - $this->assertTrue($bag->hasCacheControlDirective('public')); - $this->assertTrue($bag->getCacheControlDirective('public')); - - $this->assertTrue($bag->hasCacheControlDirective('max-age')); - $this->assertEquals(10, $bag->getCacheControlDirective('max-age')); - - $bag->addCacheControlDirective('s-maxage', 100); - $this->assertEquals('max-age=10, public, s-maxage=100', $bag->get('cache-control')); - } - - public function testCacheControlDirectiveParsingQuotedZero() - { - $bag = new HeaderBag(['cache-control' => 'max-age="0"']); - $this->assertTrue($bag->hasCacheControlDirective('max-age')); - $this->assertEquals(0, $bag->getCacheControlDirective('max-age')); - } - - public function testCacheControlDirectiveOverrideWithReplace() - { - $bag = new HeaderBag(['cache-control' => 'private, max-age=100']); - $bag->replace(['cache-control' => 'public, max-age=10']); - $this->assertTrue($bag->hasCacheControlDirective('public')); - $this->assertTrue($bag->getCacheControlDirective('public')); - - $this->assertTrue($bag->hasCacheControlDirective('max-age')); - $this->assertEquals(10, $bag->getCacheControlDirective('max-age')); - } - - public function testCacheControlClone() - { - $headers = ['foo' => 'bar']; - $bag1 = new HeaderBag($headers); - $bag2 = new HeaderBag($bag1->all()); - - $this->assertEquals($bag1->all(), $bag2->all()); - } - - public function testGetIterator() - { - $headers = ['foo' => 'bar', 'hello' => 'world', 'third' => 'charm']; - $headerBag = new HeaderBag($headers); - - $i = 0; - foreach ($headerBag as $key => $val) { - ++$i; - $this->assertEquals([$headers[$key]], $val); - } - - $this->assertEquals(\count($headers), $i); - } - - public function testCount() - { - $headers = ['foo' => 'bar', 'HELLO' => 'WORLD']; - $headerBag = new HeaderBag($headers); - - $this->assertCount(\count($headers), $headerBag); - } -} diff --git a/vendor/symfony/http-foundation/Tests/IpUtilsTest.php b/vendor/symfony/http-foundation/Tests/IpUtilsTest.php deleted file mode 100644 index d3b262e0..00000000 --- a/vendor/symfony/http-foundation/Tests/IpUtilsTest.php +++ /dev/null @@ -1,104 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\IpUtils; - -class IpUtilsTest extends TestCase -{ - /** - * @dataProvider getIpv4Data - */ - public function testIpv4($matches, $remoteAddr, $cidr) - { - $this->assertSame($matches, IpUtils::checkIp($remoteAddr, $cidr)); - } - - public function getIpv4Data() - { - return [ - [true, '192.168.1.1', '192.168.1.1'], - [true, '192.168.1.1', '192.168.1.1/1'], - [true, '192.168.1.1', '192.168.1.0/24'], - [false, '192.168.1.1', '1.2.3.4/1'], - [false, '192.168.1.1', '192.168.1.1/33'], // invalid subnet - [true, '192.168.1.1', ['1.2.3.4/1', '192.168.1.0/24']], - [true, '192.168.1.1', ['192.168.1.0/24', '1.2.3.4/1']], - [false, '192.168.1.1', ['1.2.3.4/1', '4.3.2.1/1']], - [true, '1.2.3.4', '0.0.0.0/0'], - [true, '1.2.3.4', '192.168.1.0/0'], - [false, '1.2.3.4', '256.256.256/0'], // invalid CIDR notation - [false, 'an_invalid_ip', '192.168.1.0/24'], - ]; - } - - /** - * @dataProvider getIpv6Data - */ - public function testIpv6($matches, $remoteAddr, $cidr) - { - if (!\defined('AF_INET6')) { - $this->markTestSkipped('Only works when PHP is compiled without the option "disable-ipv6".'); - } - - $this->assertSame($matches, IpUtils::checkIp($remoteAddr, $cidr)); - } - - public function getIpv6Data() - { - return [ - [true, '2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'], - [false, '2a00:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'], - [false, '2a01:198:603:0:396e:4789:8e99:890f', '::1'], - [true, '0:0:0:0:0:0:0:1', '::1'], - [false, '0:0:603:0:396e:4789:8e99:0001', '::1'], - [true, '0:0:603:0:396e:4789:8e99:0001', '::/0'], - [true, '0:0:603:0:396e:4789:8e99:0001', '2a01:198:603:0::/0'], - [true, '2a01:198:603:0:396e:4789:8e99:890f', ['::1', '2a01:198:603:0::/65']], - [true, '2a01:198:603:0:396e:4789:8e99:890f', ['2a01:198:603:0::/65', '::1']], - [false, '2a01:198:603:0:396e:4789:8e99:890f', ['::1', '1a01:198:603:0::/65']], - [false, '}__test|O:21:"JDatabaseDriverMysqli":3:{s:2', '::1'], - [false, '2a01:198:603:0:396e:4789:8e99:890f', 'unknown'], - ]; - } - - /** - * @requires extension sockets - */ - public function testAnIpv6WithOptionDisabledIpv6() - { - $this->expectException('RuntimeException'); - if (\defined('AF_INET6')) { - $this->markTestSkipped('Only works when PHP is compiled with the option "disable-ipv6".'); - } - - IpUtils::checkIp('2a01:198:603:0:396e:4789:8e99:890f', '2a01:198:603:0::/65'); - } - - /** - * @dataProvider invalidIpAddressData - */ - public function testInvalidIpAddressesDoNotMatch($requestIp, $proxyIp) - { - $this->assertFalse(IpUtils::checkIp4($requestIp, $proxyIp)); - } - - public function invalidIpAddressData() - { - return [ - 'invalid proxy wildcard' => ['192.168.20.13', '*'], - 'invalid proxy missing netmask' => ['192.168.20.13', '0.0.0.0'], - 'invalid request IP with invalid proxy wildcard' => ['0.0.0.0', '*'], - ]; - } -} diff --git a/vendor/symfony/http-foundation/Tests/JsonResponseTest.php b/vendor/symfony/http-foundation/Tests/JsonResponseTest.php deleted file mode 100644 index 2ad7ae10..00000000 --- a/vendor/symfony/http-foundation/Tests/JsonResponseTest.php +++ /dev/null @@ -1,262 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\JsonResponse; - -class JsonResponseTest extends TestCase -{ - protected function setUp() - { - parent::setUp(); - - if (!\defined('HHVM_VERSION')) { - $this->iniSet('serialize_precision', 14); - } - } - - public function testConstructorEmptyCreatesJsonObject() - { - $response = new JsonResponse(); - $this->assertSame('{}', $response->getContent()); - } - - public function testConstructorWithArrayCreatesJsonArray() - { - $response = new JsonResponse([0, 1, 2, 3]); - $this->assertSame('[0,1,2,3]', $response->getContent()); - } - - public function testConstructorWithAssocArrayCreatesJsonObject() - { - $response = new JsonResponse(['foo' => 'bar']); - $this->assertSame('{"foo":"bar"}', $response->getContent()); - } - - public function testConstructorWithSimpleTypes() - { - $response = new JsonResponse('foo'); - $this->assertSame('"foo"', $response->getContent()); - - $response = new JsonResponse(0); - $this->assertSame('0', $response->getContent()); - - $response = new JsonResponse(0.1); - $this->assertEquals(0.1, $response->getContent()); - $this->assertIsString($response->getContent()); - - $response = new JsonResponse(true); - $this->assertSame('true', $response->getContent()); - } - - public function testConstructorWithCustomStatus() - { - $response = new JsonResponse([], 202); - $this->assertSame(202, $response->getStatusCode()); - } - - public function testConstructorAddsContentTypeHeader() - { - $response = new JsonResponse(); - $this->assertSame('application/json', $response->headers->get('Content-Type')); - } - - public function testConstructorWithCustomHeaders() - { - $response = new JsonResponse([], 200, ['ETag' => 'foo']); - $this->assertSame('application/json', $response->headers->get('Content-Type')); - $this->assertSame('foo', $response->headers->get('ETag')); - } - - public function testConstructorWithCustomContentType() - { - $headers = ['Content-Type' => 'application/vnd.acme.blog-v1+json']; - - $response = new JsonResponse([], 200, $headers); - $this->assertSame('application/vnd.acme.blog-v1+json', $response->headers->get('Content-Type')); - } - - public function testSetJson() - { - $response = new JsonResponse('1', 200, [], true); - $this->assertEquals('1', $response->getContent()); - - $response = new JsonResponse('[1]', 200, [], true); - $this->assertEquals('[1]', $response->getContent()); - - $response = new JsonResponse(null, 200, []); - $response->setJson('true'); - $this->assertEquals('true', $response->getContent()); - } - - public function testCreate() - { - $response = JsonResponse::create(['foo' => 'bar'], 204); - - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertEquals('{"foo":"bar"}', $response->getContent()); - $this->assertEquals(204, $response->getStatusCode()); - } - - public function testStaticCreateEmptyJsonObject() - { - $response = JsonResponse::create(); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('{}', $response->getContent()); - } - - public function testStaticCreateJsonArray() - { - $response = JsonResponse::create([0, 1, 2, 3]); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('[0,1,2,3]', $response->getContent()); - } - - public function testStaticCreateJsonObject() - { - $response = JsonResponse::create(['foo' => 'bar']); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('{"foo":"bar"}', $response->getContent()); - } - - public function testStaticCreateWithSimpleTypes() - { - $response = JsonResponse::create('foo'); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('"foo"', $response->getContent()); - - $response = JsonResponse::create(0); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('0', $response->getContent()); - - $response = JsonResponse::create(0.1); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertEquals(0.1, $response->getContent()); - $this->assertIsString($response->getContent()); - - $response = JsonResponse::create(true); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('true', $response->getContent()); - } - - public function testStaticCreateWithCustomStatus() - { - $response = JsonResponse::create([], 202); - $this->assertSame(202, $response->getStatusCode()); - } - - public function testStaticCreateAddsContentTypeHeader() - { - $response = JsonResponse::create(); - $this->assertSame('application/json', $response->headers->get('Content-Type')); - } - - public function testStaticCreateWithCustomHeaders() - { - $response = JsonResponse::create([], 200, ['ETag' => 'foo']); - $this->assertSame('application/json', $response->headers->get('Content-Type')); - $this->assertSame('foo', $response->headers->get('ETag')); - } - - public function testStaticCreateWithCustomContentType() - { - $headers = ['Content-Type' => 'application/vnd.acme.blog-v1+json']; - - $response = JsonResponse::create([], 200, $headers); - $this->assertSame('application/vnd.acme.blog-v1+json', $response->headers->get('Content-Type')); - } - - public function testSetCallback() - { - $response = JsonResponse::create(['foo' => 'bar'])->setCallback('callback'); - - $this->assertEquals('/**/callback({"foo":"bar"});', $response->getContent()); - $this->assertEquals('text/javascript', $response->headers->get('Content-Type')); - } - - public function testJsonEncodeFlags() - { - $response = new JsonResponse('<>\'&"'); - - $this->assertEquals('"\u003C\u003E\u0027\u0026\u0022"', $response->getContent()); - } - - public function testGetEncodingOptions() - { - $response = new JsonResponse(); - - $this->assertEquals(\JSON_HEX_TAG | \JSON_HEX_APOS | \JSON_HEX_AMP | \JSON_HEX_QUOT, $response->getEncodingOptions()); - } - - public function testSetEncodingOptions() - { - $response = new JsonResponse(); - $response->setData([[1, 2, 3]]); - - $this->assertEquals('[[1,2,3]]', $response->getContent()); - - $response->setEncodingOptions(\JSON_FORCE_OBJECT); - - $this->assertEquals('{"0":{"0":1,"1":2,"2":3}}', $response->getContent()); - } - - public function testItAcceptsJsonAsString() - { - $response = JsonResponse::fromJsonString('{"foo":"bar"}'); - $this->assertSame('{"foo":"bar"}', $response->getContent()); - } - - public function testSetCallbackInvalidIdentifier() - { - $this->expectException('InvalidArgumentException'); - $response = new JsonResponse('foo'); - $response->setCallback('+invalid'); - } - - public function testSetContent() - { - $this->expectException('InvalidArgumentException'); - JsonResponse::create("\xB1\x31"); - } - - public function testSetContentJsonSerializeError() - { - $this->expectException('Exception'); - $this->expectExceptionMessage('This error is expected'); - if (!interface_exists('JsonSerializable', false)) { - $this->markTestSkipped('JsonSerializable is required.'); - } - - $serializable = new JsonSerializableObject(); - - JsonResponse::create($serializable); - } - - public function testSetComplexCallback() - { - $response = JsonResponse::create(['foo' => 'bar']); - $response->setCallback('ಠ_ಠ["foo"].bar[0]'); - - $this->assertEquals('/**/ಠ_ಠ["foo"].bar[0]({"foo":"bar"});', $response->getContent()); - } -} - -if (interface_exists('JsonSerializable', false)) { - class JsonSerializableObject implements \JsonSerializable - { - public function jsonSerialize() - { - throw new \Exception('This error is expected'); - } - } -} diff --git a/vendor/symfony/http-foundation/Tests/ParameterBagTest.php b/vendor/symfony/http-foundation/Tests/ParameterBagTest.php deleted file mode 100644 index 685e74a6..00000000 --- a/vendor/symfony/http-foundation/Tests/ParameterBagTest.php +++ /dev/null @@ -1,194 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\ParameterBag; - -class ParameterBagTest extends TestCase -{ - public function testConstructor() - { - $this->testAll(); - } - - public function testAll() - { - $bag = new ParameterBag(['foo' => 'bar']); - $this->assertEquals(['foo' => 'bar'], $bag->all(), '->all() gets all the input'); - } - - public function testKeys() - { - $bag = new ParameterBag(['foo' => 'bar']); - $this->assertEquals(['foo'], $bag->keys()); - } - - public function testAdd() - { - $bag = new ParameterBag(['foo' => 'bar']); - $bag->add(['bar' => 'bas']); - $this->assertEquals(['foo' => 'bar', 'bar' => 'bas'], $bag->all()); - } - - public function testRemove() - { - $bag = new ParameterBag(['foo' => 'bar']); - $bag->add(['bar' => 'bas']); - $this->assertEquals(['foo' => 'bar', 'bar' => 'bas'], $bag->all()); - $bag->remove('bar'); - $this->assertEquals(['foo' => 'bar'], $bag->all()); - } - - public function testReplace() - { - $bag = new ParameterBag(['foo' => 'bar']); - - $bag->replace(['FOO' => 'BAR']); - $this->assertEquals(['FOO' => 'BAR'], $bag->all(), '->replace() replaces the input with the argument'); - $this->assertFalse($bag->has('foo'), '->replace() overrides previously set the input'); - } - - public function testGet() - { - $bag = new ParameterBag(['foo' => 'bar', 'null' => null]); - - $this->assertEquals('bar', $bag->get('foo'), '->get() gets the value of a parameter'); - $this->assertEquals('default', $bag->get('unknown', 'default'), '->get() returns second argument as default if a parameter is not defined'); - $this->assertNull($bag->get('null', 'default'), '->get() returns null if null is set'); - } - - public function testGetDoesNotUseDeepByDefault() - { - $bag = new ParameterBag(['foo' => ['bar' => 'moo']]); - - $this->assertNull($bag->get('foo[bar]')); - } - - public function testSet() - { - $bag = new ParameterBag([]); - - $bag->set('foo', 'bar'); - $this->assertEquals('bar', $bag->get('foo'), '->set() sets the value of parameter'); - - $bag->set('foo', 'baz'); - $this->assertEquals('baz', $bag->get('foo'), '->set() overrides previously set parameter'); - } - - public function testHas() - { - $bag = new ParameterBag(['foo' => 'bar']); - - $this->assertTrue($bag->has('foo'), '->has() returns true if a parameter is defined'); - $this->assertFalse($bag->has('unknown'), '->has() return false if a parameter is not defined'); - } - - public function testGetAlpha() - { - $bag = new ParameterBag(['word' => 'foo_BAR_012']); - - $this->assertEquals('fooBAR', $bag->getAlpha('word'), '->getAlpha() gets only alphabetic characters'); - $this->assertEquals('', $bag->getAlpha('unknown'), '->getAlpha() returns empty string if a parameter is not defined'); - } - - public function testGetAlnum() - { - $bag = new ParameterBag(['word' => 'foo_BAR_012']); - - $this->assertEquals('fooBAR012', $bag->getAlnum('word'), '->getAlnum() gets only alphanumeric characters'); - $this->assertEquals('', $bag->getAlnum('unknown'), '->getAlnum() returns empty string if a parameter is not defined'); - } - - public function testGetDigits() - { - $bag = new ParameterBag(['word' => 'foo_BAR_012']); - - $this->assertEquals('012', $bag->getDigits('word'), '->getDigits() gets only digits as string'); - $this->assertEquals('', $bag->getDigits('unknown'), '->getDigits() returns empty string if a parameter is not defined'); - } - - public function testGetInt() - { - $bag = new ParameterBag(['digits' => '0123']); - - $this->assertEquals(123, $bag->getInt('digits'), '->getInt() gets a value of parameter as integer'); - $this->assertEquals(0, $bag->getInt('unknown'), '->getInt() returns zero if a parameter is not defined'); - } - - public function testFilter() - { - $bag = new ParameterBag([ - 'digits' => '0123ab', - 'email' => 'example@example.com', - 'url' => 'http://example.com/foo', - 'dec' => '256', - 'hex' => '0x100', - 'array' => ['bang'], - ]); - - $this->assertEmpty($bag->filter('nokey'), '->filter() should return empty by default if no key is found'); - - $this->assertEquals('0123', $bag->filter('digits', '', \FILTER_SANITIZE_NUMBER_INT), '->filter() gets a value of parameter as integer filtering out invalid characters'); - - $this->assertEquals('example@example.com', $bag->filter('email', '', \FILTER_VALIDATE_EMAIL), '->filter() gets a value of parameter as email'); - - $this->assertEquals('http://example.com/foo', $bag->filter('url', '', \FILTER_VALIDATE_URL, ['flags' => \FILTER_FLAG_PATH_REQUIRED]), '->filter() gets a value of parameter as URL with a path'); - - // This test is repeated for code-coverage - $this->assertEquals('http://example.com/foo', $bag->filter('url', '', \FILTER_VALIDATE_URL, \FILTER_FLAG_PATH_REQUIRED), '->filter() gets a value of parameter as URL with a path'); - - $this->assertFalse($bag->filter('dec', '', \FILTER_VALIDATE_INT, [ - 'flags' => \FILTER_FLAG_ALLOW_HEX, - 'options' => ['min_range' => 1, 'max_range' => 0xff], - ]), '->filter() gets a value of parameter as integer between boundaries'); - - $this->assertFalse($bag->filter('hex', '', \FILTER_VALIDATE_INT, [ - 'flags' => \FILTER_FLAG_ALLOW_HEX, - 'options' => ['min_range' => 1, 'max_range' => 0xff], - ]), '->filter() gets a value of parameter as integer between boundaries'); - - $this->assertEquals(['bang'], $bag->filter('array', ''), '->filter() gets a value of parameter as an array'); - } - - public function testGetIterator() - { - $parameters = ['foo' => 'bar', 'hello' => 'world']; - $bag = new ParameterBag($parameters); - - $i = 0; - foreach ($bag as $key => $val) { - ++$i; - $this->assertEquals($parameters[$key], $val); - } - - $this->assertEquals(\count($parameters), $i); - } - - public function testCount() - { - $parameters = ['foo' => 'bar', 'hello' => 'world']; - $bag = new ParameterBag($parameters); - - $this->assertCount(\count($parameters), $bag); - } - - public function testGetBoolean() - { - $parameters = ['string_true' => 'true', 'string_false' => 'false']; - $bag = new ParameterBag($parameters); - - $this->assertTrue($bag->getBoolean('string_true'), '->getBoolean() gets the string true as boolean true'); - $this->assertFalse($bag->getBoolean('string_false'), '->getBoolean() gets the string false as boolean false'); - $this->assertFalse($bag->getBoolean('unknown'), '->getBoolean() returns false if a parameter is not defined'); - } -} diff --git a/vendor/symfony/http-foundation/Tests/RedirectResponseTest.php b/vendor/symfony/http-foundation/Tests/RedirectResponseTest.php deleted file mode 100644 index 47e5f8c6..00000000 --- a/vendor/symfony/http-foundation/Tests/RedirectResponseTest.php +++ /dev/null @@ -1,92 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\RedirectResponse; - -class RedirectResponseTest extends TestCase -{ - public function testGenerateMetaRedirect() - { - $response = new RedirectResponse('foo.bar'); - - $this->assertMatchesRegularExpression('##', preg_replace('/\s+/', ' ', $response->getContent())); - } - - public function testRedirectResponseConstructorNullUrl() - { - $this->expectException('InvalidArgumentException'); - new RedirectResponse(null); - } - - public function testRedirectResponseConstructorWrongStatusCode() - { - $this->expectException('InvalidArgumentException'); - new RedirectResponse('foo.bar', 404); - } - - public function testGenerateLocationHeader() - { - $response = new RedirectResponse('foo.bar'); - - $this->assertTrue($response->headers->has('Location')); - $this->assertEquals('foo.bar', $response->headers->get('Location')); - } - - public function testGetTargetUrl() - { - $response = new RedirectResponse('foo.bar'); - - $this->assertEquals('foo.bar', $response->getTargetUrl()); - } - - public function testSetTargetUrl() - { - $response = new RedirectResponse('foo.bar'); - $response->setTargetUrl('baz.beep'); - - $this->assertEquals('baz.beep', $response->getTargetUrl()); - } - - public function testSetTargetUrlNull() - { - $this->expectException('InvalidArgumentException'); - $response = new RedirectResponse('foo.bar'); - $response->setTargetUrl(null); - } - - public function testCreate() - { - $response = RedirectResponse::create('foo', 301); - - $this->assertInstanceOf('Symfony\Component\HttpFoundation\RedirectResponse', $response); - $this->assertEquals(301, $response->getStatusCode()); - } - - public function testCacheHeaders() - { - $response = new RedirectResponse('foo.bar', 301); - $this->assertFalse($response->headers->hasCacheControlDirective('no-cache')); - - $response = new RedirectResponse('foo.bar', 301, ['cache-control' => 'max-age=86400']); - $this->assertFalse($response->headers->hasCacheControlDirective('no-cache')); - $this->assertTrue($response->headers->hasCacheControlDirective('max-age')); - - $response = new RedirectResponse('foo.bar', 301, ['Cache-Control' => 'max-age=86400']); - $this->assertFalse($response->headers->hasCacheControlDirective('no-cache')); - $this->assertTrue($response->headers->hasCacheControlDirective('max-age')); - - $response = new RedirectResponse('foo.bar', 302); - $this->assertTrue($response->headers->hasCacheControlDirective('no-cache')); - } -} diff --git a/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php b/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php deleted file mode 100644 index 7fb6925b..00000000 --- a/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php +++ /dev/null @@ -1,151 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestMatcher; - -class RequestMatcherTest extends TestCase -{ - /** - * @dataProvider getMethodData - */ - public function testMethod($requestMethod, $matcherMethod, $isMatch) - { - $matcher = new RequestMatcher(); - $matcher->matchMethod($matcherMethod); - $request = Request::create('', $requestMethod); - $this->assertSame($isMatch, $matcher->matches($request)); - - $matcher = new RequestMatcher(null, null, $matcherMethod); - $request = Request::create('', $requestMethod); - $this->assertSame($isMatch, $matcher->matches($request)); - } - - public function getMethodData() - { - return [ - ['get', 'get', true], - ['get', ['get', 'post'], true], - ['get', 'post', false], - ['get', 'GET', true], - ['get', ['GET', 'POST'], true], - ['get', 'POST', false], - ]; - } - - public function testScheme() - { - $httpRequest = $request = $request = Request::create(''); - $httpsRequest = $request = $request = Request::create('', 'get', [], [], [], ['HTTPS' => 'on']); - - $matcher = new RequestMatcher(); - $matcher->matchScheme('https'); - $this->assertFalse($matcher->matches($httpRequest)); - $this->assertTrue($matcher->matches($httpsRequest)); - - $matcher->matchScheme('http'); - $this->assertFalse($matcher->matches($httpsRequest)); - $this->assertTrue($matcher->matches($httpRequest)); - - $matcher = new RequestMatcher(); - $this->assertTrue($matcher->matches($httpsRequest)); - $this->assertTrue($matcher->matches($httpRequest)); - } - - /** - * @dataProvider getHostData - */ - public function testHost($pattern, $isMatch) - { - $matcher = new RequestMatcher(); - $request = Request::create('', 'get', [], [], [], ['HTTP_HOST' => 'foo.example.com']); - - $matcher->matchHost($pattern); - $this->assertSame($isMatch, $matcher->matches($request)); - - $matcher = new RequestMatcher(null, $pattern); - $this->assertSame($isMatch, $matcher->matches($request)); - } - - public function getHostData() - { - return [ - ['.*\.example\.com', true], - ['\.example\.com$', true], - ['^.*\.example\.com$', true], - ['.*\.sensio\.com', false], - ['.*\.example\.COM', true], - ['\.example\.COM$', true], - ['^.*\.example\.COM$', true], - ['.*\.sensio\.COM', false], - ]; - } - - public function testPath() - { - $matcher = new RequestMatcher(); - - $request = Request::create('/admin/foo'); - - $matcher->matchPath('/admin/.*'); - $this->assertTrue($matcher->matches($request)); - - $matcher->matchPath('/admin'); - $this->assertTrue($matcher->matches($request)); - - $matcher->matchPath('^/admin/.*$'); - $this->assertTrue($matcher->matches($request)); - - $matcher->matchMethod('/blog/.*'); - $this->assertFalse($matcher->matches($request)); - } - - public function testPathWithLocaleIsNotSupported() - { - $matcher = new RequestMatcher(); - $request = Request::create('/en/login'); - $request->setLocale('en'); - - $matcher->matchPath('^/{_locale}/login$'); - $this->assertFalse($matcher->matches($request)); - } - - public function testPathWithEncodedCharacters() - { - $matcher = new RequestMatcher(); - $request = Request::create('/admin/fo%20o'); - $matcher->matchPath('^/admin/fo o*$'); - $this->assertTrue($matcher->matches($request)); - } - - public function testAttributes() - { - $matcher = new RequestMatcher(); - - $request = Request::create('/admin/foo'); - $request->attributes->set('foo', 'foo_bar'); - - $matcher->matchAttribute('foo', 'foo_.*'); - $this->assertTrue($matcher->matches($request)); - - $matcher->matchAttribute('foo', 'foo'); - $this->assertTrue($matcher->matches($request)); - - $matcher->matchAttribute('foo', '^foo_bar$'); - $this->assertTrue($matcher->matches($request)); - - $matcher->matchAttribute('foo', 'babar'); - $this->assertFalse($matcher->matches($request)); - } -} diff --git a/vendor/symfony/http-foundation/Tests/RequestStackTest.php b/vendor/symfony/http-foundation/Tests/RequestStackTest.php deleted file mode 100644 index a84fb26f..00000000 --- a/vendor/symfony/http-foundation/Tests/RequestStackTest.php +++ /dev/null @@ -1,70 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; - -class RequestStackTest extends TestCase -{ - public function testGetCurrentRequest() - { - $requestStack = new RequestStack(); - $this->assertNull($requestStack->getCurrentRequest()); - - $request = Request::create('/foo'); - - $requestStack->push($request); - $this->assertSame($request, $requestStack->getCurrentRequest()); - - $this->assertSame($request, $requestStack->pop()); - $this->assertNull($requestStack->getCurrentRequest()); - - $this->assertNull($requestStack->pop()); - } - - public function testGetMasterRequest() - { - $requestStack = new RequestStack(); - $this->assertNull($requestStack->getMasterRequest()); - - $masterRequest = Request::create('/foo'); - $subRequest = Request::create('/bar'); - - $requestStack->push($masterRequest); - $requestStack->push($subRequest); - - $this->assertSame($masterRequest, $requestStack->getMasterRequest()); - } - - public function testGetParentRequest() - { - $requestStack = new RequestStack(); - $this->assertNull($requestStack->getParentRequest()); - - $masterRequest = Request::create('/foo'); - - $requestStack->push($masterRequest); - $this->assertNull($requestStack->getParentRequest()); - - $firstSubRequest = Request::create('/bar'); - - $requestStack->push($firstSubRequest); - $this->assertSame($masterRequest, $requestStack->getParentRequest()); - - $secondSubRequest = Request::create('/baz'); - - $requestStack->push($secondSubRequest); - $this->assertSame($firstSubRequest, $requestStack->getParentRequest()); - } -} diff --git a/vendor/symfony/http-foundation/Tests/RequestTest.php b/vendor/symfony/http-foundation/Tests/RequestTest.php deleted file mode 100644 index bf70a5f8..00000000 --- a/vendor/symfony/http-foundation/Tests/RequestTest.php +++ /dev/null @@ -1,2451 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; - -class RequestTest extends TestCase -{ - protected function tearDown() - { - Request::setTrustedProxies([], -1); - Request::setTrustedHosts([]); - } - - public function testInitialize() - { - $request = new Request(); - - $request->initialize(['foo' => 'bar']); - $this->assertEquals('bar', $request->query->get('foo'), '->initialize() takes an array of query parameters as its first argument'); - - $request->initialize([], ['foo' => 'bar']); - $this->assertEquals('bar', $request->request->get('foo'), '->initialize() takes an array of request parameters as its second argument'); - - $request->initialize([], [], ['foo' => 'bar']); - $this->assertEquals('bar', $request->attributes->get('foo'), '->initialize() takes an array of attributes as its third argument'); - - $request->initialize([], [], [], [], [], ['HTTP_FOO' => 'bar']); - $this->assertEquals('bar', $request->headers->get('FOO'), '->initialize() takes an array of HTTP headers as its sixth argument'); - } - - public function testGetLocale() - { - $request = new Request(); - $request->setLocale('pl'); - $locale = $request->getLocale(); - $this->assertEquals('pl', $locale); - } - - public function testGetUser() - { - $request = Request::create('http://user:password@test.com'); - $user = $request->getUser(); - - $this->assertEquals('user', $user); - } - - public function testGetPassword() - { - $request = Request::create('http://user:password@test.com'); - $password = $request->getPassword(); - - $this->assertEquals('password', $password); - } - - public function testIsNoCache() - { - $request = new Request(); - $isNoCache = $request->isNoCache(); - - $this->assertFalse($isNoCache); - } - - public function testGetContentType() - { - $request = new Request(); - $contentType = $request->getContentType(); - - $this->assertNull($contentType); - } - - public function testSetDefaultLocale() - { - $request = new Request(); - $request->setDefaultLocale('pl'); - $locale = $request->getLocale(); - - $this->assertEquals('pl', $locale); - } - - public function testCreate() - { - $request = Request::create('http://test.com/foo?bar=baz'); - $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('bar=baz', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com/foo', 'GET', ['bar' => 'baz']); - $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('bar=baz', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com/foo?bar=foo', 'GET', ['bar' => 'baz']); - $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('bar=baz', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('https://test.com/foo?bar=baz'); - $this->assertEquals('https://test.com/foo?bar=baz', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('bar=baz', $request->getQueryString()); - $this->assertEquals(443, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertTrue($request->isSecure()); - - $request = Request::create('test.com:90/foo'); - $this->assertEquals('http://test.com:90/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('test.com', $request->getHost()); - $this->assertEquals('test.com:90', $request->getHttpHost()); - $this->assertEquals(90, $request->getPort()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('https://test.com:90/foo'); - $this->assertEquals('https://test.com:90/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('test.com', $request->getHost()); - $this->assertEquals('test.com:90', $request->getHttpHost()); - $this->assertEquals(90, $request->getPort()); - $this->assertTrue($request->isSecure()); - - $request = Request::create('https://127.0.0.1:90/foo'); - $this->assertEquals('https://127.0.0.1:90/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('127.0.0.1', $request->getHost()); - $this->assertEquals('127.0.0.1:90', $request->getHttpHost()); - $this->assertEquals(90, $request->getPort()); - $this->assertTrue($request->isSecure()); - - $request = Request::create('https://[::1]:90/foo'); - $this->assertEquals('https://[::1]:90/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('[::1]', $request->getHost()); - $this->assertEquals('[::1]:90', $request->getHttpHost()); - $this->assertEquals(90, $request->getPort()); - $this->assertTrue($request->isSecure()); - - $request = Request::create('https://[::1]/foo'); - $this->assertEquals('https://[::1]/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('[::1]', $request->getHost()); - $this->assertEquals('[::1]', $request->getHttpHost()); - $this->assertEquals(443, $request->getPort()); - $this->assertTrue($request->isSecure()); - - $json = '{"jsonrpc":"2.0","method":"echo","id":7,"params":["Hello World"]}'; - $request = Request::create('http://example.com/jsonrpc', 'POST', [], [], [], [], $json); - $this->assertEquals($json, $request->getContent()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com'); - $this->assertEquals('http://test.com/', $request->getUri()); - $this->assertEquals('/', $request->getPathInfo()); - $this->assertEquals('', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com?test=1'); - $this->assertEquals('http://test.com/?test=1', $request->getUri()); - $this->assertEquals('/', $request->getPathInfo()); - $this->assertEquals('test=1', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com:90/?test=1'); - $this->assertEquals('http://test.com:90/?test=1', $request->getUri()); - $this->assertEquals('/', $request->getPathInfo()); - $this->assertEquals('test=1', $request->getQueryString()); - $this->assertEquals(90, $request->getPort()); - $this->assertEquals('test.com:90', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://username:password@test.com'); - $this->assertEquals('http://test.com/', $request->getUri()); - $this->assertEquals('/', $request->getPathInfo()); - $this->assertEquals('', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertEquals('username', $request->getUser()); - $this->assertEquals('password', $request->getPassword()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://username@test.com'); - $this->assertEquals('http://test.com/', $request->getUri()); - $this->assertEquals('/', $request->getPathInfo()); - $this->assertEquals('', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertEquals('username', $request->getUser()); - $this->assertSame('', $request->getPassword()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com/?foo'); - $this->assertEquals('/?foo', $request->getRequestUri()); - $this->assertEquals(['foo' => ''], $request->query->all()); - - // assume rewrite rule: (.*) --> app/app.php; app/ is a symlink to a symfony web/ directory - $request = Request::create('http://test.com/apparthotel-1234', 'GET', [], [], [], - [ - 'DOCUMENT_ROOT' => '/var/www/www.test.com', - 'SCRIPT_FILENAME' => '/var/www/www.test.com/app/app.php', - 'SCRIPT_NAME' => '/app/app.php', - 'PHP_SELF' => '/app/app.php/apparthotel-1234', - ]); - $this->assertEquals('http://test.com/apparthotel-1234', $request->getUri()); - $this->assertEquals('/apparthotel-1234', $request->getPathInfo()); - $this->assertEquals('', $request->getQueryString()); - $this->assertEquals(80, $request->getPort()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertFalse($request->isSecure()); - - // Fragment should not be included in the URI - $request = Request::create('http://test.com/foo#bar'); - $this->assertEquals('http://test.com/foo', $request->getUri()); - } - - public function testCreateWithRequestUri() - { - $request = Request::create('http://test.com:80/foo'); - $request->server->set('REQUEST_URI', 'http://test.com:80/foo'); - $this->assertEquals('http://test.com/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('test.com', $request->getHost()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com:8080/foo'); - $request->server->set('REQUEST_URI', 'http://test.com:8080/foo'); - $this->assertEquals('http://test.com:8080/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('test.com', $request->getHost()); - $this->assertEquals('test.com:8080', $request->getHttpHost()); - $this->assertEquals(8080, $request->getPort()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('http://test.com/foo?bar=foo', 'GET', ['bar' => 'baz']); - $request->server->set('REQUEST_URI', 'http://test.com/foo?bar=foo'); - $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('bar=baz', $request->getQueryString()); - $this->assertEquals('test.com', $request->getHost()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - $request = Request::create('https://test.com:443/foo'); - $request->server->set('REQUEST_URI', 'https://test.com:443/foo'); - $this->assertEquals('https://test.com/foo', $request->getUri()); - $this->assertEquals('/foo', $request->getPathInfo()); - $this->assertEquals('test.com', $request->getHost()); - $this->assertEquals('test.com', $request->getHttpHost()); - $this->assertEquals(443, $request->getPort()); - $this->assertTrue($request->isSecure()); - - // Fragment should not be included in the URI - $request = Request::create('http://test.com/foo#bar'); - $request->server->set('REQUEST_URI', 'http://test.com/foo#bar'); - $this->assertEquals('http://test.com/foo', $request->getUri()); - } - - /** - * @dataProvider getRequestUriData - */ - public function testGetRequestUri($serverRequestUri, $expected, $message) - { - $request = new Request(); - $request->server->add([ - 'REQUEST_URI' => $serverRequestUri, - - // For having http://test.com - 'SERVER_NAME' => 'test.com', - 'SERVER_PORT' => 80, - ]); - - $this->assertSame($expected, $request->getRequestUri(), $message); - $this->assertSame($expected, $request->server->get('REQUEST_URI'), 'Normalize the request URI.'); - } - - public function getRequestUriData() - { - $message = 'Do not modify the path.'; - yield ['/foo', '/foo', $message]; - yield ['//bar/foo', '//bar/foo', $message]; - yield ['///bar/foo', '///bar/foo', $message]; - - $message = 'Handle when the scheme, host are on REQUEST_URI.'; - yield ['http://test.com/foo?bar=baz', '/foo?bar=baz', $message]; - - $message = 'Handle when the scheme, host and port are on REQUEST_URI.'; - yield ['http://test.com:80/foo', '/foo', $message]; - yield ['https://test.com:8080/foo', '/foo', $message]; - yield ['https://test.com:443/foo', '/foo', $message]; - - $message = 'Fragment should not be included in the URI'; - yield ['http://test.com/foo#bar', '/foo', $message]; - yield ['/foo#bar', '/foo', $message]; - } - - public function testGetRequestUriWithoutRequiredHeader() - { - $expected = ''; - - $request = new Request(); - - $message = 'Fallback to empty URI when headers are missing.'; - $this->assertSame($expected, $request->getRequestUri(), $message); - $this->assertSame($expected, $request->server->get('REQUEST_URI'), 'Normalize the request URI.'); - } - - public function testCreateCheckPrecedence() - { - // server is used by default - $request = Request::create('/', 'DELETE', [], [], [], [ - 'HTTP_HOST' => 'example.com', - 'HTTPS' => 'on', - 'SERVER_PORT' => 443, - 'PHP_AUTH_USER' => 'fabien', - 'PHP_AUTH_PW' => 'pa$$', - 'QUERY_STRING' => 'foo=bar', - 'CONTENT_TYPE' => 'application/json', - ]); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(443, $request->getPort()); - $this->assertTrue($request->isSecure()); - $this->assertEquals('fabien', $request->getUser()); - $this->assertEquals('pa$$', $request->getPassword()); - $this->assertEquals('', $request->getQueryString()); - $this->assertEquals('application/json', $request->headers->get('CONTENT_TYPE')); - - // URI has precedence over server - $request = Request::create('http://thomas:pokemon@example.net:8080/?foo=bar', 'GET', [], [], [], [ - 'HTTP_HOST' => 'example.com', - 'HTTPS' => 'on', - 'SERVER_PORT' => 443, - ]); - $this->assertEquals('example.net', $request->getHost()); - $this->assertEquals(8080, $request->getPort()); - $this->assertFalse($request->isSecure()); - $this->assertEquals('thomas', $request->getUser()); - $this->assertEquals('pokemon', $request->getPassword()); - $this->assertEquals('foo=bar', $request->getQueryString()); - } - - public function testDuplicate() - { - $request = new Request(['foo' => 'bar'], ['foo' => 'bar'], ['foo' => 'bar'], [], [], ['HTTP_FOO' => 'bar']); - $dup = $request->duplicate(); - - $this->assertEquals($request->query->all(), $dup->query->all(), '->duplicate() duplicates a request an copy the current query parameters'); - $this->assertEquals($request->request->all(), $dup->request->all(), '->duplicate() duplicates a request an copy the current request parameters'); - $this->assertEquals($request->attributes->all(), $dup->attributes->all(), '->duplicate() duplicates a request an copy the current attributes'); - $this->assertEquals($request->headers->all(), $dup->headers->all(), '->duplicate() duplicates a request an copy the current HTTP headers'); - - $dup = $request->duplicate(['foo' => 'foobar'], ['foo' => 'foobar'], ['foo' => 'foobar'], [], [], ['HTTP_FOO' => 'foobar']); - - $this->assertEquals(['foo' => 'foobar'], $dup->query->all(), '->duplicate() overrides the query parameters if provided'); - $this->assertEquals(['foo' => 'foobar'], $dup->request->all(), '->duplicate() overrides the request parameters if provided'); - $this->assertEquals(['foo' => 'foobar'], $dup->attributes->all(), '->duplicate() overrides the attributes if provided'); - $this->assertEquals(['foo' => ['foobar']], $dup->headers->all(), '->duplicate() overrides the HTTP header if provided'); - } - - public function testDuplicateWithFormat() - { - $request = new Request([], [], ['_format' => 'json']); - $dup = $request->duplicate(); - - $this->assertEquals('json', $dup->getRequestFormat()); - $this->assertEquals('json', $dup->attributes->get('_format')); - - $request = new Request(); - $request->setRequestFormat('xml'); - $dup = $request->duplicate(); - - $this->assertEquals('xml', $dup->getRequestFormat()); - } - - /** - * @dataProvider getFormatToMimeTypeMapProviderWithAdditionalNullFormat - */ - public function testGetFormatFromMimeType($format, $mimeTypes) - { - $request = new Request(); - foreach ($mimeTypes as $mime) { - $this->assertEquals($format, $request->getFormat($mime)); - } - $request->setFormat($format, $mimeTypes); - foreach ($mimeTypes as $mime) { - $this->assertEquals($format, $request->getFormat($mime)); - - if (null !== $format) { - $this->assertEquals($mimeTypes[0], $request->getMimeType($format)); - } - } - } - - public function getFormatToMimeTypeMapProviderWithAdditionalNullFormat() - { - return array_merge( - [[null, [null, 'unexistent-mime-type']]], - $this->getFormatToMimeTypeMapProvider() - ); - } - - public function testGetFormatFromMimeTypeWithParameters() - { - $request = new Request(); - $this->assertEquals('json', $request->getFormat('application/json; charset=utf-8')); - $this->assertEquals('json', $request->getFormat('application/json;charset=utf-8')); - $this->assertEquals('json', $request->getFormat('application/json ; charset=utf-8')); - $this->assertEquals('json', $request->getFormat('application/json ;charset=utf-8')); - } - - /** - * @dataProvider getFormatToMimeTypeMapProvider - */ - public function testGetMimeTypeFromFormat($format, $mimeTypes) - { - $request = new Request(); - $this->assertEquals($mimeTypes[0], $request->getMimeType($format)); - } - - /** - * @dataProvider getFormatToMimeTypeMapProvider - */ - public function testGetMimeTypesFromFormat($format, $mimeTypes) - { - $this->assertEquals($mimeTypes, Request::getMimeTypes($format)); - } - - public function testGetMimeTypesFromInexistentFormat() - { - $request = new Request(); - $this->assertNull($request->getMimeType('foo')); - $this->assertEquals([], Request::getMimeTypes('foo')); - } - - public function testGetFormatWithCustomMimeType() - { - $request = new Request(); - $request->setFormat('custom', 'application/vnd.foo.api;myversion=2.3'); - $this->assertEquals('custom', $request->getFormat('application/vnd.foo.api;myversion=2.3')); - } - - public function getFormatToMimeTypeMapProvider() - { - return [ - ['txt', ['text/plain']], - ['js', ['application/javascript', 'application/x-javascript', 'text/javascript']], - ['css', ['text/css']], - ['json', ['application/json', 'application/x-json']], - ['jsonld', ['application/ld+json']], - ['xml', ['text/xml', 'application/xml', 'application/x-xml']], - ['rdf', ['application/rdf+xml']], - ['atom', ['application/atom+xml']], - ]; - } - - public function testGetUri() - { - $server = []; - - // Standard Request on non default PORT - // http://host:8080/index.php/path/info?query=string - - $server['HTTP_HOST'] = 'host:8080'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '8080'; - - $server['QUERY_STRING'] = 'query=string'; - $server['REQUEST_URI'] = '/index.php/path/info?query=string'; - $server['SCRIPT_NAME'] = '/index.php'; - $server['PATH_INFO'] = '/path/info'; - $server['PATH_TRANSLATED'] = 'redirect:/index.php/path/info'; - $server['PHP_SELF'] = '/index_dev.php/path/info'; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - - $request = new Request(); - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://host:8080/index.php/path/info?query=string', $request->getUri(), '->getUri() with non default port'); - - // Use std port number - $server['HTTP_HOST'] = 'host'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://host/index.php/path/info?query=string', $request->getUri(), '->getUri() with default port'); - - // Without HOST HEADER - unset($server['HTTP_HOST']); - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://servername/index.php/path/info?query=string', $request->getUri(), '->getUri() with default port without HOST_HEADER'); - - // Request with URL REWRITING (hide index.php) - // RewriteCond %{REQUEST_FILENAME} !-f - // RewriteRule ^(.*)$ index.php [QSA,L] - // http://host:8080/path/info?query=string - $server = []; - $server['HTTP_HOST'] = 'host:8080'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '8080'; - - $server['REDIRECT_QUERY_STRING'] = 'query=string'; - $server['REDIRECT_URL'] = '/path/info'; - $server['SCRIPT_NAME'] = '/index.php'; - $server['QUERY_STRING'] = 'query=string'; - $server['REQUEST_URI'] = '/path/info?toto=test&1=1'; - $server['SCRIPT_NAME'] = '/index.php'; - $server['PHP_SELF'] = '/index.php'; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://host:8080/path/info?query=string', $request->getUri(), '->getUri() with rewrite'); - - // Use std port number - // http://host/path/info?query=string - $server['HTTP_HOST'] = 'host'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://host/path/info?query=string', $request->getUri(), '->getUri() with rewrite and default port'); - - // Without HOST HEADER - unset($server['HTTP_HOST']); - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://servername/path/info?query=string', $request->getUri(), '->getUri() with rewrite, default port without HOST_HEADER'); - - // With encoded characters - - $server = [ - 'HTTP_HOST' => 'host:8080', - 'SERVER_NAME' => 'servername', - 'SERVER_PORT' => '8080', - 'QUERY_STRING' => 'query=string', - 'REQUEST_URI' => '/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', - 'SCRIPT_NAME' => '/ba se/index_dev.php', - 'PATH_TRANSLATED' => 'redirect:/index.php/foo bar/in+fo', - 'PHP_SELF' => '/ba se/index_dev.php/path/info', - 'SCRIPT_FILENAME' => '/some/where/ba se/index_dev.php', - ]; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals( - 'http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', - $request->getUri() - ); - - // with user info - - $server['PHP_AUTH_USER'] = 'fabien'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri()); - - $server['PHP_AUTH_PW'] = 'symfony'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://host:8080/ba%20se/index_dev.php/foo%20bar/in+fo?query=string', $request->getUri()); - } - - public function testGetUriForPath() - { - $request = Request::create('http://test.com/foo?bar=baz'); - $this->assertEquals('http://test.com/some/path', $request->getUriForPath('/some/path')); - - $request = Request::create('http://test.com:90/foo?bar=baz'); - $this->assertEquals('http://test.com:90/some/path', $request->getUriForPath('/some/path')); - - $request = Request::create('https://test.com/foo?bar=baz'); - $this->assertEquals('https://test.com/some/path', $request->getUriForPath('/some/path')); - - $request = Request::create('https://test.com:90/foo?bar=baz'); - $this->assertEquals('https://test.com:90/some/path', $request->getUriForPath('/some/path')); - - $server = []; - - // Standard Request on non default PORT - // http://host:8080/index.php/path/info?query=string - - $server['HTTP_HOST'] = 'host:8080'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '8080'; - - $server['QUERY_STRING'] = 'query=string'; - $server['REQUEST_URI'] = '/index.php/path/info?query=string'; - $server['SCRIPT_NAME'] = '/index.php'; - $server['PATH_INFO'] = '/path/info'; - $server['PATH_TRANSLATED'] = 'redirect:/index.php/path/info'; - $server['PHP_SELF'] = '/index_dev.php/path/info'; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - - $request = new Request(); - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://host:8080/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with non default port'); - - // Use std port number - $server['HTTP_HOST'] = 'host'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://host/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with default port'); - - // Without HOST HEADER - unset($server['HTTP_HOST']); - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://servername/index.php/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with default port without HOST_HEADER'); - - // Request with URL REWRITING (hide index.php) - // RewriteCond %{REQUEST_FILENAME} !-f - // RewriteRule ^(.*)$ index.php [QSA,L] - // http://host:8080/path/info?query=string - $server = []; - $server['HTTP_HOST'] = 'host:8080'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '8080'; - - $server['REDIRECT_QUERY_STRING'] = 'query=string'; - $server['REDIRECT_URL'] = '/path/info'; - $server['SCRIPT_NAME'] = '/index.php'; - $server['QUERY_STRING'] = 'query=string'; - $server['REQUEST_URI'] = '/path/info?toto=test&1=1'; - $server['SCRIPT_NAME'] = '/index.php'; - $server['PHP_SELF'] = '/index.php'; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://host:8080/some/path', $request->getUriForPath('/some/path'), '->getUri() with rewrite'); - - // Use std port number - // http://host/path/info?query=string - $server['HTTP_HOST'] = 'host'; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://host/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite and default port'); - - // Without HOST HEADER - unset($server['HTTP_HOST']); - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '80'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path'), '->getUriForPath() with rewrite, default port without HOST_HEADER'); - $this->assertEquals('servername', $request->getHttpHost()); - - // with user info - - $server['PHP_AUTH_USER'] = 'fabien'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path')); - - $server['PHP_AUTH_PW'] = 'symfony'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://servername/some/path', $request->getUriForPath('/some/path')); - } - - /** - * @dataProvider getRelativeUriForPathData() - */ - public function testGetRelativeUriForPath($expected, $pathinfo, $path) - { - $this->assertEquals($expected, Request::create($pathinfo)->getRelativeUriForPath($path)); - } - - public function getRelativeUriForPathData() - { - return [ - ['me.png', '/foo', '/me.png'], - ['../me.png', '/foo/bar', '/me.png'], - ['me.png', '/foo/bar', '/foo/me.png'], - ['../baz/me.png', '/foo/bar/b', '/foo/baz/me.png'], - ['../../fooz/baz/me.png', '/foo/bar/b', '/fooz/baz/me.png'], - ['baz/me.png', '/foo/bar/b', 'baz/me.png'], - ]; - } - - public function testGetUserInfo() - { - $request = new Request(); - - $server = ['PHP_AUTH_USER' => 'fabien']; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('fabien', $request->getUserInfo()); - - $server['PHP_AUTH_USER'] = '0'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('0', $request->getUserInfo()); - - $server['PHP_AUTH_PW'] = '0'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('0:0', $request->getUserInfo()); - } - - public function testGetSchemeAndHttpHost() - { - $request = new Request(); - - $server = []; - $server['SERVER_NAME'] = 'servername'; - $server['SERVER_PORT'] = '90'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost()); - - $server['PHP_AUTH_USER'] = 'fabien'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost()); - - $server['PHP_AUTH_USER'] = '0'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost()); - - $server['PHP_AUTH_PW'] = '0'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('http://servername:90', $request->getSchemeAndHttpHost()); - } - - /** - * @dataProvider getQueryStringNormalizationData - */ - public function testGetQueryString($query, $expectedQuery, $msg) - { - $request = new Request(); - - $request->server->set('QUERY_STRING', $query); - $this->assertSame($expectedQuery, $request->getQueryString(), $msg); - } - - public function getQueryStringNormalizationData() - { - return [ - ['foo', 'foo', 'works with valueless parameters'], - ['foo=', 'foo=', 'includes a dangling equal sign'], - ['bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'], - ['foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'], - - // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded). - // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. - ['baz=Foo%20Baz&bar=Foo+Bar', 'bar=Foo%20Bar&baz=Foo%20Baz', 'normalizes spaces in both encodings "%20" and "+"'], - - ['foo[]=1&foo[]=2', 'foo%5B%5D=1&foo%5B%5D=2', 'allows array notation'], - ['foo=1&foo=2', 'foo=1&foo=2', 'allows repeated parameters'], - ['pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'], - ['0', '0', 'allows "0"'], - ['Foo Bar&Foo%20Baz', 'Foo%20Bar&Foo%20Baz', 'normalizes encoding in keys'], - ['bar=Foo Bar&baz=Foo%20Baz', 'bar=Foo%20Bar&baz=Foo%20Baz', 'normalizes encoding in values'], - ['foo=bar&&&test&&', 'foo=bar&test', 'removes unneeded delimiters'], - ['formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'], - - // Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway. - // PHP also does not include them when building _GET. - ['foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'], - ]; - } - - public function testGetQueryStringReturnsNull() - { - $request = new Request(); - - $this->assertNull($request->getQueryString(), '->getQueryString() returns null for non-existent query string'); - - $request->server->set('QUERY_STRING', ''); - $this->assertNull($request->getQueryString(), '->getQueryString() returns null for empty query string'); - } - - public function testGetHost() - { - $request = new Request(); - - $request->initialize(['foo' => 'bar']); - $this->assertEquals('', $request->getHost(), '->getHost() return empty string if not initialized'); - - $request->initialize([], [], [], [], [], ['HTTP_HOST' => 'www.example.com']); - $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from Host Header'); - - // Host header with port number - $request->initialize([], [], [], [], [], ['HTTP_HOST' => 'www.example.com:8080']); - $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from Host Header with port number'); - - // Server values - $request->initialize([], [], [], [], [], ['SERVER_NAME' => 'www.example.com']); - $this->assertEquals('www.example.com', $request->getHost(), '->getHost() from server name'); - - $request->initialize([], [], [], [], [], ['SERVER_NAME' => 'www.example.com', 'HTTP_HOST' => 'www.host.com']); - $this->assertEquals('www.host.com', $request->getHost(), '->getHost() value from Host header has priority over SERVER_NAME '); - } - - public function testGetPort() - { - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => 'https', - 'HTTP_X_FORWARDED_PORT' => '443', - ]); - $port = $request->getPort(); - - $this->assertEquals(80, $port, 'Without trusted proxies FORWARDED_PROTO and FORWARDED_PORT are ignored.'); - - Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL); - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => 'https', - 'HTTP_X_FORWARDED_PORT' => '8443', - ]); - $this->assertEquals(80, $request->getPort(), 'With PROTO and PORT on untrusted connection server value takes precedence.'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $this->assertEquals(8443, $request->getPort(), 'With PROTO and PORT set PORT takes precedence.'); - - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => 'https', - ]); - $this->assertEquals(80, $request->getPort(), 'With only PROTO set getPort() ignores trusted headers on untrusted connection.'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $this->assertEquals(443, $request->getPort(), 'With only PROTO set getPort() defaults to 443.'); - - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => 'http', - ]); - $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() ignores trusted headers on untrusted connection.'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $this->assertEquals(80, $request->getPort(), 'If X_FORWARDED_PROTO is set to HTTP getPort() returns port of the original request.'); - - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => 'On', - ]); - $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is On, getPort() ignores trusted headers on untrusted connection.'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is On, getPort() defaults to 443.'); - - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => '1', - ]); - $this->assertEquals(80, $request->getPort(), 'With only PROTO set and value is 1, getPort() ignores trusted headers on untrusted connection.'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $this->assertEquals(443, $request->getPort(), 'With only PROTO set and value is 1, getPort() defaults to 443.'); - - $request = Request::create('http://example.com', 'GET', [], [], [], [ - 'HTTP_X_FORWARDED_PROTO' => 'something-else', - ]); - $port = $request->getPort(); - $this->assertEquals(80, $port, 'With only PROTO set and value is not recognized, getPort() defaults to 80.'); - } - - public function testGetHostWithFakeHttpHostValue() - { - $this->expectException('RuntimeException'); - $request = new Request(); - $request->initialize([], [], [], [], [], ['HTTP_HOST' => 'www.host.com?query=string']); - $request->getHost(); - } - - public function testGetSetMethod() - { - $request = new Request(); - - $this->assertEquals('GET', $request->getMethod(), '->getMethod() returns GET if no method is defined'); - - $request->setMethod('get'); - $this->assertEquals('GET', $request->getMethod(), '->getMethod() returns an uppercased string'); - - $request->setMethod('PURGE'); - $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method even if it is not a standard one'); - - $request->setMethod('POST'); - $this->assertEquals('POST', $request->getMethod(), '->getMethod() returns the method POST if no _method is defined'); - - $request->setMethod('POST'); - $request->request->set('_method', 'purge'); - $this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled'); - - $request = new Request(); - $request->setMethod('POST'); - $request->request->set('_method', 'purge'); - - $this->assertFalse(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be disabled by default'); - - Request::enableHttpMethodParameterOverride(); - - $this->assertTrue(Request::getHttpMethodParameterOverride(), 'httpMethodParameterOverride should be enabled now but it is not'); - - $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST'); - $this->disableHttpMethodParameterOverride(); - - $request = new Request(); - $request->setMethod('POST'); - $request->query->set('_method', 'purge'); - $this->assertEquals('POST', $request->getMethod(), '->getMethod() does not return the method from _method if defined and POST but support not enabled'); - - $request = new Request(); - $request->setMethod('POST'); - $request->query->set('_method', 'purge'); - Request::enableHttpMethodParameterOverride(); - $this->assertEquals('PURGE', $request->getMethod(), '->getMethod() returns the method from _method if defined and POST'); - $this->disableHttpMethodParameterOverride(); - - $request = new Request(); - $request->setMethod('POST'); - $request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete'); - $this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override even though _method is set if defined and POST'); - - $request = new Request(); - $request->setMethod('POST'); - $request->headers->set('X-HTTP-METHOD-OVERRIDE', 'delete'); - $this->assertEquals('DELETE', $request->getMethod(), '->getMethod() returns the method from X-HTTP-Method-Override if defined and POST'); - - $request = new Request(); - $request->setMethod('POST'); - $request->query->set('_method', ['delete', 'patch']); - $this->assertSame('POST', $request->getMethod(), '->getMethod() returns the request method if invalid type is defined in query'); - } - - /** - * @dataProvider getClientIpsProvider - */ - public function testGetClientIp($expected, $remoteAddr, $httpForwardedFor, $trustedProxies) - { - $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies); - - $this->assertEquals($expected[0], $request->getClientIp()); - } - - /** - * @dataProvider getClientIpsProvider - */ - public function testGetClientIps($expected, $remoteAddr, $httpForwardedFor, $trustedProxies) - { - $request = $this->getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies); - - $this->assertEquals($expected, $request->getClientIps()); - } - - /** - * @dataProvider getClientIpsForwardedProvider - */ - public function testGetClientIpsForwarded($expected, $remoteAddr, $httpForwarded, $trustedProxies) - { - $request = $this->getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies); - - $this->assertEquals($expected, $request->getClientIps()); - } - - public function getClientIpsForwardedProvider() - { - // $expected $remoteAddr $httpForwarded $trustedProxies - return [ - [['127.0.0.1'], '127.0.0.1', 'for="_gazonk"', null], - [['127.0.0.1'], '127.0.0.1', 'for="_gazonk"', ['127.0.0.1']], - [['88.88.88.88'], '127.0.0.1', 'for="88.88.88.88:80"', ['127.0.0.1']], - [['192.0.2.60'], '::1', 'for=192.0.2.60;proto=http;by=203.0.113.43', ['::1']], - [['2620:0:1cfe:face:b00c::3', '192.0.2.43'], '::1', 'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3', ['::1']], - [['2001:db8:cafe::17'], '::1', 'for="[2001:db8:cafe::17]:4711', ['::1']], - ]; - } - - public function getClientIpsProvider() - { - // $expected $remoteAddr $httpForwardedFor $trustedProxies - return [ - // simple IPv4 - [['88.88.88.88'], '88.88.88.88', null, null], - // trust the IPv4 remote addr - [['88.88.88.88'], '88.88.88.88', null, ['88.88.88.88']], - - // simple IPv6 - [['::1'], '::1', null, null], - // trust the IPv6 remote addr - [['::1'], '::1', null, ['::1']], - - // forwarded for with remote IPv4 addr not trusted - [['127.0.0.1'], '127.0.0.1', '88.88.88.88', null], - // forwarded for with remote IPv4 addr trusted + comma - [['88.88.88.88'], '127.0.0.1', '88.88.88.88,', ['127.0.0.1']], - // forwarded for with remote IPv4 and all FF addrs trusted - [['88.88.88.88'], '127.0.0.1', '88.88.88.88', ['127.0.0.1', '88.88.88.88']], - // forwarded for with remote IPv4 range trusted - [['88.88.88.88'], '123.45.67.89', '88.88.88.88', ['123.45.67.0/24']], - - // forwarded for with remote IPv6 addr not trusted - [['1620:0:1cfe:face:b00c::3'], '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3', null], - // forwarded for with remote IPv6 addr trusted - [['2620:0:1cfe:face:b00c::3'], '1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3', ['1620:0:1cfe:face:b00c::3']], - // forwarded for with remote IPv6 range trusted - [['88.88.88.88'], '2a01:198:603:0:396e:4789:8e99:890f', '88.88.88.88', ['2a01:198:603:0::/65']], - - // multiple forwarded for with remote IPv4 addr trusted - [['88.88.88.88', '87.65.43.21', '127.0.0.1'], '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', ['123.45.67.89']], - // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted - [['87.65.43.21', '127.0.0.1'], '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', ['123.45.67.89', '88.88.88.88']], - // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle - [['88.88.88.88', '127.0.0.1'], '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', ['123.45.67.89', '87.65.43.21']], - // multiple forwarded for with remote IPv4 addr and all reverse proxies trusted - [['127.0.0.1'], '123.45.67.89', '127.0.0.1, 87.65.43.21, 88.88.88.88', ['123.45.67.89', '87.65.43.21', '88.88.88.88', '127.0.0.1']], - - // multiple forwarded for with remote IPv6 addr trusted - [['2620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3'], '1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', ['1620:0:1cfe:face:b00c::3']], - // multiple forwarded for with remote IPv6 addr and some reverse proxies trusted - [['3620:0:1cfe:face:b00c::3'], '1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', ['1620:0:1cfe:face:b00c::3', '2620:0:1cfe:face:b00c::3']], - // multiple forwarded for with remote IPv4 addr and some reverse proxies trusted but in the middle - [['2620:0:1cfe:face:b00c::3', '4620:0:1cfe:face:b00c::3'], '1620:0:1cfe:face:b00c::3', '4620:0:1cfe:face:b00c::3,3620:0:1cfe:face:b00c::3,2620:0:1cfe:face:b00c::3', ['1620:0:1cfe:face:b00c::3', '3620:0:1cfe:face:b00c::3']], - - // client IP with port - [['88.88.88.88'], '127.0.0.1', '88.88.88.88:12345, 127.0.0.1', ['127.0.0.1']], - - // invalid forwarded IP is ignored - [['88.88.88.88'], '127.0.0.1', 'unknown,88.88.88.88', ['127.0.0.1']], - [['88.88.88.88'], '127.0.0.1', '}__test|O:21:"JDatabaseDriverMysqli":3:{s:2,88.88.88.88', ['127.0.0.1']], - ]; - } - - /** - * @dataProvider getClientIpsWithConflictingHeadersProvider - */ - public function testGetClientIpsWithConflictingHeaders($httpForwarded, $httpXForwardedFor) - { - $this->expectException('Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException'); - $request = new Request(); - - $server = [ - 'REMOTE_ADDR' => '88.88.88.88', - 'HTTP_FORWARDED' => $httpForwarded, - 'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor, - ]; - - Request::setTrustedProxies(['88.88.88.88'], Request::HEADER_X_FORWARDED_ALL | Request::HEADER_FORWARDED); - - $request->initialize([], [], [], [], [], $server); - - $request->getClientIps(); - } - - /** - * @dataProvider getClientIpsWithConflictingHeadersProvider - */ - public function testGetClientIpsOnlyXHttpForwardedForTrusted($httpForwarded, $httpXForwardedFor) - { - $request = new Request(); - - $server = [ - 'REMOTE_ADDR' => '88.88.88.88', - 'HTTP_FORWARDED' => $httpForwarded, - 'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor, - ]; - - Request::setTrustedProxies(['88.88.88.88'], Request::HEADER_X_FORWARDED_FOR); - - $request->initialize([], [], [], [], [], $server); - - $this->assertSame(array_reverse(explode(',', $httpXForwardedFor)), $request->getClientIps()); - } - - public function getClientIpsWithConflictingHeadersProvider() - { - // $httpForwarded $httpXForwardedFor - return [ - ['for=87.65.43.21', '192.0.2.60'], - ['for=87.65.43.21, for=192.0.2.60', '192.0.2.60'], - ['for=192.0.2.60', '192.0.2.60,87.65.43.21'], - ['for="::face", for=192.0.2.60', '192.0.2.60,192.0.2.43'], - ['for=87.65.43.21, for=192.0.2.60', '192.0.2.60,87.65.43.21'], - ]; - } - - /** - * @dataProvider getClientIpsWithAgreeingHeadersProvider - */ - public function testGetClientIpsWithAgreeingHeaders($httpForwarded, $httpXForwardedFor, $expectedIps) - { - $request = new Request(); - - $server = [ - 'REMOTE_ADDR' => '88.88.88.88', - 'HTTP_FORWARDED' => $httpForwarded, - 'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor, - ]; - - Request::setTrustedProxies(['88.88.88.88'], -1); - - $request->initialize([], [], [], [], [], $server); - - $clientIps = $request->getClientIps(); - - $this->assertSame($expectedIps, $clientIps); - } - - public function getClientIpsWithAgreeingHeadersProvider() - { - // $httpForwarded $httpXForwardedFor - return [ - ['for="192.0.2.60"', '192.0.2.60', ['192.0.2.60']], - ['for=192.0.2.60, for=87.65.43.21', '192.0.2.60,87.65.43.21', ['87.65.43.21', '192.0.2.60']], - ['for="[::face]", for=192.0.2.60', '::face,192.0.2.60', ['192.0.2.60', '::face']], - ['for="192.0.2.60:80"', '192.0.2.60', ['192.0.2.60']], - ['for=192.0.2.60;proto=http;by=203.0.113.43', '192.0.2.60', ['192.0.2.60']], - ['for="[2001:db8:cafe::17]:4711"', '2001:db8:cafe::17', ['2001:db8:cafe::17']], - ]; - } - - public function testGetContentWorksTwiceInDefaultMode() - { - $req = new Request(); - $this->assertEquals('', $req->getContent()); - $this->assertEquals('', $req->getContent()); - } - - public function testGetContentReturnsResource() - { - $req = new Request(); - $retval = $req->getContent(true); - $this->assertIsResource($retval); - $this->assertEquals('', fread($retval, 1)); - $this->assertTrue(feof($retval)); - } - - public function testGetContentReturnsResourceWhenContentSetInConstructor() - { - $req = new Request([], [], [], [], [], [], 'MyContent'); - $resource = $req->getContent(true); - - $this->assertIsResource($resource); - $this->assertEquals('MyContent', stream_get_contents($resource)); - } - - public function testContentAsResource() - { - $resource = fopen('php://memory', 'r+'); - fwrite($resource, 'My other content'); - rewind($resource); - - $req = new Request([], [], [], [], [], [], $resource); - $this->assertEquals('My other content', stream_get_contents($req->getContent(true))); - $this->assertEquals('My other content', $req->getContent()); - } - - /** - * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider - */ - public function testGetContentCantBeCalledTwiceWithResources($first, $second) - { - $this->expectException('LogicException'); - if (\PHP_VERSION_ID >= 50600) { - $this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.'); - } - - $req = new Request(); - $req->getContent($first); - $req->getContent($second); - } - - public function getContentCantBeCalledTwiceWithResourcesProvider() - { - return [ - 'Resource then fetch' => [true, false], - 'Resource then resource' => [true, true], - ]; - } - - /** - * @dataProvider getContentCanBeCalledTwiceWithResourcesProvider - * @requires PHP 5.6 - */ - public function testGetContentCanBeCalledTwiceWithResources($first, $second) - { - $req = new Request(); - $a = $req->getContent($first); - $b = $req->getContent($second); - - if ($first) { - $a = stream_get_contents($a); - } - - if ($second) { - $b = stream_get_contents($b); - } - - $this->assertSame($a, $b); - } - - public function getContentCanBeCalledTwiceWithResourcesProvider() - { - return [ - 'Fetch then fetch' => [false, false], - 'Fetch then resource' => [false, true], - 'Resource then fetch' => [true, false], - 'Resource then resource' => [true, true], - ]; - } - - public function provideOverloadedMethods() - { - return [ - ['PUT'], - ['DELETE'], - ['PATCH'], - ['put'], - ['delete'], - ['patch'], - ]; - } - - /** - * @dataProvider provideOverloadedMethods - */ - public function testCreateFromGlobals($method) - { - $normalizedMethod = strtoupper($method); - - $_GET['foo1'] = 'bar1'; - $_POST['foo2'] = 'bar2'; - $_COOKIE['foo3'] = 'bar3'; - $_FILES['foo4'] = ['bar4']; - $_SERVER['foo5'] = 'bar5'; - - $request = Request::createFromGlobals(); - $this->assertEquals('bar1', $request->query->get('foo1'), '::fromGlobals() uses values from $_GET'); - $this->assertEquals('bar2', $request->request->get('foo2'), '::fromGlobals() uses values from $_POST'); - $this->assertEquals('bar3', $request->cookies->get('foo3'), '::fromGlobals() uses values from $_COOKIE'); - $this->assertEquals(['bar4'], $request->files->get('foo4'), '::fromGlobals() uses values from $_FILES'); - $this->assertEquals('bar5', $request->server->get('foo5'), '::fromGlobals() uses values from $_SERVER'); - - unset($_GET['foo1'], $_POST['foo2'], $_COOKIE['foo3'], $_FILES['foo4'], $_SERVER['foo5']); - - $_SERVER['REQUEST_METHOD'] = $method; - $_SERVER['CONTENT_TYPE'] = 'application/x-www-form-urlencoded'; - $request = RequestContentProxy::createFromGlobals(); - $this->assertEquals($normalizedMethod, $request->getMethod()); - $this->assertEquals('mycontent', $request->request->get('content')); - - unset($_SERVER['REQUEST_METHOD'], $_SERVER['CONTENT_TYPE']); - - Request::createFromGlobals(); - Request::enableHttpMethodParameterOverride(); - $_POST['_method'] = $method; - $_POST['foo6'] = 'bar6'; - $_SERVER['REQUEST_METHOD'] = 'PoSt'; - $request = Request::createFromGlobals(); - $this->assertEquals($normalizedMethod, $request->getMethod()); - $this->assertEquals('POST', $request->getRealMethod()); - $this->assertEquals('bar6', $request->request->get('foo6')); - - unset($_POST['_method'], $_POST['foo6'], $_SERVER['REQUEST_METHOD']); - $this->disableHttpMethodParameterOverride(); - } - - public function testOverrideGlobals() - { - $request = new Request(); - $request->initialize(['foo' => 'bar']); - - // as the Request::overrideGlobals really work, it erase $_SERVER, so we must backup it - $server = $_SERVER; - - $request->overrideGlobals(); - - $this->assertEquals(['foo' => 'bar'], $_GET); - - $request->initialize([], ['foo' => 'bar']); - $request->overrideGlobals(); - - $this->assertEquals(['foo' => 'bar'], $_POST); - - $this->assertArrayNotHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); - - $request->headers->set('X_FORWARDED_PROTO', 'https'); - - Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL); - $this->assertFalse($request->isSecure()); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $this->assertTrue($request->isSecure()); - - $request->overrideGlobals(); - - $this->assertArrayHasKey('HTTP_X_FORWARDED_PROTO', $_SERVER); - - $request->headers->set('CONTENT_TYPE', 'multipart/form-data'); - $request->headers->set('CONTENT_LENGTH', 12345); - - $request->overrideGlobals(); - - $this->assertArrayHasKey('CONTENT_TYPE', $_SERVER); - $this->assertArrayHasKey('CONTENT_LENGTH', $_SERVER); - - $request->initialize(['foo' => 'bar', 'baz' => 'foo']); - $request->query->remove('baz'); - - $request->overrideGlobals(); - - $this->assertEquals(['foo' => 'bar'], $_GET); - $this->assertEquals('foo=bar', $_SERVER['QUERY_STRING']); - $this->assertEquals('foo=bar', $request->server->get('QUERY_STRING')); - - // restore initial $_SERVER array - $_SERVER = $server; - } - - public function testGetScriptName() - { - $request = new Request(); - $this->assertEquals('', $request->getScriptName()); - - $server = []; - $server['SCRIPT_NAME'] = '/index.php'; - - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('/index.php', $request->getScriptName()); - - $server = []; - $server['ORIG_SCRIPT_NAME'] = '/frontend.php'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('/frontend.php', $request->getScriptName()); - - $server = []; - $server['SCRIPT_NAME'] = '/index.php'; - $server['ORIG_SCRIPT_NAME'] = '/frontend.php'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('/index.php', $request->getScriptName()); - } - - public function testGetBasePath() - { - $request = new Request(); - $this->assertEquals('', $request->getBasePath()); - - $server = []; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - $request->initialize([], [], [], [], [], $server); - $this->assertEquals('', $request->getBasePath()); - - $server = []; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - $server['SCRIPT_NAME'] = '/index.php'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('', $request->getBasePath()); - - $server = []; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - $server['PHP_SELF'] = '/index.php'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('', $request->getBasePath()); - - $server = []; - $server['SCRIPT_FILENAME'] = '/some/where/index.php'; - $server['ORIG_SCRIPT_NAME'] = '/index.php'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('', $request->getBasePath()); - } - - public function testGetPathInfo() - { - $request = new Request(); - $this->assertEquals('/', $request->getPathInfo()); - - $server = []; - $server['REQUEST_URI'] = '/path/info'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('/path/info', $request->getPathInfo()); - - $server = []; - $server['REQUEST_URI'] = '/path%20test/info'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('/path%20test/info', $request->getPathInfo()); - - $server = []; - $server['REQUEST_URI'] = '?a=b'; - $request->initialize([], [], [], [], [], $server); - - $this->assertEquals('/', $request->getPathInfo()); - } - - public function testGetParameterPrecedence() - { - $request = new Request(); - $request->attributes->set('foo', 'attr'); - $request->query->set('foo', 'query'); - $request->request->set('foo', 'body'); - - $this->assertSame('attr', $request->get('foo')); - - $request->attributes->remove('foo'); - $this->assertSame('query', $request->get('foo')); - - $request->query->remove('foo'); - $this->assertSame('body', $request->get('foo')); - - $request->request->remove('foo'); - $this->assertNull($request->get('foo')); - } - - public function testGetPreferredLanguage() - { - $request = new Request(); - $this->assertNull($request->getPreferredLanguage()); - $this->assertNull($request->getPreferredLanguage([])); - $this->assertEquals('fr', $request->getPreferredLanguage(['fr'])); - $this->assertEquals('fr', $request->getPreferredLanguage(['fr', 'en'])); - $this->assertEquals('en', $request->getPreferredLanguage(['en', 'fr'])); - $this->assertEquals('fr-ch', $request->getPreferredLanguage(['fr-ch', 'fr-fr'])); - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6'); - $this->assertEquals('en', $request->getPreferredLanguage(['en', 'en-us'])); - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6'); - $this->assertEquals('en', $request->getPreferredLanguage(['fr', 'en'])); - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en-us; q=0.8'); - $this->assertEquals('en', $request->getPreferredLanguage(['fr', 'en'])); - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en-us; q=0.8, fr-fr; q=0.6, fr; q=0.5'); - $this->assertEquals('en', $request->getPreferredLanguage(['fr', 'en'])); - } - - public function testIsXmlHttpRequest() - { - $request = new Request(); - $this->assertFalse($request->isXmlHttpRequest()); - - $request->headers->set('X-Requested-With', 'XMLHttpRequest'); - $this->assertTrue($request->isXmlHttpRequest()); - - $request->headers->remove('X-Requested-With'); - $this->assertFalse($request->isXmlHttpRequest()); - } - - /** - * @requires extension intl - */ - public function testIntlLocale() - { - $request = new Request(); - - $request->setDefaultLocale('fr'); - $this->assertEquals('fr', $request->getLocale()); - $this->assertEquals('fr', \Locale::getDefault()); - - $request->setLocale('en'); - $this->assertEquals('en', $request->getLocale()); - $this->assertEquals('en', \Locale::getDefault()); - - $request->setDefaultLocale('de'); - $this->assertEquals('en', $request->getLocale()); - $this->assertEquals('en', \Locale::getDefault()); - } - - public function testGetCharsets() - { - $request = new Request(); - $this->assertEquals([], $request->getCharsets()); - $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6'); - $this->assertEquals([], $request->getCharsets()); // testing caching - - $request = new Request(); - $request->headers->set('Accept-Charset', 'ISO-8859-1, US-ASCII, UTF-8; q=0.8, ISO-10646-UCS-2; q=0.6'); - $this->assertEquals(['ISO-8859-1', 'US-ASCII', 'UTF-8', 'ISO-10646-UCS-2'], $request->getCharsets()); - - $request = new Request(); - $request->headers->set('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.7'); - $this->assertEquals(['ISO-8859-1', 'utf-8', '*'], $request->getCharsets()); - } - - public function testGetEncodings() - { - $request = new Request(); - $this->assertEquals([], $request->getEncodings()); - $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch'); - $this->assertEquals([], $request->getEncodings()); // testing caching - - $request = new Request(); - $request->headers->set('Accept-Encoding', 'gzip,deflate,sdch'); - $this->assertEquals(['gzip', 'deflate', 'sdch'], $request->getEncodings()); - - $request = new Request(); - $request->headers->set('Accept-Encoding', 'gzip;q=0.4,deflate;q=0.9,compress;q=0.7'); - $this->assertEquals(['deflate', 'compress', 'gzip'], $request->getEncodings()); - } - - public function testGetAcceptableContentTypes() - { - $request = new Request(); - $this->assertEquals([], $request->getAcceptableContentTypes()); - $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*'); - $this->assertEquals([], $request->getAcceptableContentTypes()); // testing caching - - $request = new Request(); - $request->headers->set('Accept', 'application/vnd.wap.wmlscriptc, text/vnd.wap.wml, application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html, multipart/mixed, */*'); - $this->assertEquals(['application/vnd.wap.wmlscriptc', 'text/vnd.wap.wml', 'application/vnd.wap.xhtml+xml', 'application/xhtml+xml', 'text/html', 'multipart/mixed', '*/*'], $request->getAcceptableContentTypes()); - } - - public function testGetLanguages() - { - $request = new Request(); - $this->assertEquals([], $request->getLanguages()); - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6'); - $this->assertEquals(['zh', 'en_US', 'en'], $request->getLanguages()); - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en-us; q=0.6, en; q=0.8'); - $this->assertEquals(['zh', 'en', 'en_US'], $request->getLanguages()); // Test out of order qvalues - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, en, en-us'); - $this->assertEquals(['zh', 'en', 'en_US'], $request->getLanguages()); // Test equal weighting without qvalues - - $request = new Request(); - $request->headers->set('Accept-language', 'zh; q=0.6, en, en-us; q=0.6'); - $this->assertEquals(['en', 'zh', 'en_US'], $request->getLanguages()); // Test equal weighting with qvalues - - $request = new Request(); - $request->headers->set('Accept-language', 'zh, i-cherokee; q=0.6'); - $this->assertEquals(['zh', 'cherokee'], $request->getLanguages()); - } - - public function testGetRequestFormat() - { - $request = new Request(); - $this->assertEquals('html', $request->getRequestFormat()); - - // Ensure that setting different default values over time is possible, - // aka. setRequestFormat determines the state. - $this->assertEquals('json', $request->getRequestFormat('json')); - $this->assertEquals('html', $request->getRequestFormat('html')); - - $request = new Request(); - $this->assertNull($request->getRequestFormat(null)); - - $request = new Request(); - $this->assertNull($request->setRequestFormat('foo')); - $this->assertEquals('foo', $request->getRequestFormat(null)); - - $request = new Request(['_format' => 'foo']); - $this->assertEquals('html', $request->getRequestFormat()); - } - - public function testHasSession() - { - $request = new Request(); - - $this->assertFalse($request->hasSession()); - $request->setSession(new Session(new MockArraySessionStorage())); - $this->assertTrue($request->hasSession()); - } - - public function testGetSession() - { - $request = new Request(); - - $request->setSession(new Session(new MockArraySessionStorage())); - $this->assertTrue($request->hasSession()); - - $session = $request->getSession(); - $this->assertObjectHasAttribute('storage', $session); - $this->assertObjectHasAttribute('flashName', $session); - $this->assertObjectHasAttribute('attributeName', $session); - } - - public function testHasPreviousSession() - { - $request = new Request(); - - $this->assertFalse($request->hasPreviousSession()); - $request->cookies->set('MOCKSESSID', 'foo'); - $this->assertFalse($request->hasPreviousSession()); - $request->setSession(new Session(new MockArraySessionStorage())); - $this->assertTrue($request->hasPreviousSession()); - } - - public function testToString() - { - $request = new Request(); - - $request->headers->set('Accept-language', 'zh, en-us; q=0.8, en; q=0.6'); - $request->cookies->set('Foo', 'Bar'); - - $asString = (string) $request; - - $this->assertStringContainsString('Accept-Language: zh, en-us; q=0.8, en; q=0.6', $asString); - $this->assertStringContainsString('Cookie: Foo=Bar', $asString); - - $request->cookies->set('Another', 'Cookie'); - - $asString = (string) $request; - - $this->assertStringContainsString('Cookie: Foo=Bar; Another=Cookie', $asString); - } - - public function testIsMethod() - { - $request = new Request(); - $request->setMethod('POST'); - $this->assertTrue($request->isMethod('POST')); - $this->assertTrue($request->isMethod('post')); - $this->assertFalse($request->isMethod('GET')); - $this->assertFalse($request->isMethod('get')); - - $request->setMethod('GET'); - $this->assertTrue($request->isMethod('GET')); - $this->assertTrue($request->isMethod('get')); - $this->assertFalse($request->isMethod('POST')); - $this->assertFalse($request->isMethod('post')); - } - - /** - * @dataProvider getBaseUrlData - */ - public function testGetBaseUrl($uri, $server, $expectedBaseUrl, $expectedPathInfo) - { - $request = Request::create($uri, 'GET', [], [], [], $server); - - $this->assertSame($expectedBaseUrl, $request->getBaseUrl(), 'baseUrl'); - $this->assertSame($expectedPathInfo, $request->getPathInfo(), 'pathInfo'); - } - - public function getBaseUrlData() - { - return [ - [ - '/fruit/strawberry/1234index.php/blah', - [ - 'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/fruit/index.php', - 'SCRIPT_NAME' => '/fruit/index.php', - 'PHP_SELF' => '/fruit/index.php', - ], - '/fruit', - '/strawberry/1234index.php/blah', - ], - [ - '/fruit/strawberry/1234index.php/blah', - [ - 'SCRIPT_FILENAME' => 'E:/Sites/cc-new/public_html/index.php', - 'SCRIPT_NAME' => '/index.php', - 'PHP_SELF' => '/index.php', - ], - '', - '/fruit/strawberry/1234index.php/blah', - ], - [ - '/foo%20bar/', - [ - 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php', - 'SCRIPT_NAME' => '/foo bar/app.php', - 'PHP_SELF' => '/foo bar/app.php', - ], - '/foo%20bar', - '/', - ], - [ - '/foo%20bar/home', - [ - 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php', - 'SCRIPT_NAME' => '/foo bar/app.php', - 'PHP_SELF' => '/foo bar/app.php', - ], - '/foo%20bar', - '/home', - ], - [ - '/foo%20bar/app.php/home', - [ - 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php', - 'SCRIPT_NAME' => '/foo bar/app.php', - 'PHP_SELF' => '/foo bar/app.php', - ], - '/foo%20bar/app.php', - '/home', - ], - [ - '/foo%20bar/app.php/home%3Dbaz', - [ - 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo bar/app.php', - 'SCRIPT_NAME' => '/foo bar/app.php', - 'PHP_SELF' => '/foo bar/app.php', - ], - '/foo%20bar/app.php', - '/home%3Dbaz', - ], - [ - '/foo/bar+baz', - [ - 'SCRIPT_FILENAME' => '/home/John Doe/public_html/foo/app.php', - 'SCRIPT_NAME' => '/foo/app.php', - 'PHP_SELF' => '/foo/app.php', - ], - '/foo', - '/bar+baz', - ], - ]; - } - - /** - * @dataProvider urlencodedStringPrefixData - */ - public function testUrlencodedStringPrefix($string, $prefix, $expect) - { - $request = new Request(); - - $me = new \ReflectionMethod($request, 'getUrlencodedPrefix'); - $me->setAccessible(true); - - $this->assertSame($expect, $me->invoke($request, $string, $prefix)); - } - - public function urlencodedStringPrefixData() - { - return [ - ['foo', 'foo', 'foo'], - ['fo%6f', 'foo', 'fo%6f'], - ['foo/bar', 'foo', 'foo'], - ['fo%6f/bar', 'foo', 'fo%6f'], - ['f%6f%6f/bar', 'foo', 'f%6f%6f'], - ['%66%6F%6F/bar', 'foo', '%66%6F%6F'], - ['fo+o/bar', 'fo+o', 'fo+o'], - ['fo%2Bo/bar', 'fo+o', 'fo%2Bo'], - ]; - } - - private function disableHttpMethodParameterOverride() - { - $class = new \ReflectionClass('Symfony\\Component\\HttpFoundation\\Request'); - $property = $class->getProperty('httpMethodParameterOverride'); - $property->setAccessible(true); - $property->setValue(false); - } - - private function getRequestInstanceForClientIpTests($remoteAddr, $httpForwardedFor, $trustedProxies) - { - $request = new Request(); - - $server = ['REMOTE_ADDR' => $remoteAddr]; - if (null !== $httpForwardedFor) { - $server['HTTP_X_FORWARDED_FOR'] = $httpForwardedFor; - } - - if ($trustedProxies) { - Request::setTrustedProxies($trustedProxies, Request::HEADER_X_FORWARDED_ALL); - } - - $request->initialize([], [], [], [], [], $server); - - return $request; - } - - private function getRequestInstanceForClientIpsForwardedTests($remoteAddr, $httpForwarded, $trustedProxies) - { - $request = new Request(); - - $server = ['REMOTE_ADDR' => $remoteAddr]; - - if (null !== $httpForwarded) { - $server['HTTP_FORWARDED'] = $httpForwarded; - } - - if ($trustedProxies) { - Request::setTrustedProxies($trustedProxies, Request::HEADER_FORWARDED); - } - - $request->initialize([], [], [], [], [], $server); - - return $request; - } - - public function testTrustedProxiesXForwardedFor() - { - $request = Request::create('http://example.com/'); - $request->server->set('REMOTE_ADDR', '3.3.3.3'); - $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2'); - $request->headers->set('X_FORWARDED_HOST', 'foo.example.com:1234, real.example.com:8080'); - $request->headers->set('X_FORWARDED_PROTO', 'https'); - $request->headers->set('X_FORWARDED_PORT', 443); - - // no trusted proxies - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // disabling proxy trusting - Request::setTrustedProxies([], Request::HEADER_X_FORWARDED_ALL); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // request is forwarded by a non-trusted proxy - Request::setTrustedProxies(['2.2.2.2'], Request::HEADER_X_FORWARDED_ALL); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // trusted proxy via setTrustedProxies() - Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL); - $this->assertEquals('1.1.1.1', $request->getClientIp()); - $this->assertEquals('foo.example.com', $request->getHost()); - $this->assertEquals(443, $request->getPort()); - $this->assertTrue($request->isSecure()); - - // trusted proxy via setTrustedProxies() - Request::setTrustedProxies(['3.3.3.4', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // check various X_FORWARDED_PROTO header values - Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL); - $request->headers->set('X_FORWARDED_PROTO', 'ssl'); - $this->assertTrue($request->isSecure()); - - $request->headers->set('X_FORWARDED_PROTO', 'https, http'); - $this->assertTrue($request->isSecure()); - } - - /** - * @group legacy - * @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead. - */ - public function testLegacyTrustedProxies() - { - $request = Request::create('http://example.com/'); - $request->server->set('REMOTE_ADDR', '3.3.3.3'); - $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2'); - $request->headers->set('X_FORWARDED_HOST', 'foo.example.com, real.example.com:8080'); - $request->headers->set('X_FORWARDED_PROTO', 'https'); - $request->headers->set('X_FORWARDED_PORT', 443); - $request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4'); - $request->headers->set('X_MY_HOST', 'my.example.com'); - $request->headers->set('X_MY_PROTO', 'http'); - $request->headers->set('X_MY_PORT', 81); - - Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_X_FORWARDED_ALL); - - // custom header names - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_MY_PORT'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_MY_PROTO'); - $this->assertEquals('4.4.4.4', $request->getClientIp()); - $this->assertEquals('my.example.com', $request->getHost()); - $this->assertEquals(81, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // disabling via empty header names - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, null); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, null); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, null); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - //reset - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO'); - } - - public function testTrustedProxiesForwarded() - { - $request = Request::create('http://example.com/'); - $request->server->set('REMOTE_ADDR', '3.3.3.3'); - $request->headers->set('FORWARDED', 'for=1.1.1.1, host=foo.example.com:8080, proto=https, for=2.2.2.2, host=real.example.com:8080'); - - // no trusted proxies - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // disabling proxy trusting - Request::setTrustedProxies([], Request::HEADER_FORWARDED); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // request is forwarded by a non-trusted proxy - Request::setTrustedProxies(['2.2.2.2'], Request::HEADER_FORWARDED); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // trusted proxy via setTrustedProxies() - Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_FORWARDED); - $this->assertEquals('1.1.1.1', $request->getClientIp()); - $this->assertEquals('foo.example.com', $request->getHost()); - $this->assertEquals(8080, $request->getPort()); - $this->assertTrue($request->isSecure()); - - // trusted proxy via setTrustedProxies() - Request::setTrustedProxies(['3.3.3.4', '2.2.2.2'], Request::HEADER_FORWARDED); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // check various X_FORWARDED_PROTO header values - Request::setTrustedProxies(['3.3.3.3', '2.2.2.2'], Request::HEADER_FORWARDED); - $request->headers->set('FORWARDED', 'proto=ssl'); - $this->assertTrue($request->isSecure()); - - $request->headers->set('FORWARDED', 'proto=https, proto=http'); - $this->assertTrue($request->isSecure()); - } - - /** - * @group legacy - */ - public function testSetTrustedProxiesInvalidHeaderName() - { - $this->expectException('InvalidArgumentException'); - Request::create('http://example.com/'); - Request::setTrustedHeaderName('bogus name', 'X_MY_FOR'); - } - - /** - * @group legacy - */ - public function testGetTrustedProxiesInvalidHeaderName() - { - $this->expectException('InvalidArgumentException'); - Request::create('http://example.com/'); - Request::getTrustedHeaderName('bogus name'); - } - - /** - * @dataProvider iisRequestUriProvider - */ - public function testIISRequestUri($headers, $server, $expectedRequestUri) - { - $request = new Request(); - $request->headers->replace($headers); - $request->server->replace($server); - - $this->assertEquals($expectedRequestUri, $request->getRequestUri(), '->getRequestUri() is correct'); - - $subRequestUri = '/bar/foo'; - $subRequest = Request::create($subRequestUri, 'get', [], [], [], $request->server->all()); - $this->assertEquals($subRequestUri, $subRequest->getRequestUri(), '->getRequestUri() is correct in sub request'); - } - - public function iisRequestUriProvider() - { - return [ - [ - [], - [ - 'IIS_WasUrlRewritten' => '1', - 'UNENCODED_URL' => '/foo/bar', - ], - '/foo/bar', - ], - [ - [], - [ - 'ORIG_PATH_INFO' => '/foo/bar', - ], - '/foo/bar', - ], - [ - [], - [ - 'ORIG_PATH_INFO' => '/foo/bar', - 'QUERY_STRING' => 'foo=bar', - ], - '/foo/bar?foo=bar', - ], - ]; - } - - public function testTrustedHosts() - { - // create a request - $request = Request::create('/'); - - // no trusted host set -> no host check - $request->headers->set('host', 'evil.com'); - $this->assertEquals('evil.com', $request->getHost()); - - // add a trusted domain and all its subdomains - Request::setTrustedHosts(['^([a-z]{9}\.)?trusted\.com$']); - - // untrusted host - $request->headers->set('host', 'evil.com'); - try { - $request->getHost(); - $this->fail('Request::getHost() should throw an exception when host is not trusted.'); - } catch (SuspiciousOperationException $e) { - $this->assertEquals('Untrusted Host "evil.com".', $e->getMessage()); - } - - // trusted hosts - $request->headers->set('host', 'trusted.com'); - $this->assertEquals('trusted.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - - $request->server->set('HTTPS', true); - $request->headers->set('host', 'trusted.com'); - $this->assertEquals('trusted.com', $request->getHost()); - $this->assertEquals(443, $request->getPort()); - $request->server->set('HTTPS', false); - - $request->headers->set('host', 'trusted.com:8000'); - $this->assertEquals('trusted.com', $request->getHost()); - $this->assertEquals(8000, $request->getPort()); - - $request->headers->set('host', 'subdomain.trusted.com'); - $this->assertEquals('subdomain.trusted.com', $request->getHost()); - } - - public function testSetTrustedHostsDoesNotBreakOnSpecialCharacters() - { - Request::setTrustedHosts(['localhost(\.local){0,1}#,example.com', 'localhost']); - - $request = Request::create('/'); - $request->headers->set('host', 'localhost'); - $this->assertSame('localhost', $request->getHost()); - } - - public function testFactory() - { - Request::setFactory(function (array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) { - return new NewRequest(); - }); - - $this->assertEquals('foo', Request::create('/')->getFoo()); - - Request::setFactory(null); - } - - /** - * @dataProvider getLongHostNames - */ - public function testVeryLongHosts($host) - { - $start = microtime(true); - - $request = Request::create('/'); - $request->headers->set('host', $host); - $this->assertEquals($host, $request->getHost()); - $this->assertLessThan(5, microtime(true) - $start); - } - - /** - * @dataProvider getHostValidities - */ - public function testHostValidity($host, $isValid, $expectedHost = null, $expectedPort = null) - { - $request = Request::create('/'); - $request->headers->set('host', $host); - - if ($isValid) { - $this->assertSame($expectedHost ?: $host, $request->getHost()); - if ($expectedPort) { - $this->assertSame($expectedPort, $request->getPort()); - } - } else { - $this->expectException(SuspiciousOperationException::class); - $this->expectExceptionMessage('Invalid Host'); - - $request->getHost(); - } - } - - public function getHostValidities() - { - return [ - ['.a', false], - ['a..', false], - ['a.', true], - ["\xE9", false], - ['[::1]', true], - ['[::1]:80', true, '[::1]', 80], - [str_repeat('.', 101), false], - ]; - } - - public function getLongHostNames() - { - return [ - ['a'.str_repeat('.a', 40000)], - [str_repeat(':', 101)], - ]; - } - - /** - * @dataProvider methodIdempotentProvider - */ - public function testMethodIdempotent($method, $idempotent) - { - $request = new Request(); - $request->setMethod($method); - $this->assertEquals($idempotent, $request->isMethodIdempotent()); - } - - public function methodIdempotentProvider() - { - return [ - ['HEAD', true], - ['GET', true], - ['POST', false], - ['PUT', true], - ['PATCH', false], - ['DELETE', true], - ['PURGE', true], - ['OPTIONS', true], - ['TRACE', true], - ['CONNECT', false], - ]; - } - - /** - * @dataProvider methodSafeProvider - */ - public function testMethodSafe($method, $safe) - { - $request = new Request(); - $request->setMethod($method); - $this->assertEquals($safe, $request->isMethodSafe(false)); - } - - public function methodSafeProvider() - { - return [ - ['HEAD', true], - ['GET', true], - ['POST', false], - ['PUT', false], - ['PATCH', false], - ['DELETE', false], - ['PURGE', false], - ['OPTIONS', true], - ['TRACE', true], - ['CONNECT', false], - ]; - } - - /** - * @group legacy - * @expectedDeprecation Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead. - */ - public function testMethodSafeChecksCacheable() - { - $request = new Request(); - $request->setMethod('OPTIONS'); - $this->assertFalse($request->isMethodSafe()); - } - - /** - * @dataProvider methodCacheableProvider - */ - public function testMethodCacheable($method, $cacheable) - { - $request = new Request(); - $request->setMethod($method); - $this->assertEquals($cacheable, $request->isMethodCacheable()); - } - - public function methodCacheableProvider() - { - return [ - ['HEAD', true], - ['GET', true], - ['POST', false], - ['PUT', false], - ['PATCH', false], - ['DELETE', false], - ['PURGE', false], - ['OPTIONS', false], - ['TRACE', false], - ['CONNECT', false], - ]; - } - - /** - * @group legacy - */ - public function testGetTrustedHeaderName() - { - Request::setTrustedProxies(['8.8.8.8'], Request::HEADER_X_FORWARDED_ALL); - - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertSame('X_FORWARDED_FOR', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertSame('X_FORWARDED_HOST', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertSame('X_FORWARDED_PORT', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertSame('X_FORWARDED_PROTO', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedProxies(['8.8.8.8'], Request::HEADER_FORWARDED); - - $this->assertSame('FORWARDED', Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'A'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'B'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'C'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'D'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'E'); - - Request::setTrustedProxies(['8.8.8.8'], Request::HEADER_FORWARDED); - - $this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedProxies(['8.8.8.8'], Request::HEADER_X_FORWARDED_ALL); - - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertSame('B', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertSame('C', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertSame('D', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertSame('E', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedProxies(['8.8.8.8'], Request::HEADER_FORWARDED); - - $this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - - //reset - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO'); - } - - /** - * @dataProvider protocolVersionProvider - */ - public function testProtocolVersion($serverProtocol, $trustedProxy, $via, $expected) - { - if ($trustedProxy) { - Request::setTrustedProxies(['1.1.1.1'], -1); - } - - $request = new Request(); - $request->server->set('SERVER_PROTOCOL', $serverProtocol); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Via', $via); - - $this->assertSame($expected, $request->getProtocolVersion()); - } - - public function protocolVersionProvider() - { - return [ - 'untrusted without via' => ['HTTP/2.0', false, '', 'HTTP/2.0'], - 'untrusted with via' => ['HTTP/2.0', false, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/2.0'], - 'trusted without via' => ['HTTP/2.0', true, '', 'HTTP/2.0'], - 'trusted with via' => ['HTTP/2.0', true, '1.0 fred, 1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'], - 'trusted with via and protocol name' => ['HTTP/2.0', true, 'HTTP/1.0 fred, HTTP/1.1 nowhere.com (Apache/1.1)', 'HTTP/1.0'], - 'trusted with broken via' => ['HTTP/2.0', true, 'HTTP/1^0 foo', 'HTTP/2.0'], - 'trusted with partially-broken via' => ['HTTP/2.0', true, '1.0 fred, foo', 'HTTP/1.0'], - ]; - } - - public function nonstandardRequestsData() - { - return [ - ['', '', '/', 'http://host:8080/', ''], - ['/', '', '/', 'http://host:8080/', ''], - - ['hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'], - ['/hello/app.php/x', '', '/x', 'http://host:8080/hello/app.php/x', '/hello', '/hello/app.php'], - - ['', 'a=b', '/', 'http://host:8080/?a=b'], - ['?a=b', 'a=b', '/', 'http://host:8080/?a=b'], - ['/?a=b', 'a=b', '/', 'http://host:8080/?a=b'], - - ['x', 'a=b', '/x', 'http://host:8080/x?a=b'], - ['x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'], - ['/x?a=b', 'a=b', '/x', 'http://host:8080/x?a=b'], - - ['hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'], - ['/hello/x', '', '/x', 'http://host:8080/hello/x', '/hello'], - - ['hello/app.php/x', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'], - ['hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'], - ['/hello/app.php/x?a=b', 'a=b', '/x', 'http://host:8080/hello/app.php/x?a=b', '/hello', '/hello/app.php'], - ]; - } - - /** - * @dataProvider nonstandardRequestsData - */ - public function testNonstandardRequests($requestUri, $queryString, $expectedPathInfo, $expectedUri, $expectedBasePath = '', $expectedBaseUrl = null) - { - if (null === $expectedBaseUrl) { - $expectedBaseUrl = $expectedBasePath; - } - - $server = [ - 'HTTP_HOST' => 'host:8080', - 'SERVER_PORT' => '8080', - 'QUERY_STRING' => $queryString, - 'PHP_SELF' => '/hello/app.php', - 'SCRIPT_FILENAME' => '/some/path/app.php', - 'REQUEST_URI' => $requestUri, - ]; - - $request = new Request([], [], [], [], [], $server); - - $this->assertEquals($expectedPathInfo, $request->getPathInfo()); - $this->assertEquals($expectedUri, $request->getUri()); - $this->assertEquals($queryString, $request->getQueryString()); - $this->assertEquals(8080, $request->getPort()); - $this->assertEquals('host:8080', $request->getHttpHost()); - $this->assertEquals($expectedBaseUrl, $request->getBaseUrl()); - $this->assertEquals($expectedBasePath, $request->getBasePath()); - } - - public function testTrustedHost() - { - Request::setTrustedProxies(['1.1.1.1'], -1); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Forwarded', 'host=localhost:8080'); - $request->headers->set('X-Forwarded-Host', 'localhost:8080'); - - $this->assertSame('localhost:8080', $request->getHttpHost()); - $this->assertSame(8080, $request->getPort()); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Forwarded', 'host="[::1]:443"'); - $request->headers->set('X-Forwarded-Host', '[::1]:443'); - $request->headers->set('X-Forwarded-Port', 443); - - $this->assertSame('[::1]:443', $request->getHttpHost()); - $this->assertSame(443, $request->getPort()); - } - - public function testTrustedPort() - { - Request::setTrustedProxies(['1.1.1.1'], -1); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Forwarded', 'host=localhost:8080'); - $request->headers->set('X-Forwarded-Port', 8080); - - $this->assertSame(8080, $request->getPort()); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Forwarded', 'host=localhost'); - $request->headers->set('X-Forwarded-Port', 80); - - $this->assertSame(80, $request->getPort()); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('Forwarded', 'host="[::1]"'); - $request->headers->set('X-Forwarded-Proto', 'https'); - $request->headers->set('X-Forwarded-Port', 443); - - $this->assertSame(443, $request->getPort()); - } - - public function testTrustedPortDoesNotDefaultToZero() - { - Request::setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_ALL); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('X-Forwarded-Host', 'test.example.com'); - $request->headers->set('X-Forwarded-Port', ''); - - $this->assertSame(80, $request->getPort()); - } -} - -class RequestContentProxy extends Request -{ - public function getContent($asResource = false) - { - return http_build_query(['_method' => 'PUT', 'content' => 'mycontent'], '', '&'); - } -} - -class NewRequest extends Request -{ - public function getFoo() - { - return 'foo'; - } -} diff --git a/vendor/symfony/http-foundation/Tests/ResponseFunctionalTest.php b/vendor/symfony/http-foundation/Tests/ResponseFunctionalTest.php deleted file mode 100644 index 7aad1cac..00000000 --- a/vendor/symfony/http-foundation/Tests/ResponseFunctionalTest.php +++ /dev/null @@ -1,62 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; - -/** - * @requires PHP 7.0 - */ -class ResponseFunctionalTest extends TestCase -{ - private static $server; - - public static function setUpBeforeClass() - { - $spec = [ - 1 => ['file', '/dev/null', 'w'], - 2 => ['file', '/dev/null', 'w'], - ]; - if (!self::$server = @proc_open('exec php -S localhost:8054', $spec, $pipes, __DIR__.'/Fixtures/response-functional')) { - self::markTestSkipped('PHP server unable to start.'); - } - sleep(1); - } - - public static function tearDownAfterClass() - { - if (self::$server) { - proc_terminate(self::$server); - proc_close(self::$server); - } - } - - /** - * @dataProvider provideCookie - */ - public function testCookie($fixture) - { - if (\PHP_VERSION_ID >= 80000 && 'cookie_max_age' === $fixture) { - $this->markTestSkipped('This fixture produces a fatal error on PHP 8.'); - } - - $result = file_get_contents(sprintf('http://localhost:8054/%s.php', $fixture)); - $this->assertStringMatchesFormatFile(__DIR__.sprintf('/Fixtures/response-functional/%s.expected', $fixture), $result); - } - - public function provideCookie() - { - foreach (glob(__DIR__.'/Fixtures/response-functional/*.php') as $file) { - yield [pathinfo($file, \PATHINFO_FILENAME)]; - } - } -} diff --git a/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php b/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php deleted file mode 100644 index 028593a1..00000000 --- a/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php +++ /dev/null @@ -1,367 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Cookie; -use Symfony\Component\HttpFoundation\ResponseHeaderBag; - -/** - * @group time-sensitive - */ -class ResponseHeaderBagTest extends TestCase -{ - public function testAllPreserveCase() - { - $headers = [ - 'fOo' => 'BAR', - 'ETag' => 'xyzzy', - 'Content-MD5' => 'Q2hlY2sgSW50ZWdyaXR5IQ==', - 'P3P' => 'CP="CAO PSA OUR"', - 'WWW-Authenticate' => 'Basic realm="WallyWorld"', - 'X-UA-Compatible' => 'IE=edge,chrome=1', - 'X-XSS-Protection' => '1; mode=block', - ]; - - $bag = new ResponseHeaderBag($headers); - $allPreservedCase = $bag->allPreserveCase(); - - foreach (array_keys($headers) as $headerName) { - $this->assertArrayHasKey($headerName, $allPreservedCase, '->allPreserveCase() gets all input keys in original case'); - } - } - - public function testCacheControlHeader() - { - $bag = new ResponseHeaderBag([]); - $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('no-cache')); - - $bag = new ResponseHeaderBag(['Cache-Control' => 'public']); - $this->assertEquals('public', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('public')); - - $bag = new ResponseHeaderBag(['ETag' => 'abcde']); - $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('private')); - $this->assertTrue($bag->hasCacheControlDirective('no-cache')); - $this->assertFalse($bag->hasCacheControlDirective('max-age')); - - $bag = new ResponseHeaderBag(['Expires' => 'Wed, 16 Feb 2011 14:17:43 GMT']); - $this->assertEquals('private, must-revalidate', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag([ - 'Expires' => 'Wed, 16 Feb 2011 14:17:43 GMT', - 'Cache-Control' => 'max-age=3600', - ]); - $this->assertEquals('max-age=3600, private', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(['Last-Modified' => 'abcde']); - $this->assertEquals('private, must-revalidate', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(['Etag' => 'abcde', 'Last-Modified' => 'abcde']); - $this->assertEquals('private, must-revalidate', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(['cache-control' => 'max-age=100']); - $this->assertEquals('max-age=100, private', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(['cache-control' => 's-maxage=100']); - $this->assertEquals('s-maxage=100', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(['cache-control' => 'private, max-age=100']); - $this->assertEquals('max-age=100, private', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(['cache-control' => 'public, max-age=100']); - $this->assertEquals('max-age=100, public', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(); - $bag->set('Last-Modified', 'abcde'); - $this->assertEquals('private, must-revalidate', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(); - $bag->set('Cache-Control', ['public', 'must-revalidate']); - $this->assertCount(1, $bag->get('Cache-Control', null, false)); - $this->assertEquals('must-revalidate, public', $bag->get('Cache-Control')); - - $bag = new ResponseHeaderBag(); - $bag->set('Cache-Control', 'public'); - $bag->set('Cache-Control', 'must-revalidate', false); - $this->assertCount(1, $bag->get('Cache-Control', null, false)); - $this->assertEquals('must-revalidate, public', $bag->get('Cache-Control')); - } - - public function testCacheControlClone() - { - $headers = ['foo' => 'bar']; - $bag1 = new ResponseHeaderBag($headers); - $bag2 = new ResponseHeaderBag($bag1->allPreserveCase()); - $this->assertEquals($bag1->allPreserveCase(), $bag2->allPreserveCase()); - } - - public function testToStringIncludesCookieHeaders() - { - $bag = new ResponseHeaderBag([]); - $bag->setCookie(new Cookie('foo', 'bar')); - - $this->assertSetCookieHeader('foo=bar; path=/; httponly', $bag); - - $bag->clearCookie('foo'); - - $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; httponly', $bag); - } - - public function testClearCookieSecureNotHttpOnly() - { - $bag = new ResponseHeaderBag([]); - - $bag->clearCookie('foo', '/', null, true, false); - - $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure', $bag); - } - - public function testClearCookieSamesite() - { - $bag = new ResponseHeaderBag([]); - - $bag->clearCookie('foo', '/', null, true, false, 'none'); - $this->assertSetCookieHeader('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', time() - 31536001).'; Max-Age=0; path=/; secure; samesite=none', $bag); - } - - public function testReplace() - { - $bag = new ResponseHeaderBag([]); - $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('no-cache')); - - $bag->replace(['Cache-Control' => 'public']); - $this->assertEquals('public', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('public')); - } - - public function testReplaceWithRemove() - { - $bag = new ResponseHeaderBag([]); - $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('no-cache')); - - $bag->remove('Cache-Control'); - $bag->replace([]); - $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); - $this->assertTrue($bag->hasCacheControlDirective('no-cache')); - } - - public function testCookiesWithSameNames() - { - $bag = new ResponseHeaderBag(); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar')); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'foo.bar')); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'bar.foo')); - $bag->setCookie(new Cookie('foo', 'bar')); - - $this->assertCount(4, $bag->getCookies()); - $this->assertEquals('foo=bar; path=/path/foo; domain=foo.bar; httponly', $bag->get('set-cookie')); - $this->assertEquals([ - 'foo=bar; path=/path/foo; domain=foo.bar; httponly', - 'foo=bar; path=/path/bar; domain=foo.bar; httponly', - 'foo=bar; path=/path/bar; domain=bar.foo; httponly', - 'foo=bar; path=/; httponly', - ], $bag->get('set-cookie', null, false)); - - $this->assertSetCookieHeader('foo=bar; path=/path/foo; domain=foo.bar; httponly', $bag); - $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=foo.bar; httponly', $bag); - $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=bar.foo; httponly', $bag); - $this->assertSetCookieHeader('foo=bar; path=/; httponly', $bag); - - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - - $this->assertArrayHasKey('foo', $cookies['foo.bar']['/path/foo']); - $this->assertArrayHasKey('foo', $cookies['foo.bar']['/path/bar']); - $this->assertArrayHasKey('foo', $cookies['bar.foo']['/path/bar']); - $this->assertArrayHasKey('foo', $cookies['']['/']); - } - - public function testRemoveCookie() - { - $bag = new ResponseHeaderBag(); - $this->assertFalse($bag->has('set-cookie')); - - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar')); - $bag->setCookie(new Cookie('bar', 'foo', 0, '/path/bar', 'foo.bar')); - $this->assertTrue($bag->has('set-cookie')); - - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - $this->assertArrayHasKey('/path/foo', $cookies['foo.bar']); - - $bag->removeCookie('foo', '/path/foo', 'foo.bar'); - $this->assertTrue($bag->has('set-cookie')); - - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - $this->assertArrayNotHasKey('/path/foo', $cookies['foo.bar']); - - $bag->removeCookie('bar', '/path/bar', 'foo.bar'); - $this->assertFalse($bag->has('set-cookie')); - - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - $this->assertArrayNotHasKey('foo.bar', $cookies); - } - - public function testRemoveCookieWithNullRemove() - { - $bag = new ResponseHeaderBag(); - $bag->setCookie(new Cookie('foo', 'bar', 0)); - $bag->setCookie(new Cookie('bar', 'foo', 0)); - - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - $this->assertArrayHasKey('/', $cookies['']); - - $bag->removeCookie('foo', null); - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - $this->assertArrayNotHasKey('foo', $cookies['']['/']); - - $bag->removeCookie('bar', null); - $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); - $this->assertFalse(isset($cookies['']['/']['bar'])); - } - - public function testSetCookieHeader() - { - $bag = new ResponseHeaderBag(); - $bag->set('set-cookie', 'foo=bar'); - $this->assertEquals([new Cookie('foo', 'bar', 0, '/', null, false, false, true)], $bag->getCookies()); - - $bag->set('set-cookie', 'foo2=bar2', false); - $this->assertEquals([ - new Cookie('foo', 'bar', 0, '/', null, false, false, true), - new Cookie('foo2', 'bar2', 0, '/', null, false, false, true), - ], $bag->getCookies()); - - $bag->remove('set-cookie'); - $this->assertEquals([], $bag->getCookies()); - } - - public function testGetCookiesWithInvalidArgument() - { - $this->expectException('InvalidArgumentException'); - $bag = new ResponseHeaderBag(); - - $bag->getCookies('invalid_argument'); - } - - public function testMakeDispositionInvalidDisposition() - { - $this->expectException('InvalidArgumentException'); - $headers = new ResponseHeaderBag(); - - $headers->makeDisposition('invalid', 'foo.html'); - } - - /** - * @dataProvider provideMakeDisposition - */ - public function testMakeDisposition($disposition, $filename, $filenameFallback, $expected) - { - $headers = new ResponseHeaderBag(); - - $this->assertEquals($expected, $headers->makeDisposition($disposition, $filename, $filenameFallback)); - } - - public function testToStringDoesntMessUpHeaders() - { - $headers = new ResponseHeaderBag(); - - $headers->set('Location', 'http://www.symfony.com'); - $headers->set('Content-type', 'text/html'); - - (string) $headers; - - $allHeaders = $headers->allPreserveCase(); - $this->assertEquals(['http://www.symfony.com'], $allHeaders['Location']); - $this->assertEquals(['text/html'], $allHeaders['Content-type']); - } - - public function provideMakeDisposition() - { - return [ - ['attachment', 'foo.html', 'foo.html', 'attachment; filename="foo.html"'], - ['attachment', 'foo.html', '', 'attachment; filename="foo.html"'], - ['attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'], - ['attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'], - ['attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'], - ['attachment', 'föö.html', 'foo.html', 'attachment; filename="foo.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html'], - ]; - } - - /** - * @dataProvider provideMakeDispositionFail - */ - public function testMakeDispositionFail($disposition, $filename) - { - $this->expectException('InvalidArgumentException'); - $headers = new ResponseHeaderBag(); - - $headers->makeDisposition($disposition, $filename); - } - - public function provideMakeDispositionFail() - { - return [ - ['attachment', 'foo%20bar.html'], - ['attachment', 'foo/bar.html'], - ['attachment', '/foo.html'], - ['attachment', 'foo\bar.html'], - ['attachment', '\foo.html'], - ['attachment', 'föö.html'], - ]; - } - - public function testDateHeaderAddedOnCreation() - { - $now = time(); - - $bag = new ResponseHeaderBag(); - $this->assertTrue($bag->has('Date')); - - $this->assertEquals($now, $bag->getDate('Date')->getTimestamp()); - } - - public function testDateHeaderCanBeSetOnCreation() - { - $someDate = 'Thu, 23 Mar 2017 09:15:12 GMT'; - $bag = new ResponseHeaderBag(['Date' => $someDate]); - - $this->assertEquals($someDate, $bag->get('Date')); - } - - public function testDateHeaderWillBeRecreatedWhenRemoved() - { - $someDate = 'Thu, 23 Mar 2017 09:15:12 GMT'; - $bag = new ResponseHeaderBag(['Date' => $someDate]); - $bag->remove('Date'); - - // a (new) Date header is still present - $this->assertTrue($bag->has('Date')); - $this->assertNotEquals($someDate, $bag->get('Date')); - } - - public function testDateHeaderWillBeRecreatedWhenHeadersAreReplaced() - { - $bag = new ResponseHeaderBag(); - $bag->replace([]); - - $this->assertTrue($bag->has('Date')); - } - - private function assertSetCookieHeader($expected, ResponseHeaderBag $actual) - { - $this->assertMatchesRegularExpression('#^Set-Cookie:\s+'.preg_quote($expected, '#').'$#m', str_replace("\r\n", "\n", (string) $actual)); - } -} diff --git a/vendor/symfony/http-foundation/Tests/ResponseTest.php b/vendor/symfony/http-foundation/Tests/ResponseTest.php deleted file mode 100644 index a8297da5..00000000 --- a/vendor/symfony/http-foundation/Tests/ResponseTest.php +++ /dev/null @@ -1,1012 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; - -/** - * @group time-sensitive - */ -class ResponseTest extends ResponseTestCase -{ - public function testCreate() - { - $response = Response::create('foo', 301, ['Foo' => 'bar']); - - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); - $this->assertEquals(301, $response->getStatusCode()); - $this->assertEquals('bar', $response->headers->get('foo')); - } - - public function testToString() - { - $response = new Response(); - $response = explode("\r\n", $response); - $this->assertEquals('HTTP/1.0 200 OK', $response[0]); - $this->assertEquals('Cache-Control: no-cache, private', $response[1]); - } - - public function testClone() - { - $response = new Response(); - $responseClone = clone $response; - $this->assertEquals($response, $responseClone); - } - - public function testSendHeaders() - { - $response = new Response(); - $headers = $response->sendHeaders(); - $this->assertObjectHasAttribute('headers', $headers); - $this->assertObjectHasAttribute('content', $headers); - $this->assertObjectHasAttribute('version', $headers); - $this->assertObjectHasAttribute('statusCode', $headers); - $this->assertObjectHasAttribute('statusText', $headers); - $this->assertObjectHasAttribute('charset', $headers); - } - - public function testSend() - { - $response = new Response(); - $responseSend = $response->send(); - $this->assertObjectHasAttribute('headers', $responseSend); - $this->assertObjectHasAttribute('content', $responseSend); - $this->assertObjectHasAttribute('version', $responseSend); - $this->assertObjectHasAttribute('statusCode', $responseSend); - $this->assertObjectHasAttribute('statusText', $responseSend); - $this->assertObjectHasAttribute('charset', $responseSend); - } - - public function testGetCharset() - { - $response = new Response(); - $charsetOrigin = 'UTF-8'; - $response->setCharset($charsetOrigin); - $charset = $response->getCharset(); - $this->assertEquals($charsetOrigin, $charset); - } - - public function testIsCacheable() - { - $response = new Response(); - $this->assertFalse($response->isCacheable()); - } - - public function testIsCacheableWithErrorCode() - { - $response = new Response('', 500); - $this->assertFalse($response->isCacheable()); - } - - public function testIsCacheableWithNoStoreDirective() - { - $response = new Response(); - $response->headers->set('cache-control', 'private'); - $this->assertFalse($response->isCacheable()); - } - - public function testIsCacheableWithSetTtl() - { - $response = new Response(); - $response->setTtl(10); - $this->assertTrue($response->isCacheable()); - } - - public function testMustRevalidate() - { - $response = new Response(); - $this->assertFalse($response->mustRevalidate()); - } - - public function testMustRevalidateWithMustRevalidateCacheControlHeader() - { - $response = new Response(); - $response->headers->set('cache-control', 'must-revalidate'); - - $this->assertTrue($response->mustRevalidate()); - } - - public function testMustRevalidateWithProxyRevalidateCacheControlHeader() - { - $response = new Response(); - $response->headers->set('cache-control', 'proxy-revalidate'); - - $this->assertTrue($response->mustRevalidate()); - } - - public function testSetNotModified() - { - $response = new Response('foo'); - $modified = $response->setNotModified(); - $this->assertObjectHasAttribute('headers', $modified); - $this->assertObjectHasAttribute('content', $modified); - $this->assertObjectHasAttribute('version', $modified); - $this->assertObjectHasAttribute('statusCode', $modified); - $this->assertObjectHasAttribute('statusText', $modified); - $this->assertObjectHasAttribute('charset', $modified); - $this->assertEquals(304, $modified->getStatusCode()); - - ob_start(); - $modified->sendContent(); - $string = ob_get_clean(); - $this->assertEmpty($string); - } - - public function testIsSuccessful() - { - $response = new Response(); - $this->assertTrue($response->isSuccessful()); - } - - public function testIsNotModified() - { - $response = new Response(); - $modified = $response->isNotModified(new Request()); - $this->assertFalse($modified); - } - - public function testIsNotModifiedNotSafe() - { - $request = Request::create('/homepage', 'POST'); - - $response = new Response(); - $this->assertFalse($response->isNotModified($request)); - } - - public function testIsNotModifiedLastModified() - { - $before = 'Sun, 25 Aug 2013 18:32:31 GMT'; - $modified = 'Sun, 25 Aug 2013 18:33:31 GMT'; - $after = 'Sun, 25 Aug 2013 19:33:31 GMT'; - - $request = new Request(); - $request->headers->set('If-Modified-Since', $modified); - - $response = new Response(); - - $response->headers->set('Last-Modified', $modified); - $this->assertTrue($response->isNotModified($request)); - - $response->headers->set('Last-Modified', $before); - $this->assertTrue($response->isNotModified($request)); - - $response->headers->set('Last-Modified', $after); - $this->assertFalse($response->isNotModified($request)); - - $response->headers->set('Last-Modified', ''); - $this->assertFalse($response->isNotModified($request)); - } - - public function testIsNotModifiedEtag() - { - $etagOne = 'randomly_generated_etag'; - $etagTwo = 'randomly_generated_etag_2'; - - $request = new Request(); - $request->headers->set('if_none_match', sprintf('%s, %s, %s', $etagOne, $etagTwo, 'etagThree')); - - $response = new Response(); - - $response->headers->set('ETag', $etagOne); - $this->assertTrue($response->isNotModified($request)); - - $response->headers->set('ETag', $etagTwo); - $this->assertTrue($response->isNotModified($request)); - - $response->headers->set('ETag', ''); - $this->assertFalse($response->isNotModified($request)); - } - - public function testIsNotModifiedLastModifiedAndEtag() - { - $before = 'Sun, 25 Aug 2013 18:32:31 GMT'; - $modified = 'Sun, 25 Aug 2013 18:33:31 GMT'; - $after = 'Sun, 25 Aug 2013 19:33:31 GMT'; - $etag = 'randomly_generated_etag'; - - $request = new Request(); - $request->headers->set('if_none_match', sprintf('%s, %s', $etag, 'etagThree')); - $request->headers->set('If-Modified-Since', $modified); - - $response = new Response(); - - $response->headers->set('ETag', $etag); - $response->headers->set('Last-Modified', $after); - $this->assertFalse($response->isNotModified($request)); - - $response->headers->set('ETag', 'non-existent-etag'); - $response->headers->set('Last-Modified', $before); - $this->assertFalse($response->isNotModified($request)); - - $response->headers->set('ETag', $etag); - $response->headers->set('Last-Modified', $modified); - $this->assertTrue($response->isNotModified($request)); - } - - public function testIsNotModifiedIfModifiedSinceAndEtagWithoutLastModified() - { - $modified = 'Sun, 25 Aug 2013 18:33:31 GMT'; - $etag = 'randomly_generated_etag'; - - $request = new Request(); - $request->headers->set('if_none_match', sprintf('%s, %s', $etag, 'etagThree')); - $request->headers->set('If-Modified-Since', $modified); - - $response = new Response(); - - $response->headers->set('ETag', $etag); - $this->assertTrue($response->isNotModified($request)); - - $response->headers->set('ETag', 'non-existent-etag'); - $this->assertFalse($response->isNotModified($request)); - } - - public function testIsValidateable() - { - $response = new Response('', 200, ['Last-Modified' => $this->createDateTimeOneHourAgo()->format(\DATE_RFC2822)]); - $this->assertTrue($response->isValidateable(), '->isValidateable() returns true if Last-Modified is present'); - - $response = new Response('', 200, ['ETag' => '"12345"']); - $this->assertTrue($response->isValidateable(), '->isValidateable() returns true if ETag is present'); - - $response = new Response(); - $this->assertFalse($response->isValidateable(), '->isValidateable() returns false when no validator is present'); - } - - public function testGetDate() - { - $oneHourAgo = $this->createDateTimeOneHourAgo(); - $response = new Response('', 200, ['Date' => $oneHourAgo->format(\DATE_RFC2822)]); - $date = $response->getDate(); - $this->assertEquals($oneHourAgo->getTimestamp(), $date->getTimestamp(), '->getDate() returns the Date header if present'); - - $response = new Response(); - $date = $response->getDate(); - $this->assertEquals(time(), $date->getTimestamp(), '->getDate() returns the current Date if no Date header present'); - - $response = new Response('', 200, ['Date' => $this->createDateTimeOneHourAgo()->format(\DATE_RFC2822)]); - $now = $this->createDateTimeNow(); - $response->headers->set('Date', $now->format(\DATE_RFC2822)); - $date = $response->getDate(); - $this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the date when the header has been modified'); - - $response = new Response('', 200); - $now = $this->createDateTimeNow(); - $response->headers->remove('Date'); - $date = $response->getDate(); - $this->assertEquals($now->getTimestamp(), $date->getTimestamp(), '->getDate() returns the current Date when the header has previously been removed'); - } - - public function testGetMaxAge() - { - $response = new Response(); - $response->headers->set('Cache-Control', 's-maxage=600, max-age=0'); - $this->assertEquals(600, $response->getMaxAge(), '->getMaxAge() uses s-maxage cache control directive when present'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'max-age=600'); - $this->assertEquals(600, $response->getMaxAge(), '->getMaxAge() falls back to max-age when no s-maxage directive present'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'must-revalidate'); - $response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(\DATE_RFC2822)); - $this->assertEquals(3600, $response->getMaxAge(), '->getMaxAge() falls back to Expires when no max-age or s-maxage directive present'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'must-revalidate'); - $response->headers->set('Expires', -1); - $this->assertEquals('Sat, 01 Jan 00 00:00:00 +0000', $response->getExpires()->format(\DATE_RFC822)); - - $response = new Response(); - $this->assertNull($response->getMaxAge(), '->getMaxAge() returns null if no freshness information available'); - } - - public function testSetSharedMaxAge() - { - $response = new Response(); - $response->setSharedMaxAge(20); - - $cacheControl = $response->headers->get('Cache-Control'); - $this->assertEquals('public, s-maxage=20', $cacheControl); - } - - public function testIsPrivate() - { - $response = new Response(); - $response->headers->set('Cache-Control', 'max-age=100'); - $response->setPrivate(); - $this->assertEquals(100, $response->headers->getCacheControlDirective('max-age'), '->isPrivate() adds the private Cache-Control directive when set to true'); - $this->assertTrue($response->headers->getCacheControlDirective('private'), '->isPrivate() adds the private Cache-Control directive when set to true'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'public, max-age=100'); - $response->setPrivate(); - $this->assertEquals(100, $response->headers->getCacheControlDirective('max-age'), '->isPrivate() adds the private Cache-Control directive when set to true'); - $this->assertTrue($response->headers->getCacheControlDirective('private'), '->isPrivate() adds the private Cache-Control directive when set to true'); - $this->assertFalse($response->headers->hasCacheControlDirective('public'), '->isPrivate() removes the public Cache-Control directive'); - } - - public function testExpire() - { - $response = new Response(); - $response->headers->set('Cache-Control', 'max-age=100'); - $response->expire(); - $this->assertEquals(100, $response->headers->get('Age'), '->expire() sets the Age to max-age when present'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'max-age=100, s-maxage=500'); - $response->expire(); - $this->assertEquals(500, $response->headers->get('Age'), '->expire() sets the Age to s-maxage when both max-age and s-maxage are present'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'max-age=5, s-maxage=500'); - $response->headers->set('Age', '1000'); - $response->expire(); - $this->assertEquals(1000, $response->headers->get('Age'), '->expire() does nothing when the response is already stale/expired'); - - $response = new Response(); - $response->expire(); - $this->assertFalse($response->headers->has('Age'), '->expire() does nothing when the response does not include freshness information'); - - $response = new Response(); - $response->headers->set('Expires', -1); - $response->expire(); - $this->assertNull($response->headers->get('Age'), '->expire() does not set the Age when the response is expired'); - - $response = new Response(); - $response->headers->set('Expires', date(\DATE_RFC2822, time() + 600)); - $response->expire(); - $this->assertNull($response->headers->get('Expires'), '->expire() removes the Expires header when the response is fresh'); - } - - public function testNullExpireHeader() - { - $response = new Response(null, 200, ['Expires' => null]); - $this->assertNull($response->getExpires()); - } - - public function testGetTtl() - { - $response = new Response(); - $this->assertNull($response->getTtl(), '->getTtl() returns null when no Expires or Cache-Control headers are present'); - - $response = new Response(); - $response->headers->set('Expires', $this->createDateTimeOneHourLater()->format(\DATE_RFC2822)); - $this->assertEquals(3600, $response->getTtl(), '->getTtl() uses the Expires header when no max-age is present'); - - $response = new Response(); - $response->headers->set('Expires', $this->createDateTimeOneHourAgo()->format(\DATE_RFC2822)); - $this->assertLessThan(0, $response->getTtl(), '->getTtl() returns negative values when Expires is in past'); - - $response = new Response(); - $response->headers->set('Expires', $response->getDate()->format(\DATE_RFC2822)); - $response->headers->set('Age', 0); - $this->assertSame(0, $response->getTtl(), '->getTtl() correctly handles zero'); - - $response = new Response(); - $response->headers->set('Cache-Control', 'max-age=60'); - $this->assertEquals(60, $response->getTtl(), '->getTtl() uses Cache-Control max-age when present'); - } - - public function testSetClientTtl() - { - $response = new Response(); - $response->setClientTtl(10); - - $this->assertEquals($response->getMaxAge(), $response->getAge() + 10); - } - - public function testGetSetProtocolVersion() - { - $response = new Response(); - - $this->assertEquals('1.0', $response->getProtocolVersion()); - - $response->setProtocolVersion('1.1'); - - $this->assertEquals('1.1', $response->getProtocolVersion()); - } - - public function testGetVary() - { - $response = new Response(); - $this->assertEquals([], $response->getVary(), '->getVary() returns an empty array if no Vary header is present'); - - $response = new Response(); - $response->headers->set('Vary', 'Accept-Language'); - $this->assertEquals(['Accept-Language'], $response->getVary(), '->getVary() parses a single header name value'); - - $response = new Response(); - $response->headers->set('Vary', 'Accept-Language User-Agent X-Foo'); - $this->assertEquals(['Accept-Language', 'User-Agent', 'X-Foo'], $response->getVary(), '->getVary() parses multiple header name values separated by spaces'); - - $response = new Response(); - $response->headers->set('Vary', 'Accept-Language,User-Agent, X-Foo'); - $this->assertEquals(['Accept-Language', 'User-Agent', 'X-Foo'], $response->getVary(), '->getVary() parses multiple header name values separated by commas'); - - $vary = ['Accept-Language', 'User-Agent', 'X-foo']; - - $response = new Response(); - $response->headers->set('Vary', $vary); - $this->assertEquals($vary, $response->getVary(), '->getVary() parses multiple header name values in arrays'); - - $response = new Response(); - $response->headers->set('Vary', 'Accept-Language, User-Agent, X-foo'); - $this->assertEquals($vary, $response->getVary(), '->getVary() parses multiple header name values in arrays'); - } - - public function testSetVary() - { - $response = new Response(); - $response->setVary('Accept-Language'); - $this->assertEquals(['Accept-Language'], $response->getVary()); - - $response->setVary('Accept-Language, User-Agent'); - $this->assertEquals(['Accept-Language', 'User-Agent'], $response->getVary(), '->setVary() replace the vary header by default'); - - $response->setVary('X-Foo', false); - $this->assertEquals(['Accept-Language', 'User-Agent', 'X-Foo'], $response->getVary(), '->setVary() doesn\'t wipe out earlier Vary headers if replace is set to false'); - } - - public function testDefaultContentType() - { - $headerMock = $this->getMockBuilder('Symfony\Component\HttpFoundation\ResponseHeaderBag')->setMethods(['set'])->getMock(); - $headerMock->expects($this->exactly(2)) - ->method('set') - ->withConsecutive( - ['Content-Type', 'text/html'], - ['Content-Type', 'text/html; charset=UTF-8'] - ); - - $response = new Response('foo'); - $response->headers = $headerMock; - - $response->prepare(new Request()); - } - - public function testContentTypeCharset() - { - $response = new Response(); - $response->headers->set('Content-Type', 'text/css'); - - // force fixContentType() to be called - $response->prepare(new Request()); - - $this->assertEquals('text/css; charset=UTF-8', $response->headers->get('Content-Type')); - } - - public function testPrepareDoesNothingIfContentTypeIsSet() - { - $response = new Response('foo'); - $response->headers->set('Content-Type', 'text/plain'); - - $response->prepare(new Request()); - - $this->assertEquals('text/plain; charset=UTF-8', $response->headers->get('content-type')); - } - - public function testPrepareDoesNothingIfRequestFormatIsNotDefined() - { - $response = new Response('foo'); - - $response->prepare(new Request()); - - $this->assertEquals('text/html; charset=UTF-8', $response->headers->get('content-type')); - } - - public function testPrepareSetContentType() - { - $response = new Response('foo'); - $request = Request::create('/'); - $request->setRequestFormat('json'); - - $response->prepare($request); - - $this->assertEquals('application/json', $response->headers->get('content-type')); - } - - public function testPrepareRemovesContentForHeadRequests() - { - $response = new Response('foo'); - $request = Request::create('/', 'HEAD'); - - $length = 12345; - $response->headers->set('Content-Length', $length); - $response->prepare($request); - - $this->assertEquals('', $response->getContent()); - $this->assertEquals($length, $response->headers->get('Content-Length'), 'Content-Length should be as if it was GET; see RFC2616 14.13'); - } - - public function testPrepareRemovesContentForInformationalResponse() - { - $response = new Response('foo'); - $request = Request::create('/'); - - $response->setContent('content'); - $response->setStatusCode(101); - $response->prepare($request); - $this->assertEquals('', $response->getContent()); - $this->assertFalse($response->headers->has('Content-Type')); - - $response->setContent('content'); - $response->setStatusCode(304); - $response->prepare($request); - $this->assertEquals('', $response->getContent()); - $this->assertFalse($response->headers->has('Content-Type')); - $this->assertFalse($response->headers->has('Content-Length')); - } - - public function testPrepareRemovesContentLength() - { - $response = new Response('foo'); - $request = Request::create('/'); - - $response->headers->set('Content-Length', 12345); - $response->prepare($request); - $this->assertEquals(12345, $response->headers->get('Content-Length')); - - $response->headers->set('Transfer-Encoding', 'chunked'); - $response->prepare($request); - $this->assertFalse($response->headers->has('Content-Length')); - } - - public function testPrepareSetsPragmaOnHttp10Only() - { - $request = Request::create('/', 'GET'); - $request->server->set('SERVER_PROTOCOL', 'HTTP/1.0'); - - $response = new Response('foo'); - $response->prepare($request); - $this->assertEquals('no-cache', $response->headers->get('pragma')); - $this->assertEquals('-1', $response->headers->get('expires')); - - $request->server->set('SERVER_PROTOCOL', 'HTTP/1.1'); - $response = new Response('foo'); - $response->prepare($request); - $this->assertFalse($response->headers->has('pragma')); - $this->assertFalse($response->headers->has('expires')); - } - - public function testSetCache() - { - $response = new Response(); - // ['etag', 'last_modified', 'max_age', 's_maxage', 'private', 'public'] - try { - $response->setCache(['wrong option' => 'value']); - $this->fail('->setCache() throws an InvalidArgumentException if an option is not supported'); - } catch (\Exception $e) { - $this->assertInstanceOf('InvalidArgumentException', $e, '->setCache() throws an InvalidArgumentException if an option is not supported'); - $this->assertStringContainsString('"wrong option"', $e->getMessage()); - } - - $options = ['etag' => '"whatever"']; - $response->setCache($options); - $this->assertEquals('"whatever"', $response->getEtag()); - - $now = $this->createDateTimeNow(); - $options = ['last_modified' => $now]; - $response->setCache($options); - $this->assertEquals($now->getTimestamp(), $response->getLastModified()->getTimestamp()); - - $options = ['max_age' => 100]; - $response->setCache($options); - $this->assertEquals(100, $response->getMaxAge()); - - $options = ['s_maxage' => 200]; - $response->setCache($options); - $this->assertEquals(200, $response->getMaxAge()); - - $this->assertTrue($response->headers->hasCacheControlDirective('public')); - $this->assertFalse($response->headers->hasCacheControlDirective('private')); - - $response->setCache(['public' => true]); - $this->assertTrue($response->headers->hasCacheControlDirective('public')); - $this->assertFalse($response->headers->hasCacheControlDirective('private')); - - $response->setCache(['public' => false]); - $this->assertFalse($response->headers->hasCacheControlDirective('public')); - $this->assertTrue($response->headers->hasCacheControlDirective('private')); - - $response->setCache(['private' => true]); - $this->assertFalse($response->headers->hasCacheControlDirective('public')); - $this->assertTrue($response->headers->hasCacheControlDirective('private')); - - $response->setCache(['private' => false]); - $this->assertTrue($response->headers->hasCacheControlDirective('public')); - $this->assertFalse($response->headers->hasCacheControlDirective('private')); - - $response->setCache(['immutable' => true]); - $this->assertTrue($response->headers->hasCacheControlDirective('immutable')); - - $response->setCache(['immutable' => false]); - $this->assertFalse($response->headers->hasCacheControlDirective('immutable')); - } - - public function testSendContent() - { - $response = new Response('test response rendering', 200); - - ob_start(); - $response->sendContent(); - $string = ob_get_clean(); - $this->assertStringContainsString('test response rendering', $string); - } - - public function testSetPublic() - { - $response = new Response(); - $response->setPublic(); - - $this->assertTrue($response->headers->hasCacheControlDirective('public')); - $this->assertFalse($response->headers->hasCacheControlDirective('private')); - } - - public function testSetImmutable() - { - $response = new Response(); - $response->setImmutable(); - - $this->assertTrue($response->headers->hasCacheControlDirective('immutable')); - } - - public function testIsImmutable() - { - $response = new Response(); - $response->setImmutable(); - - $this->assertTrue($response->isImmutable()); - } - - public function testSetExpires() - { - $response = new Response(); - $response->setExpires(null); - - $this->assertNull($response->getExpires(), '->setExpires() remove the header when passed null'); - - $now = $this->createDateTimeNow(); - $response->setExpires($now); - - $this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp()); - } - - public function testSetLastModified() - { - $response = new Response(); - $response->setLastModified($this->createDateTimeNow()); - $this->assertNotNull($response->getLastModified()); - - $response->setLastModified(null); - $this->assertNull($response->getLastModified()); - } - - public function testIsInvalid() - { - $response = new Response(); - - try { - $response->setStatusCode(99); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertTrue($response->isInvalid()); - } - - try { - $response->setStatusCode(650); - $this->fail(); - } catch (\InvalidArgumentException $e) { - $this->assertTrue($response->isInvalid()); - } - - $response = new Response('', 200); - $this->assertFalse($response->isInvalid()); - } - - /** - * @dataProvider getStatusCodeFixtures - */ - public function testSetStatusCode($code, $text, $expectedText) - { - $response = new Response(); - - $response->setStatusCode($code, $text); - - $statusText = new \ReflectionProperty($response, 'statusText'); - $statusText->setAccessible(true); - - $this->assertEquals($expectedText, $statusText->getValue($response)); - } - - public function getStatusCodeFixtures() - { - return [ - ['200', null, 'OK'], - ['200', false, ''], - ['200', 'foo', 'foo'], - ['199', null, 'unknown status'], - ['199', false, ''], - ['199', 'foo', 'foo'], - ]; - } - - public function testIsInformational() - { - $response = new Response('', 100); - $this->assertTrue($response->isInformational()); - - $response = new Response('', 200); - $this->assertFalse($response->isInformational()); - } - - public function testIsRedirectRedirection() - { - foreach ([301, 302, 303, 307] as $code) { - $response = new Response('', $code); - $this->assertTrue($response->isRedirection()); - $this->assertTrue($response->isRedirect()); - } - - $response = new Response('', 304); - $this->assertTrue($response->isRedirection()); - $this->assertFalse($response->isRedirect()); - - $response = new Response('', 200); - $this->assertFalse($response->isRedirection()); - $this->assertFalse($response->isRedirect()); - - $response = new Response('', 404); - $this->assertFalse($response->isRedirection()); - $this->assertFalse($response->isRedirect()); - - $response = new Response('', 301, ['Location' => '/good-uri']); - $this->assertFalse($response->isRedirect('/bad-uri')); - $this->assertTrue($response->isRedirect('/good-uri')); - } - - public function testIsNotFound() - { - $response = new Response('', 404); - $this->assertTrue($response->isNotFound()); - - $response = new Response('', 200); - $this->assertFalse($response->isNotFound()); - } - - public function testIsEmpty() - { - foreach ([204, 304] as $code) { - $response = new Response('', $code); - $this->assertTrue($response->isEmpty()); - } - - $response = new Response('', 200); - $this->assertFalse($response->isEmpty()); - } - - public function testIsForbidden() - { - $response = new Response('', 403); - $this->assertTrue($response->isForbidden()); - - $response = new Response('', 200); - $this->assertFalse($response->isForbidden()); - } - - public function testIsOk() - { - $response = new Response('', 200); - $this->assertTrue($response->isOk()); - - $response = new Response('', 404); - $this->assertFalse($response->isOk()); - } - - public function testIsServerOrClientError() - { - $response = new Response('', 404); - $this->assertTrue($response->isClientError()); - $this->assertFalse($response->isServerError()); - - $response = new Response('', 500); - $this->assertFalse($response->isClientError()); - $this->assertTrue($response->isServerError()); - } - - public function testHasVary() - { - $response = new Response(); - $this->assertFalse($response->hasVary()); - - $response->setVary('User-Agent'); - $this->assertTrue($response->hasVary()); - } - - public function testSetEtag() - { - $response = new Response('', 200, ['ETag' => '"12345"']); - $response->setEtag(); - - $this->assertNull($response->headers->get('Etag'), '->setEtag() removes Etags when call with null'); - } - - /** - * @dataProvider validContentProvider - */ - public function testSetContent($content) - { - $response = new Response(); - $response->setContent($content); - $this->assertEquals((string) $content, $response->getContent()); - } - - /** - * @dataProvider invalidContentProvider - */ - public function testSetContentInvalid($content) - { - $this->expectException('UnexpectedValueException'); - $response = new Response(); - $response->setContent($content); - } - - public function testSettersAreChainable() - { - $response = new Response(); - - $setters = [ - 'setProtocolVersion' => '1.0', - 'setCharset' => 'UTF-8', - 'setPublic' => null, - 'setPrivate' => null, - 'setDate' => $this->createDateTimeNow(), - 'expire' => null, - 'setMaxAge' => 1, - 'setSharedMaxAge' => 1, - 'setTtl' => 1, - 'setClientTtl' => 1, - ]; - - foreach ($setters as $setter => $arg) { - $this->assertEquals($response, $response->{$setter}($arg)); - } - } - - public function testNoDeprecationsAreTriggered() - { - new DefaultResponse(); - $this->getMockBuilder(Response::class)->getMock(); - - // we just need to ensure that subclasses of Response can be created without any deprecations - // being triggered if the subclass does not override any final methods - $this->addToAssertionCount(1); - } - - public function validContentProvider() - { - return [ - 'obj' => [new StringableObject()], - 'string' => ['Foo'], - 'int' => [2], - ]; - } - - public function invalidContentProvider() - { - return [ - 'obj' => [new \stdClass()], - 'array' => [[]], - 'bool' => [true, '1'], - ]; - } - - protected function createDateTimeOneHourAgo() - { - return $this->createDateTimeNow()->sub(new \DateInterval('PT1H')); - } - - protected function createDateTimeOneHourLater() - { - return $this->createDateTimeNow()->add(new \DateInterval('PT1H')); - } - - protected function createDateTimeNow() - { - $date = new \DateTime(); - - return $date->setTimestamp(time()); - } - - protected function provideResponse() - { - return new Response(); - } - - /** - * @see http://github.com/zendframework/zend-diactoros for the canonical source repository - * - * @author Fábio Pacheco - * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com) - * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License - */ - public function ianaCodesReasonPhrasesProvider() - { - if (!\in_array('https', stream_get_wrappers(), true)) { - $this->markTestSkipped('The "https" wrapper is not available'); - } - - $ianaHttpStatusCodes = new \DOMDocument(); - - $context = stream_context_create([ - 'http' => [ - 'method' => 'GET', - 'timeout' => 30, - 'user_agent' => __METHOD__, - ], - ]); - - if (!$rawStatusCodes = file_get_contents('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml', false, $context)) { - $this->markTestSkipped('The IANA server is throttling the list of status codes'); - } - - $ianaHttpStatusCodes->loadXML($rawStatusCodes); - if (!$ianaHttpStatusCodes->relaxNGValidate(__DIR__.'/schema/http-status-codes.rng')) { - self::fail('Invalid IANA\'s HTTP status code list.'); - } - - $ianaCodesReasonPhrases = []; - - $xpath = new \DOMXPath($ianaHttpStatusCodes); - $xpath->registerNamespace('ns', 'http://www.iana.org/assignments'); - - $records = $xpath->query('//ns:record'); - foreach ($records as $record) { - $value = $xpath->query('.//ns:value', $record)->item(0)->nodeValue; - $description = $xpath->query('.//ns:description', $record)->item(0)->nodeValue; - - if (\in_array($description, ['Unassigned', '(Unused)'], true)) { - continue; - } - - if (preg_match('/^([0-9]+)\s*\-\s*([0-9]+)$/', $value, $matches)) { - for ($value = $matches[1]; $value <= $matches[2]; ++$value) { - $ianaCodesReasonPhrases[] = [$value, $description]; - } - } else { - $ianaCodesReasonPhrases[] = [$value, $description]; - } - } - - return $ianaCodesReasonPhrases; - } - - /** - * @dataProvider ianaCodesReasonPhrasesProvider - */ - public function testReasonPhraseDefaultsAgainstIana($code, $reasonPhrase) - { - $this->assertEquals($reasonPhrase, Response::$statusTexts[$code]); - } -} - -class StringableObject -{ - public function __toString() - { - return 'Foo'; - } -} - -class DefaultResponse extends Response -{ -} diff --git a/vendor/symfony/http-foundation/Tests/ResponseTestCase.php b/vendor/symfony/http-foundation/Tests/ResponseTestCase.php deleted file mode 100644 index 4ead34c1..00000000 --- a/vendor/symfony/http-foundation/Tests/ResponseTestCase.php +++ /dev/null @@ -1,89 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; - -abstract class ResponseTestCase extends TestCase -{ - public function testNoCacheControlHeaderOnAttachmentUsingHTTPSAndMSIE() - { - // Check for HTTPS and IE 8 - $request = new Request(); - $request->server->set('HTTPS', true); - $request->server->set('HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertFalse($response->headers->has('Cache-Control')); - - // Check for IE 10 and HTTPS - $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)'); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for IE 9 and HTTPS - $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)'); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for IE 9 and HTTP - $request->server->set('HTTPS', false); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for IE 8 and HTTP - $request->server->set('HTTP_USER_AGENT', 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)'); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for non-IE and HTTPS - $request->server->set('HTTPS', true); - $request->server->set('HTTP_USER_AGENT', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17'); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - - // Check for non-IE and HTTP - $request->server->set('HTTPS', false); - - $response = $this->provideResponse(); - $response->headers->set('Content-Disposition', 'attachment; filename="fname.ext"'); - $response->prepare($request); - - $this->assertTrue($response->headers->has('Cache-Control')); - } - - abstract protected function provideResponse(); -} diff --git a/vendor/symfony/http-foundation/Tests/ServerBagTest.php b/vendor/symfony/http-foundation/Tests/ServerBagTest.php deleted file mode 100644 index 0663b118..00000000 --- a/vendor/symfony/http-foundation/Tests/ServerBagTest.php +++ /dev/null @@ -1,170 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\ServerBag; - -/** - * ServerBagTest. - * - * @author Bulat Shakirzyanov - */ -class ServerBagTest extends TestCase -{ - public function testShouldExtractHeadersFromServerArray() - { - $server = [ - 'SOME_SERVER_VARIABLE' => 'value', - 'SOME_SERVER_VARIABLE2' => 'value', - 'ROOT' => 'value', - 'HTTP_CONTENT_TYPE' => 'text/html', - 'HTTP_CONTENT_LENGTH' => '0', - 'HTTP_ETAG' => 'asdf', - 'PHP_AUTH_USER' => 'foo', - 'PHP_AUTH_PW' => 'bar', - ]; - - $bag = new ServerBag($server); - - $this->assertEquals([ - 'CONTENT_TYPE' => 'text/html', - 'CONTENT_LENGTH' => '0', - 'ETAG' => 'asdf', - 'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'), - 'PHP_AUTH_USER' => 'foo', - 'PHP_AUTH_PW' => 'bar', - ], $bag->getHeaders()); - } - - public function testHttpPasswordIsOptional() - { - $bag = new ServerBag(['PHP_AUTH_USER' => 'foo']); - - $this->assertEquals([ - 'AUTHORIZATION' => 'Basic '.base64_encode('foo:'), - 'PHP_AUTH_USER' => 'foo', - 'PHP_AUTH_PW' => '', - ], $bag->getHeaders()); - } - - public function testHttpBasicAuthWithPhpCgi() - { - $bag = new ServerBag(['HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:bar')]); - - $this->assertEquals([ - 'AUTHORIZATION' => 'Basic '.base64_encode('foo:bar'), - 'PHP_AUTH_USER' => 'foo', - 'PHP_AUTH_PW' => 'bar', - ], $bag->getHeaders()); - } - - public function testHttpBasicAuthWithPhpCgiBogus() - { - $bag = new ServerBag(['HTTP_AUTHORIZATION' => 'Basic_'.base64_encode('foo:bar')]); - - // Username and passwords should not be set as the header is bogus - $headers = $bag->getHeaders(); - $this->assertArrayNotHasKey('PHP_AUTH_USER', $headers); - $this->assertArrayNotHasKey('PHP_AUTH_PW', $headers); - } - - public function testHttpBasicAuthWithPhpCgiRedirect() - { - $bag = new ServerBag(['REDIRECT_HTTP_AUTHORIZATION' => 'Basic '.base64_encode('username:pass:word')]); - - $this->assertEquals([ - 'AUTHORIZATION' => 'Basic '.base64_encode('username:pass:word'), - 'PHP_AUTH_USER' => 'username', - 'PHP_AUTH_PW' => 'pass:word', - ], $bag->getHeaders()); - } - - public function testHttpBasicAuthWithPhpCgiEmptyPassword() - { - $bag = new ServerBag(['HTTP_AUTHORIZATION' => 'Basic '.base64_encode('foo:')]); - - $this->assertEquals([ - 'AUTHORIZATION' => 'Basic '.base64_encode('foo:'), - 'PHP_AUTH_USER' => 'foo', - 'PHP_AUTH_PW' => '', - ], $bag->getHeaders()); - } - - public function testHttpDigestAuthWithPhpCgi() - { - $digest = 'Digest username="foo", realm="acme", nonce="'.md5('secret').'", uri="/protected, qop="auth"'; - $bag = new ServerBag(['HTTP_AUTHORIZATION' => $digest]); - - $this->assertEquals([ - 'AUTHORIZATION' => $digest, - 'PHP_AUTH_DIGEST' => $digest, - ], $bag->getHeaders()); - } - - public function testHttpDigestAuthWithPhpCgiBogus() - { - $digest = 'Digest_username="foo", realm="acme", nonce="'.md5('secret').'", uri="/protected, qop="auth"'; - $bag = new ServerBag(['HTTP_AUTHORIZATION' => $digest]); - - // Username and passwords should not be set as the header is bogus - $headers = $bag->getHeaders(); - $this->assertArrayNotHasKey('PHP_AUTH_USER', $headers); - $this->assertArrayNotHasKey('PHP_AUTH_PW', $headers); - } - - public function testHttpDigestAuthWithPhpCgiRedirect() - { - $digest = 'Digest username="foo", realm="acme", nonce="'.md5('secret').'", uri="/protected, qop="auth"'; - $bag = new ServerBag(['REDIRECT_HTTP_AUTHORIZATION' => $digest]); - - $this->assertEquals([ - 'AUTHORIZATION' => $digest, - 'PHP_AUTH_DIGEST' => $digest, - ], $bag->getHeaders()); - } - - public function testOAuthBearerAuth() - { - $headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo'; - $bag = new ServerBag(['HTTP_AUTHORIZATION' => $headerContent]); - - $this->assertEquals([ - 'AUTHORIZATION' => $headerContent, - ], $bag->getHeaders()); - } - - public function testOAuthBearerAuthWithRedirect() - { - $headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo'; - $bag = new ServerBag(['REDIRECT_HTTP_AUTHORIZATION' => $headerContent]); - - $this->assertEquals([ - 'AUTHORIZATION' => $headerContent, - ], $bag->getHeaders()); - } - - /** - * @see https://github.com/symfony/symfony/issues/17345 - */ - public function testItDoesNotOverwriteTheAuthorizationHeaderIfItIsAlreadySet() - { - $headerContent = 'Bearer L-yLEOr9zhmUYRkzN1jwwxwQ-PBNiKDc8dgfB4hTfvo'; - $bag = new ServerBag(['PHP_AUTH_USER' => 'foo', 'HTTP_AUTHORIZATION' => $headerContent]); - - $this->assertEquals([ - 'AUTHORIZATION' => $headerContent, - 'PHP_AUTH_USER' => 'foo', - 'PHP_AUTH_PW' => '', - ], $bag->getHeaders()); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php b/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php deleted file mode 100644 index 3f2f7b3c..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php +++ /dev/null @@ -1,186 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Attribute; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; - -/** - * Tests AttributeBag. - * - * @author Drak - */ -class AttributeBagTest extends TestCase -{ - private $array = []; - - /** - * @var AttributeBag - */ - private $bag; - - protected function setUp() - { - $this->array = [ - 'hello' => 'world', - 'always' => 'be happy', - 'user.login' => 'drak', - 'csrf.token' => [ - 'a' => '1234', - 'b' => '4321', - ], - 'category' => [ - 'fishing' => [ - 'first' => 'cod', - 'second' => 'sole', - ], - ], - ]; - $this->bag = new AttributeBag('_sf2'); - $this->bag->initialize($this->array); - } - - protected function tearDown() - { - $this->bag = null; - $this->array = []; - } - - public function testInitialize() - { - $bag = new AttributeBag(); - $bag->initialize($this->array); - $this->assertEquals($this->array, $bag->all()); - $array = ['should' => 'change']; - $bag->initialize($array); - $this->assertEquals($array, $bag->all()); - } - - public function testGetStorageKey() - { - $this->assertEquals('_sf2', $this->bag->getStorageKey()); - $attributeBag = new AttributeBag('test'); - $this->assertEquals('test', $attributeBag->getStorageKey()); - } - - public function testGetSetName() - { - $this->assertEquals('attributes', $this->bag->getName()); - $this->bag->setName('foo'); - $this->assertEquals('foo', $this->bag->getName()); - } - - /** - * @dataProvider attributesProvider - */ - public function testHas($key, $value, $exists) - { - $this->assertEquals($exists, $this->bag->has($key)); - } - - /** - * @dataProvider attributesProvider - */ - public function testGet($key, $value, $expected) - { - $this->assertEquals($value, $this->bag->get($key)); - } - - public function testGetDefaults() - { - $this->assertNull($this->bag->get('user2.login')); - $this->assertEquals('default', $this->bag->get('user2.login', 'default')); - } - - /** - * @dataProvider attributesProvider - */ - public function testSet($key, $value, $expected) - { - $this->bag->set($key, $value); - $this->assertEquals($value, $this->bag->get($key)); - } - - public function testAll() - { - $this->assertEquals($this->array, $this->bag->all()); - - $this->bag->set('hello', 'fabien'); - $array = $this->array; - $array['hello'] = 'fabien'; - $this->assertEquals($array, $this->bag->all()); - } - - public function testReplace() - { - $array = []; - $array['name'] = 'jack'; - $array['foo.bar'] = 'beep'; - $this->bag->replace($array); - $this->assertEquals($array, $this->bag->all()); - $this->assertNull($this->bag->get('hello')); - $this->assertNull($this->bag->get('always')); - $this->assertNull($this->bag->get('user.login')); - } - - public function testRemove() - { - $this->assertEquals('world', $this->bag->get('hello')); - $this->bag->remove('hello'); - $this->assertNull($this->bag->get('hello')); - - $this->assertEquals('be happy', $this->bag->get('always')); - $this->bag->remove('always'); - $this->assertNull($this->bag->get('always')); - - $this->assertEquals('drak', $this->bag->get('user.login')); - $this->bag->remove('user.login'); - $this->assertNull($this->bag->get('user.login')); - } - - public function testClear() - { - $this->bag->clear(); - $this->assertEquals([], $this->bag->all()); - } - - public function attributesProvider() - { - return [ - ['hello', 'world', true], - ['always', 'be happy', true], - ['user.login', 'drak', true], - ['csrf.token', ['a' => '1234', 'b' => '4321'], true], - ['category', ['fishing' => ['first' => 'cod', 'second' => 'sole']], true], - ['user2.login', null, false], - ['never', null, false], - ['bye', null, false], - ['bye/for/now', null, false], - ]; - } - - public function testGetIterator() - { - $i = 0; - foreach ($this->bag as $key => $val) { - $this->assertEquals($this->array[$key], $val); - ++$i; - } - - $this->assertEquals(\count($this->array), $i); - } - - public function testCount() - { - $this->assertCount(\count($this->array), $this->bag); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php b/vendor/symfony/http-foundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php deleted file mode 100644 index 6b4bb17d..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php +++ /dev/null @@ -1,204 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Attribute; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag; - -/** - * Tests NamespacedAttributeBag. - * - * @author Drak - */ -class NamespacedAttributeBagTest extends TestCase -{ - private $array = []; - - /** - * @var NamespacedAttributeBag - */ - private $bag; - - protected function setUp() - { - $this->array = [ - 'hello' => 'world', - 'always' => 'be happy', - 'user.login' => 'drak', - 'csrf.token' => [ - 'a' => '1234', - 'b' => '4321', - ], - 'category' => [ - 'fishing' => [ - 'first' => 'cod', - 'second' => 'sole', - ], - ], - ]; - $this->bag = new NamespacedAttributeBag('_sf2', '/'); - $this->bag->initialize($this->array); - } - - protected function tearDown() - { - $this->bag = null; - $this->array = []; - } - - public function testInitialize() - { - $bag = new NamespacedAttributeBag(); - $bag->initialize($this->array); - $this->assertEquals($this->array, $this->bag->all()); - $array = ['should' => 'not stick']; - $bag->initialize($array); - - // should have remained the same - $this->assertEquals($this->array, $this->bag->all()); - } - - public function testGetStorageKey() - { - $this->assertEquals('_sf2', $this->bag->getStorageKey()); - $attributeBag = new NamespacedAttributeBag('test'); - $this->assertEquals('test', $attributeBag->getStorageKey()); - } - - /** - * @dataProvider attributesProvider - */ - public function testHas($key, $value, $exists) - { - $this->assertEquals($exists, $this->bag->has($key)); - } - - /** - * @dataProvider attributesProvider - */ - public function testHasNoSideEffect($key, $value, $expected) - { - $expected = json_encode($this->bag->all()); - $this->bag->has($key); - - $this->assertEquals($expected, json_encode($this->bag->all())); - } - - /** - * @dataProvider attributesProvider - */ - public function testGet($key, $value, $expected) - { - $this->assertEquals($value, $this->bag->get($key)); - } - - public function testGetDefaults() - { - $this->assertNull($this->bag->get('user2.login')); - $this->assertEquals('default', $this->bag->get('user2.login', 'default')); - } - - /** - * @dataProvider attributesProvider - */ - public function testGetNoSideEffect($key, $value, $expected) - { - $expected = json_encode($this->bag->all()); - $this->bag->get($key); - - $this->assertEquals($expected, json_encode($this->bag->all())); - } - - /** - * @dataProvider attributesProvider - */ - public function testSet($key, $value, $expected) - { - $this->bag->set($key, $value); - $this->assertEquals($value, $this->bag->get($key)); - } - - public function testAll() - { - $this->assertEquals($this->array, $this->bag->all()); - - $this->bag->set('hello', 'fabien'); - $array = $this->array; - $array['hello'] = 'fabien'; - $this->assertEquals($array, $this->bag->all()); - } - - public function testReplace() - { - $array = []; - $array['name'] = 'jack'; - $array['foo.bar'] = 'beep'; - $this->bag->replace($array); - $this->assertEquals($array, $this->bag->all()); - $this->assertNull($this->bag->get('hello')); - $this->assertNull($this->bag->get('always')); - $this->assertNull($this->bag->get('user.login')); - } - - public function testRemove() - { - $this->assertEquals('world', $this->bag->get('hello')); - $this->bag->remove('hello'); - $this->assertNull($this->bag->get('hello')); - - $this->assertEquals('be happy', $this->bag->get('always')); - $this->bag->remove('always'); - $this->assertNull($this->bag->get('always')); - - $this->assertEquals('drak', $this->bag->get('user.login')); - $this->bag->remove('user.login'); - $this->assertNull($this->bag->get('user.login')); - } - - public function testRemoveExistingNamespacedAttribute() - { - $this->assertSame('cod', $this->bag->remove('category/fishing/first')); - } - - public function testRemoveNonexistingNamespacedAttribute() - { - $this->assertNull($this->bag->remove('foo/bar/baz')); - } - - public function testClear() - { - $this->bag->clear(); - $this->assertEquals([], $this->bag->all()); - } - - public function attributesProvider() - { - return [ - ['hello', 'world', true], - ['always', 'be happy', true], - ['user.login', 'drak', true], - ['csrf.token', ['a' => '1234', 'b' => '4321'], true], - ['csrf.token/a', '1234', true], - ['csrf.token/b', '4321', true], - ['category', ['fishing' => ['first' => 'cod', 'second' => 'sole']], true], - ['category/fishing', ['first' => 'cod', 'second' => 'sole'], true], - ['category/fishing/missing/first', null, false], - ['category/fishing/first', 'cod', true], - ['category/fishing/second', 'sole', true], - ['category/fishing/missing/second', null, false], - ['user2.login', null, false], - ['never', null, false], - ['bye', null, false], - ['bye/for/now', null, false], - ]; - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Flash/AutoExpireFlashBagTest.php b/vendor/symfony/http-foundation/Tests/Session/Flash/AutoExpireFlashBagTest.php deleted file mode 100644 index b4e2c3a5..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Flash/AutoExpireFlashBagTest.php +++ /dev/null @@ -1,161 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Flash; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag as FlashBag; - -/** - * AutoExpireFlashBagTest. - * - * @author Drak - */ -class AutoExpireFlashBagTest extends TestCase -{ - /** - * @var \Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag - */ - private $bag; - - protected $array = []; - - protected function setUp() - { - parent::setUp(); - $this->bag = new FlashBag(); - $this->array = ['new' => ['notice' => ['A previous flash message']]]; - $this->bag->initialize($this->array); - } - - protected function tearDown() - { - $this->bag = null; - parent::tearDown(); - } - - public function testInitialize() - { - $bag = new FlashBag(); - $array = ['new' => ['notice' => ['A previous flash message']]]; - $bag->initialize($array); - $this->assertEquals(['A previous flash message'], $bag->peek('notice')); - $array = ['new' => [ - 'notice' => ['Something else'], - 'error' => ['a'], - ]]; - $bag->initialize($array); - $this->assertEquals(['Something else'], $bag->peek('notice')); - $this->assertEquals(['a'], $bag->peek('error')); - } - - public function testGetStorageKey() - { - $this->assertEquals('_symfony_flashes', $this->bag->getStorageKey()); - $attributeBag = new FlashBag('test'); - $this->assertEquals('test', $attributeBag->getStorageKey()); - } - - public function testGetSetName() - { - $this->assertEquals('flashes', $this->bag->getName()); - $this->bag->setName('foo'); - $this->assertEquals('foo', $this->bag->getName()); - } - - public function testPeek() - { - $this->assertEquals([], $this->bag->peek('non_existing')); - $this->assertEquals(['default'], $this->bag->peek('non_existing', ['default'])); - $this->assertEquals(['A previous flash message'], $this->bag->peek('notice')); - $this->assertEquals(['A previous flash message'], $this->bag->peek('notice')); - } - - public function testSet() - { - $this->bag->set('notice', 'Foo'); - $this->assertEquals(['A previous flash message'], $this->bag->peek('notice')); - } - - public function testHas() - { - $this->assertFalse($this->bag->has('nothing')); - $this->assertTrue($this->bag->has('notice')); - } - - public function testKeys() - { - $this->assertEquals(['notice'], $this->bag->keys()); - } - - public function testPeekAll() - { - $array = [ - 'new' => [ - 'notice' => 'Foo', - 'error' => 'Bar', - ], - ]; - - $this->bag->initialize($array); - $this->assertEquals([ - 'notice' => 'Foo', - 'error' => 'Bar', - ], $this->bag->peekAll() - ); - - $this->assertEquals([ - 'notice' => 'Foo', - 'error' => 'Bar', - ], $this->bag->peekAll() - ); - } - - public function testGet() - { - $this->assertEquals([], $this->bag->get('non_existing')); - $this->assertEquals(['default'], $this->bag->get('non_existing', ['default'])); - $this->assertEquals(['A previous flash message'], $this->bag->get('notice')); - $this->assertEquals([], $this->bag->get('notice')); - } - - public function testSetAll() - { - $this->bag->setAll(['a' => 'first', 'b' => 'second']); - $this->assertFalse($this->bag->has('a')); - $this->assertFalse($this->bag->has('b')); - } - - public function testAll() - { - $this->bag->set('notice', 'Foo'); - $this->bag->set('error', 'Bar'); - $this->assertEquals([ - 'notice' => ['A previous flash message'], - ], $this->bag->all() - ); - - $this->assertEquals([], $this->bag->all()); - } - - public function testClear() - { - $this->assertEquals(['notice' => ['A previous flash message']], $this->bag->clear()); - } - - public function testDoNotRemoveTheNewFlashesWhenDisplayingTheExistingOnes() - { - $this->bag->add('success', 'Something'); - $this->bag->all(); - - $this->assertEquals(['new' => ['success' => ['Something']], 'display' => []], $this->array); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Flash/FlashBagTest.php b/vendor/symfony/http-foundation/Tests/Session/Flash/FlashBagTest.php deleted file mode 100644 index 6d8619e0..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Flash/FlashBagTest.php +++ /dev/null @@ -1,157 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Flash; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; - -/** - * FlashBagTest. - * - * @author Drak - */ -class FlashBagTest extends TestCase -{ - /** - * @var \Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface - */ - private $bag; - - protected $array = []; - - protected function setUp() - { - parent::setUp(); - $this->bag = new FlashBag(); - $this->array = ['notice' => ['A previous flash message']]; - $this->bag->initialize($this->array); - } - - protected function tearDown() - { - $this->bag = null; - parent::tearDown(); - } - - public function testInitialize() - { - $bag = new FlashBag(); - $bag->initialize($this->array); - $this->assertEquals($this->array, $bag->peekAll()); - $array = ['should' => ['change']]; - $bag->initialize($array); - $this->assertEquals($array, $bag->peekAll()); - } - - public function testGetStorageKey() - { - $this->assertEquals('_symfony_flashes', $this->bag->getStorageKey()); - $attributeBag = new FlashBag('test'); - $this->assertEquals('test', $attributeBag->getStorageKey()); - } - - public function testGetSetName() - { - $this->assertEquals('flashes', $this->bag->getName()); - $this->bag->setName('foo'); - $this->assertEquals('foo', $this->bag->getName()); - } - - public function testPeek() - { - $this->assertEquals([], $this->bag->peek('non_existing')); - $this->assertEquals(['default'], $this->bag->peek('not_existing', ['default'])); - $this->assertEquals(['A previous flash message'], $this->bag->peek('notice')); - $this->assertEquals(['A previous flash message'], $this->bag->peek('notice')); - } - - public function testAdd() - { - $tab = ['bar' => 'baz']; - $this->bag->add('string_message', 'lorem'); - $this->bag->add('object_message', new \stdClass()); - $this->bag->add('array_message', $tab); - - $this->assertEquals(['lorem'], $this->bag->get('string_message')); - $this->assertEquals([new \stdClass()], $this->bag->get('object_message')); - $this->assertEquals([$tab], $this->bag->get('array_message')); - } - - public function testGet() - { - $this->assertEquals([], $this->bag->get('non_existing')); - $this->assertEquals(['default'], $this->bag->get('not_existing', ['default'])); - $this->assertEquals(['A previous flash message'], $this->bag->get('notice')); - $this->assertEquals([], $this->bag->get('notice')); - } - - public function testAll() - { - $this->bag->set('notice', 'Foo'); - $this->bag->set('error', 'Bar'); - $this->assertEquals([ - 'notice' => ['Foo'], - 'error' => ['Bar'], ], $this->bag->all() - ); - - $this->assertEquals([], $this->bag->all()); - } - - public function testSet() - { - $this->bag->set('notice', 'Foo'); - $this->bag->set('notice', 'Bar'); - $this->assertEquals(['Bar'], $this->bag->peek('notice')); - } - - public function testHas() - { - $this->assertFalse($this->bag->has('nothing')); - $this->assertTrue($this->bag->has('notice')); - } - - public function testKeys() - { - $this->assertEquals(['notice'], $this->bag->keys()); - } - - public function testSetAll() - { - $this->bag->add('one_flash', 'Foo'); - $this->bag->add('another_flash', 'Bar'); - $this->assertTrue($this->bag->has('one_flash')); - $this->assertTrue($this->bag->has('another_flash')); - $this->bag->setAll(['unique_flash' => 'FooBar']); - $this->assertFalse($this->bag->has('one_flash')); - $this->assertFalse($this->bag->has('another_flash')); - $this->assertSame(['unique_flash' => 'FooBar'], $this->bag->all()); - $this->assertSame([], $this->bag->all()); - } - - public function testPeekAll() - { - $this->bag->set('notice', 'Foo'); - $this->bag->set('error', 'Bar'); - $this->assertEquals([ - 'notice' => ['Foo'], - 'error' => ['Bar'], - ], $this->bag->peekAll() - ); - $this->assertTrue($this->bag->has('notice')); - $this->assertTrue($this->bag->has('error')); - $this->assertEquals([ - 'notice' => ['Foo'], - 'error' => ['Bar'], - ], $this->bag->peekAll() - ); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/SessionTest.php b/vendor/symfony/http-foundation/Tests/Session/SessionTest.php deleted file mode 100644 index acb12998..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/SessionTest.php +++ /dev/null @@ -1,288 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; -use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\HttpFoundation\Session\SessionBagProxy; -use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; - -/** - * SessionTest. - * - * @author Fabien Potencier - * @author Robert Schönthal - * @author Drak - */ -class SessionTest extends TestCase -{ - /** - * @var \Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface - */ - protected $storage; - - /** - * @var \Symfony\Component\HttpFoundation\Session\SessionInterface - */ - protected $session; - - protected function setUp() - { - $this->storage = new MockArraySessionStorage(); - $this->session = new Session($this->storage, new AttributeBag(), new FlashBag()); - } - - protected function tearDown() - { - $this->storage = null; - $this->session = null; - } - - public function testStart() - { - $this->assertEquals('', $this->session->getId()); - $this->assertTrue($this->session->start()); - $this->assertNotEquals('', $this->session->getId()); - } - - public function testIsStarted() - { - $this->assertFalse($this->session->isStarted()); - $this->session->start(); - $this->assertTrue($this->session->isStarted()); - } - - public function testSetId() - { - $this->assertEquals('', $this->session->getId()); - $this->session->setId('0123456789abcdef'); - $this->session->start(); - $this->assertEquals('0123456789abcdef', $this->session->getId()); - } - - public function testSetIdAfterStart() - { - $this->session->start(); - $id = $this->session->getId(); - - $e = null; - try { - $this->session->setId($id); - } catch (\Exception $e) { - } - - $this->assertNull($e); - - try { - $this->session->setId('different'); - } catch (\Exception $e) { - } - - $this->assertInstanceOf('\LogicException', $e); - } - - public function testSetName() - { - $this->assertEquals('MOCKSESSID', $this->session->getName()); - $this->session->setName('session.test.com'); - $this->session->start(); - $this->assertEquals('session.test.com', $this->session->getName()); - } - - public function testGet() - { - // tests defaults - $this->assertNull($this->session->get('foo')); - $this->assertEquals(1, $this->session->get('foo', 1)); - } - - /** - * @dataProvider setProvider - */ - public function testSet($key, $value) - { - $this->session->set($key, $value); - $this->assertEquals($value, $this->session->get($key)); - } - - /** - * @dataProvider setProvider - */ - public function testHas($key, $value) - { - $this->session->set($key, $value); - $this->assertTrue($this->session->has($key)); - $this->assertFalse($this->session->has($key.'non_value')); - } - - public function testReplace() - { - $this->session->replace(['happiness' => 'be good', 'symfony' => 'awesome']); - $this->assertEquals(['happiness' => 'be good', 'symfony' => 'awesome'], $this->session->all()); - $this->session->replace([]); - $this->assertEquals([], $this->session->all()); - } - - /** - * @dataProvider setProvider - */ - public function testAll($key, $value, $result) - { - $this->session->set($key, $value); - $this->assertEquals($result, $this->session->all()); - } - - /** - * @dataProvider setProvider - */ - public function testClear($key, $value) - { - $this->session->set('hi', 'fabien'); - $this->session->set($key, $value); - $this->session->clear(); - $this->assertEquals([], $this->session->all()); - } - - public function setProvider() - { - return [ - ['foo', 'bar', ['foo' => 'bar']], - ['foo.bar', 'too much beer', ['foo.bar' => 'too much beer']], - ['great', 'symfony is great', ['great' => 'symfony is great']], - ]; - } - - /** - * @dataProvider setProvider - */ - public function testRemove($key, $value) - { - $this->session->set('hi.world', 'have a nice day'); - $this->session->set($key, $value); - $this->session->remove($key); - $this->assertEquals(['hi.world' => 'have a nice day'], $this->session->all()); - } - - public function testInvalidate() - { - $this->session->set('invalidate', 123); - $this->session->invalidate(); - $this->assertEquals([], $this->session->all()); - } - - public function testMigrate() - { - $this->session->set('migrate', 321); - $this->session->migrate(); - $this->assertEquals(321, $this->session->get('migrate')); - } - - public function testMigrateDestroy() - { - $this->session->set('migrate', 333); - $this->session->migrate(true); - $this->assertEquals(333, $this->session->get('migrate')); - } - - public function testSave() - { - $this->session->start(); - $this->session->save(); - - $this->assertFalse($this->session->isStarted()); - } - - public function testGetId() - { - $this->assertEquals('', $this->session->getId()); - $this->session->start(); - $this->assertNotEquals('', $this->session->getId()); - } - - public function testGetFlashBag() - { - $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\Session\\Flash\\FlashBagInterface', $this->session->getFlashBag()); - } - - public function testGetIterator() - { - $attributes = ['hello' => 'world', 'symfony' => 'rocks']; - foreach ($attributes as $key => $val) { - $this->session->set($key, $val); - } - - $i = 0; - foreach ($this->session as $key => $val) { - $this->assertEquals($attributes[$key], $val); - ++$i; - } - - $this->assertEquals(\count($attributes), $i); - } - - public function testGetCount() - { - $this->session->set('hello', 'world'); - $this->session->set('symfony', 'rocks'); - - $this->assertCount(2, $this->session); - } - - public function testGetMeta() - { - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\MetadataBag', $this->session->getMetadataBag()); - } - - public function testIsEmpty() - { - $this->assertTrue($this->session->isEmpty()); - - $this->session->set('hello', 'world'); - $this->assertFalse($this->session->isEmpty()); - - $this->session->remove('hello'); - $this->assertTrue($this->session->isEmpty()); - - $flash = $this->session->getFlashBag(); - $flash->set('hello', 'world'); - $this->assertFalse($this->session->isEmpty()); - - $flash->get('hello'); - $this->assertTrue($this->session->isEmpty()); - } - - public function testGetBagWithBagImplementingGetBag() - { - $bag = new AttributeBag(); - $bag->setName('foo'); - - $storage = new MockArraySessionStorage(); - $storage->registerBag($bag); - - $this->assertSame($bag, (new Session($storage))->getBag('foo')); - } - - public function testGetBagWithBagNotImplementingGetBag() - { - $data = []; - - $bag = new AttributeBag(); - $bag->setName('foo'); - - $storage = new MockArraySessionStorage(); - $storage->registerBag(new SessionBagProxy($bag, $data, $usageIndex)); - - $this->assertSame($bag, (new Session($storage))->getBag('foo')); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php deleted file mode 100644 index b4db12ba..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; - -/** - * @requires PHP 7.0 - */ -class AbstractSessionHandlerTest extends TestCase -{ - private static $server; - - public static function setUpBeforeClass() - { - $spec = [ - 1 => ['file', '/dev/null', 'w'], - 2 => ['file', '/dev/null', 'w'], - ]; - if (!self::$server = @proc_open('exec php -S localhost:8053', $spec, $pipes, __DIR__.'/Fixtures')) { - self::markTestSkipped('PHP server unable to start.'); - } - sleep(1); - } - - public static function tearDownAfterClass() - { - if (self::$server) { - proc_terminate(self::$server); - proc_close(self::$server); - } - } - - /** - * @dataProvider provideSession - */ - public function testSession($fixture) - { - $context = ['http' => ['header' => "Cookie: sid=123abc\r\n"]]; - $context = stream_context_create($context); - $result = file_get_contents(sprintf('http://localhost:8053/%s.php', $fixture), false, $context); - - $this->assertStringEqualsFile(__DIR__.sprintf('/Fixtures/%s.expected', $fixture), $result); - } - - public function provideSession() - { - foreach (glob(__DIR__.'/Fixtures/*.php') as $file) { - yield [pathinfo($file, \PATHINFO_FILENAME)]; - } - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/common.inc b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/common.inc deleted file mode 100644 index 7a064c7f..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/common.inc +++ /dev/null @@ -1,151 +0,0 @@ -data = $data; - } - - public function open($path, $name) - { - echo __FUNCTION__, "\n"; - - return parent::open($path, $name); - } - - public function validateId($sessionId) - { - echo __FUNCTION__, "\n"; - - return parent::validateId($sessionId); - } - - /** - * {@inheritdoc} - */ - public function read($sessionId) - { - echo __FUNCTION__, "\n"; - - return parent::read($sessionId); - } - - /** - * {@inheritdoc} - */ - public function updateTimestamp($sessionId, $data) - { - echo __FUNCTION__, "\n"; - - return true; - } - - /** - * {@inheritdoc} - */ - public function write($sessionId, $data) - { - echo __FUNCTION__, "\n"; - - return parent::write($sessionId, $data); - } - - /** - * {@inheritdoc} - */ - public function destroy($sessionId) - { - echo __FUNCTION__, "\n"; - - return parent::destroy($sessionId); - } - - public function close() - { - echo __FUNCTION__, "\n"; - - return true; - } - - public function gc($maxLifetime) - { - echo __FUNCTION__, "\n"; - - return true; - } - - protected function doRead($sessionId) - { - echo __FUNCTION__.': ', $this->data, "\n"; - - return $this->data; - } - - protected function doWrite($sessionId, $data) - { - echo __FUNCTION__.': ', $data, "\n"; - - return true; - } - - protected function doDestroy($sessionId) - { - echo __FUNCTION__, "\n"; - - return true; - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/empty_destroys.expected b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/empty_destroys.expected deleted file mode 100644 index 82037147..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/empty_destroys.expected +++ /dev/null @@ -1,17 +0,0 @@ -open -validateId -read -doRead: abc|i:123; -read - -write -destroy -doDestroy -close -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=10800, private, must-revalidate - [2] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/empty_destroys.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/empty_destroys.php deleted file mode 100644 index 3cfc1250..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/empty_destroys.php +++ /dev/null @@ -1,8 +0,0 @@ - Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=10800, private, must-revalidate -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/read_only.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/read_only.php deleted file mode 100644 index 3e62fb9e..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/read_only.php +++ /dev/null @@ -1,8 +0,0 @@ - Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=10800, private, must-revalidate - [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/regenerate.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/regenerate.php deleted file mode 100644 index a0f635c8..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/regenerate.php +++ /dev/null @@ -1,10 +0,0 @@ - bar -) -$_SESSION is not empty -write -destroy -close -$_SESSION is empty -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=0, private, must-revalidate - [2] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/storage.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/storage.php deleted file mode 100644 index 96dca3c2..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/storage.php +++ /dev/null @@ -1,24 +0,0 @@ -setSaveHandler(new TestSessionHandler()); -$flash = new FlashBag(); -$storage->registerBag($flash); -$storage->start(); - -$flash->add('foo', 'bar'); - -print_r($flash->get('foo')); -echo empty($_SESSION) ? '$_SESSION is empty' : '$_SESSION is not empty'; -echo "\n"; - -$storage->save(); - -echo empty($_SESSION) ? '$_SESSION is empty' : '$_SESSION is not empty'; - -ob_start(function ($buffer) { return str_replace(session_id(), 'random_session_id', $buffer); }); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.expected b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.expected deleted file mode 100644 index 33da0a5b..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.expected +++ /dev/null @@ -1,15 +0,0 @@ -open -validateId -read -doRead: abc|i:123; -read - -updateTimestamp -close -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=10800, private, must-revalidate - [2] => Set-Cookie: abc=def -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.php deleted file mode 100644 index ffb5b20a..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie.php +++ /dev/null @@ -1,8 +0,0 @@ - Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=10800, private, must-revalidate - [2] => Set-Cookie: abc=def - [3] => Set-Cookie: sid=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; Max-Age=0; path=/; secure; HttpOnly -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.php deleted file mode 100644 index ec511932..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_cookie_and_session.php +++ /dev/null @@ -1,13 +0,0 @@ - Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=0, private, must-revalidate - [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php deleted file mode 100644 index fc2c4182..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php +++ /dev/null @@ -1,13 +0,0 @@ - 'lax']); -$storage->setSaveHandler(new TestSessionHandler()); -$storage->start(); - -$_SESSION = ['foo' => 'bar']; - -ob_start(function ($buffer) { return str_replace(session_id(), 'random_session_id', $buffer); }); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected deleted file mode 100644 index 8b5fc08b..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected +++ /dev/null @@ -1,23 +0,0 @@ -open -validateId -read -doRead: -read -destroy -close -open -validateId -read -doRead: -read - -write -doWrite: foo|s:3:"bar"; -close -Array -( - [0] => Content-Type: text/plain; charset=utf-8 - [1] => Cache-Control: max-age=0, private, must-revalidate - [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax -) -shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php deleted file mode 100644 index a28b6fed..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php +++ /dev/null @@ -1,15 +0,0 @@ - 'lax']); -$storage->setSaveHandler(new TestSessionHandler()); -$storage->start(); - -$_SESSION = ['foo' => 'bar']; - -$storage->regenerate(true); - -ob_start(function ($buffer) { return preg_replace('~_sf2_meta.*$~m', '', str_replace(session_id(), 'random_session_id', $buffer)); }); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php deleted file mode 100644 index d7a324fc..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php +++ /dev/null @@ -1,135 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler; - -/** - * @requires extension memcache - * @group time-sensitive - * @group legacy - */ -class MemcacheSessionHandlerTest extends TestCase -{ - const PREFIX = 'prefix_'; - const TTL = 1000; - - /** - * @var MemcacheSessionHandler - */ - protected $storage; - - protected $memcache; - - protected function setUp() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the Memcache class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - - parent::setUp(); - $this->memcache = $this->getMockBuilder('Memcache')->getMock(); - $this->storage = new MemcacheSessionHandler( - $this->memcache, - ['prefix' => self::PREFIX, 'expiretime' => self::TTL] - ); - } - - protected function tearDown() - { - $this->memcache = null; - $this->storage = null; - parent::tearDown(); - } - - public function testOpenSession() - { - $this->assertTrue($this->storage->open('', '')); - } - - public function testCloseSession() - { - $this->assertTrue($this->storage->close()); - } - - public function testReadSession() - { - $this->memcache - ->expects($this->once()) - ->method('get') - ->with(self::PREFIX.'id') - ; - - $this->assertEquals('', $this->storage->read('id')); - } - - public function testWriteSession() - { - $this->memcache - ->expects($this->once()) - ->method('set') - ->with(self::PREFIX.'id', 'data', 0, $this->equalTo(time() + self::TTL, 2)) - ->willReturn(true) - ; - - $this->assertTrue($this->storage->write('id', 'data')); - } - - public function testDestroySession() - { - $this->memcache - ->expects($this->once()) - ->method('delete') - ->with(self::PREFIX.'id') - ->willReturn(true) - ; - - $this->assertTrue($this->storage->destroy('id')); - } - - public function testGcSession() - { - $this->assertTrue($this->storage->gc(123)); - } - - /** - * @dataProvider getOptionFixtures - */ - public function testSupportedOptions($options, $supported) - { - try { - new MemcacheSessionHandler($this->memcache, $options); - $this->assertTrue($supported); - } catch (\InvalidArgumentException $e) { - $this->assertFalse($supported); - } - } - - public function getOptionFixtures() - { - return [ - [['prefix' => 'session'], true], - [['expiretime' => 100], true], - [['prefix' => 'session', 'expiretime' => 200], true], - [['expiretime' => 100, 'foo' => 'bar'], false], - ]; - } - - public function testGetConnection() - { - $method = new \ReflectionMethod($this->storage, 'getMemcache'); - $method->setAccessible(true); - - $this->assertInstanceOf('\Memcache', $method->invoke($this->storage)); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php deleted file mode 100644 index c3deb7ae..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php +++ /dev/null @@ -1,145 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler; - -/** - * @requires extension memcached - * @group time-sensitive - */ -class MemcachedSessionHandlerTest extends TestCase -{ - const PREFIX = 'prefix_'; - const TTL = 1000; - - /** - * @var MemcachedSessionHandler - */ - protected $storage; - - protected $memcached; - - protected function setUp() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the Memcached class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - - parent::setUp(); - - if (version_compare(phpversion('memcached'), '2.2.0', '>=') && version_compare(phpversion('memcached'), '3.0.0b1', '<')) { - $this->markTestSkipped('Tests can only be run with memcached extension 2.1.0 or lower, or 3.0.0b1 or higher'); - } - - $this->memcached = $this->getMockBuilder('Memcached')->getMock(); - $this->storage = new MemcachedSessionHandler( - $this->memcached, - ['prefix' => self::PREFIX, 'expiretime' => self::TTL] - ); - } - - protected function tearDown() - { - $this->memcached = null; - $this->storage = null; - parent::tearDown(); - } - - public function testOpenSession() - { - $this->assertTrue($this->storage->open('', '')); - } - - public function testCloseSession() - { - $this->memcached - ->expects($this->once()) - ->method('quit') - ->willReturn(true) - ; - - $this->assertTrue($this->storage->close()); - } - - public function testReadSession() - { - $this->memcached - ->expects($this->once()) - ->method('get') - ->with(self::PREFIX.'id') - ; - - $this->assertEquals('', $this->storage->read('id')); - } - - public function testWriteSession() - { - $this->memcached - ->expects($this->once()) - ->method('set') - ->with(self::PREFIX.'id', 'data', $this->equalTo(time() + self::TTL, 2)) - ->willReturn(true) - ; - - $this->assertTrue($this->storage->write('id', 'data')); - } - - public function testDestroySession() - { - $this->memcached - ->expects($this->once()) - ->method('delete') - ->with(self::PREFIX.'id') - ->willReturn(true) - ; - - $this->assertTrue($this->storage->destroy('id')); - } - - public function testGcSession() - { - $this->assertTrue($this->storage->gc(123)); - } - - /** - * @dataProvider getOptionFixtures - */ - public function testSupportedOptions($options, $supported) - { - try { - new MemcachedSessionHandler($this->memcached, $options); - $this->assertTrue($supported); - } catch (\InvalidArgumentException $e) { - $this->assertFalse($supported); - } - } - - public function getOptionFixtures() - { - return [ - [['prefix' => 'session'], true], - [['expiretime' => 100], true], - [['prefix' => 'session', 'expiretime' => 200], true], - [['expiretime' => 100, 'foo' => 'bar'], false], - ]; - } - - public function testGetConnection() - { - $method = new \ReflectionMethod($this->storage, 'getMemcached'); - $method->setAccessible(true); - - $this->assertInstanceOf('\Memcached', $method->invoke($this->storage)); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php deleted file mode 100644 index cbfda8e7..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php +++ /dev/null @@ -1,330 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandler; - -/** - * @author Markus Bachmann - * @group time-sensitive - * @group legacy - */ -class MongoDbSessionHandlerTest extends TestCase -{ - /** - * @var MockObject - */ - private $mongo; - private $storage; - public $options; - - protected function setUp() - { - parent::setUp(); - - if (\extension_loaded('mongodb')) { - if (!class_exists('MongoDB\Client')) { - $this->markTestSkipped('The mongodb/mongodb package is required.'); - } - } elseif (!\extension_loaded('mongo')) { - $this->markTestSkipped('The Mongo or MongoDB extension is required.'); - } - - if (phpversion('mongodb')) { - $mongoClass = 'MongoDB\Client'; - } else { - $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; - } - - $this->mongo = $this->getMockBuilder($mongoClass) - ->disableOriginalConstructor() - ->getMock(); - - $this->options = [ - 'id_field' => '_id', - 'data_field' => 'data', - 'time_field' => 'time', - 'expiry_field' => 'expires_at', - 'database' => 'sf2-test', - 'collection' => 'session-test', - ]; - - $this->storage = new MongoDbSessionHandler($this->mongo, $this->options); - } - - public function testConstructorShouldThrowExceptionForInvalidMongo() - { - $this->expectException('InvalidArgumentException'); - new MongoDbSessionHandler(new \stdClass(), $this->options); - } - - public function testConstructorShouldThrowExceptionForMissingOptions() - { - $this->expectException('InvalidArgumentException'); - new MongoDbSessionHandler($this->mongo, []); - } - - public function testOpenMethodAlwaysReturnTrue() - { - $this->assertTrue($this->storage->open('test', 'test'), 'The "open" method should always return true'); - } - - public function testCloseMethodAlwaysReturnTrue() - { - $this->assertTrue($this->storage->close(), 'The "close" method should always return true'); - } - - public function testRead() - { - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->willReturn($collection); - - // defining the timeout before the actual method call - // allows to test for "greater than" values in the $criteria - $testTimeout = time() + 1; - - $collection->expects($this->once()) - ->method('findOne') - ->willReturnCallback(function ($criteria) use ($testTimeout) { - $this->assertArrayHasKey($this->options['id_field'], $criteria); - $this->assertEquals('foo', $criteria[$this->options['id_field']]); - - $this->assertArrayHasKey($this->options['expiry_field'], $criteria); - $this->assertArrayHasKey('$gte', $criteria[$this->options['expiry_field']]); - - if (phpversion('mongodb')) { - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$gte']); - $this->assertGreaterThanOrEqual(round((string) $criteria[$this->options['expiry_field']]['$gte'] / 1000), $testTimeout); - } else { - $this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$gte']); - $this->assertGreaterThanOrEqual($criteria[$this->options['expiry_field']]['$gte']->sec, $testTimeout); - } - - $fields = [ - $this->options['id_field'] => 'foo', - ]; - - if (phpversion('mongodb')) { - $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY); - $fields[$this->options['id_field']] = new \MongoDB\BSON\UTCDateTime(time() * 1000); - } else { - $fields[$this->options['data_field']] = new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY); - $fields[$this->options['id_field']] = new \MongoDate(); - } - - return $fields; - }); - - $this->assertEquals('bar', $this->storage->read('foo')); - } - - public function testWrite() - { - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->willReturn($collection); - - $data = []; - - $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; - - $collection->expects($this->once()) - ->method($methodName) - ->willReturnCallback(function ($criteria, $updateData, $options) use (&$data) { - $this->assertEquals([$this->options['id_field'] => 'foo'], $criteria); - - if (phpversion('mongodb')) { - $this->assertEquals(['upsert' => true], $options); - } else { - $this->assertEquals(['upsert' => true, 'multiple' => false], $options); - } - - $data = $updateData['$set']; - }); - - $expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime'); - $this->assertTrue($this->storage->write('foo', 'bar')); - - if (phpversion('mongodb')) { - $this->assertEquals('bar', $data[$this->options['data_field']]->getData()); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]); - $this->assertGreaterThanOrEqual($expectedExpiry, round((string) $data[$this->options['expiry_field']] / 1000)); - } else { - $this->assertEquals('bar', $data[$this->options['data_field']]->bin); - $this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]); - $this->assertGreaterThanOrEqual($expectedExpiry, $data[$this->options['expiry_field']]->sec); - } - } - - public function testWriteWhenUsingExpiresField() - { - $this->options = [ - 'id_field' => '_id', - 'data_field' => 'data', - 'time_field' => 'time', - 'database' => 'sf2-test', - 'collection' => 'session-test', - 'expiry_field' => 'expiresAt', - ]; - - $this->storage = new MongoDbSessionHandler($this->mongo, $this->options); - - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->willReturn($collection); - - $data = []; - - $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; - - $collection->expects($this->once()) - ->method($methodName) - ->willReturnCallback(function ($criteria, $updateData, $options) use (&$data) { - $this->assertEquals([$this->options['id_field'] => 'foo'], $criteria); - - if (phpversion('mongodb')) { - $this->assertEquals(['upsert' => true], $options); - } else { - $this->assertEquals(['upsert' => true, 'multiple' => false], $options); - } - - $data = $updateData['$set']; - }); - - $this->assertTrue($this->storage->write('foo', 'bar')); - - if (phpversion('mongodb')) { - $this->assertEquals('bar', $data[$this->options['data_field']]->getData()); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]); - } else { - $this->assertEquals('bar', $data[$this->options['data_field']]->bin); - $this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]); - } - } - - public function testReplaceSessionData() - { - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->willReturn($collection); - - $data = []; - - $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; - - $collection->expects($this->exactly(2)) - ->method($methodName) - ->willReturnCallback(function ($criteria, $updateData, $options) use (&$data) { - $data = $updateData; - }); - - $this->storage->write('foo', 'bar'); - $this->storage->write('foo', 'foobar'); - - if (phpversion('mongodb')) { - $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData()); - } else { - $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin); - } - } - - public function testDestroy() - { - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->willReturn($collection); - - $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove'; - - $collection->expects($this->once()) - ->method($methodName) - ->with([$this->options['id_field'] => 'foo']); - - $this->assertTrue($this->storage->destroy('foo')); - } - - public function testGc() - { - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->willReturn($collection); - - $methodName = phpversion('mongodb') ? 'deleteMany' : 'remove'; - - $collection->expects($this->once()) - ->method($methodName) - ->willReturnCallback(function ($criteria) { - if (phpversion('mongodb')) { - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$lt']); - $this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000)); - } else { - $this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$lt']); - $this->assertGreaterThanOrEqual(time() - 1, $criteria[$this->options['expiry_field']]['$lt']->sec); - } - }); - - $this->assertTrue($this->storage->gc(1)); - } - - public function testGetConnection() - { - $method = new \ReflectionMethod($this->storage, 'getMongo'); - $method->setAccessible(true); - - if (phpversion('mongodb')) { - $mongoClass = 'MongoDB\Client'; - } else { - $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; - } - - $this->assertInstanceOf($mongoClass, $method->invoke($this->storage)); - } - - private function createMongoCollectionMock() - { - $collectionClass = 'MongoCollection'; - if (phpversion('mongodb')) { - $collectionClass = 'MongoDB\Collection'; - } - - $collection = $this->getMockBuilder($collectionClass) - ->disableOriginalConstructor() - ->getMock(); - - return $collection; - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php deleted file mode 100644 index 7de55798..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; - -/** - * Test class for NativeFileSessionHandler. - * - * @author Drak - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - */ -class NativeFileSessionHandlerTest extends TestCase -{ - public function testConstruct() - { - $storage = new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler(sys_get_temp_dir())); - - $this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName()); - $this->assertEquals('user', ini_get('session.save_handler')); - - $this->assertEquals(sys_get_temp_dir(), ini_get('session.save_path')); - $this->assertEquals('TESTING', ini_get('session.name')); - } - - /** - * @dataProvider savePathDataProvider - */ - public function testConstructSavePath($savePath, $expectedSavePath, $path) - { - new NativeFileSessionHandler($savePath); - $this->assertEquals($expectedSavePath, ini_get('session.save_path')); - $this->assertDirectoryExists(realpath($path)); - - rmdir($path); - } - - public function savePathDataProvider() - { - $base = sys_get_temp_dir(); - - return [ - ["$base/foo", "$base/foo", "$base/foo"], - ["5;$base/foo", "5;$base/foo", "$base/foo"], - ["5;0600;$base/foo", "5;0600;$base/foo", "$base/foo"], - ]; - } - - public function testConstructException() - { - $this->expectException('InvalidArgumentException'); - new NativeFileSessionHandler('something;invalid;with;too-many-args'); - } - - public function testConstructDefault() - { - $path = ini_get('session.save_path'); - new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler()); - - $this->assertEquals($path, ini_get('session.save_path')); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php deleted file mode 100644 index 4a9fb600..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler; - -/** - * Test class for NativeSessionHandler. - * - * @author Drak - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @group legacy - */ -class NativeSessionHandlerTest extends TestCase -{ - /** - * @expectedDeprecation The Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead. - */ - public function testConstruct() - { - $handler = new NativeSessionHandler(); - - $this->assertInstanceOf('SessionHandler', $handler); - $this->assertTrue($handler instanceof NativeSessionHandler); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php deleted file mode 100644 index f793db14..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php +++ /dev/null @@ -1,59 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Session; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; - -/** - * Test class for NullSessionHandler. - * - * @author Drak - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - */ -class NullSessionHandlerTest extends TestCase -{ - public function testSaveHandlers() - { - $this->getStorage(); - $this->assertEquals('user', ini_get('session.save_handler')); - } - - public function testSession() - { - session_id('nullsessionstorage'); - $storage = $this->getStorage(); - $session = new Session($storage); - $this->assertNull($session->get('something')); - $session->set('something', 'unique'); - $this->assertEquals('unique', $session->get('something')); - } - - public function testNothingIsPersisted() - { - session_id('nullsessionstorage'); - $storage = $this->getStorage(); - $session = new Session($storage); - $session->start(); - $this->assertEquals('nullsessionstorage', $session->getId()); - $this->assertNull($session->get('something')); - } - - public function getStorage() - { - return new NativeSessionStorage([], new NullSessionHandler()); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php deleted file mode 100644 index 9cbe654d..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ /dev/null @@ -1,405 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler; - -/** - * @requires extension pdo_sqlite - * @group time-sensitive - */ -class PdoSessionHandlerTest extends TestCase -{ - private $dbFile; - - protected function tearDown() - { - // make sure the temporary database file is deleted when it has been created (even when a test fails) - if ($this->dbFile) { - @unlink($this->dbFile); - } - parent::tearDown(); - } - - protected function getPersistentSqliteDsn() - { - $this->dbFile = tempnam(sys_get_temp_dir(), 'sf2_sqlite_sessions'); - - return 'sqlite:'.$this->dbFile; - } - - protected function getMemorySqlitePdo() - { - $pdo = new \PDO('sqlite::memory:'); - $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); - $storage = new PdoSessionHandler($pdo); - $storage->createTable(); - - return $pdo; - } - - public function testWrongPdoErrMode() - { - $this->expectException('InvalidArgumentException'); - $pdo = $this->getMemorySqlitePdo(); - $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT); - - new PdoSessionHandler($pdo); - } - - public function testInexistentTable() - { - $this->expectException('RuntimeException'); - $storage = new PdoSessionHandler($this->getMemorySqlitePdo(), ['db_table' => 'inexistent_table']); - $storage->open('', 'sid'); - $storage->read('id'); - $storage->write('id', 'data'); - $storage->close(); - } - - public function testCreateTableTwice() - { - $this->expectException('RuntimeException'); - $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); - $storage->createTable(); - } - - public function testWithLazyDsnConnection() - { - $dsn = $this->getPersistentSqliteDsn(); - - $storage = new PdoSessionHandler($dsn); - $storage->createTable(); - $storage->open('', 'sid'); - $data = $storage->read('id'); - $storage->write('id', 'data'); - $storage->close(); - $this->assertSame('', $data, 'New session returns empty string data'); - - $storage->open('', 'sid'); - $data = $storage->read('id'); - $storage->close(); - $this->assertSame('data', $data, 'Written value can be read back correctly'); - } - - public function testWithLazySavePathConnection() - { - $dsn = $this->getPersistentSqliteDsn(); - - // Open is called with what ini_set('session.save_path', $dsn) would mean - $storage = new PdoSessionHandler(null); - $storage->open($dsn, 'sid'); - $storage->createTable(); - $data = $storage->read('id'); - $storage->write('id', 'data'); - $storage->close(); - $this->assertSame('', $data, 'New session returns empty string data'); - - $storage->open($dsn, 'sid'); - $data = $storage->read('id'); - $storage->close(); - $this->assertSame('data', $data, 'Written value can be read back correctly'); - } - - public function testReadWriteReadWithNullByte() - { - $sessionData = 'da'."\0".'ta'; - - $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); - $storage->open('', 'sid'); - $readData = $storage->read('id'); - $storage->write('id', $sessionData); - $storage->close(); - $this->assertSame('', $readData, 'New session returns empty string data'); - - $storage->open('', 'sid'); - $readData = $storage->read('id'); - $storage->close(); - $this->assertSame($sessionData, $readData, 'Written value can be read back correctly'); - } - - public function testReadConvertsStreamToString() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - - $pdo = new MockPdo('pgsql'); - $pdo->prepareResult = $this->getMockBuilder('PDOStatement')->getMock(); - - $content = 'foobar'; - $stream = $this->createStream($content); - - $pdo->prepareResult->expects($this->once())->method('fetchAll') - ->willReturn([[$stream, 42, time()]]); - - $storage = new PdoSessionHandler($pdo); - $result = $storage->read('foo'); - - $this->assertSame($content, $result); - } - - public function testReadLockedConvertsStreamToString() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - if (filter_var(ini_get('session.use_strict_mode'), \FILTER_VALIDATE_BOOLEAN)) { - $this->markTestSkipped('Strict mode needs no locking for new sessions.'); - } - - $pdo = new MockPdo('pgsql'); - $selectStmt = $this->getMockBuilder('PDOStatement')->getMock(); - $insertStmt = $this->getMockBuilder('PDOStatement')->getMock(); - - $pdo->prepareResult = function ($statement) use ($selectStmt, $insertStmt) { - return 0 === strpos($statement, 'INSERT') ? $insertStmt : $selectStmt; - }; - - $content = 'foobar'; - $stream = $this->createStream($content); - $exception = null; - - $selectStmt->expects($this->atLeast(2))->method('fetchAll') - ->willReturnCallback(function () use (&$exception, $stream) { - return $exception ? [[$stream, 42, time()]] : []; - }); - - $insertStmt->expects($this->once())->method('execute') - ->willReturnCallback(function () use (&$exception) { - throw $exception = new \PDOException('', '23'); - }); - - $storage = new PdoSessionHandler($pdo); - $result = $storage->read('foo'); - - $this->assertSame($content, $result); - } - - public function testReadingRequiresExactlySameId() - { - $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); - $storage->open('', 'sid'); - $storage->write('id', 'data'); - $storage->write('test', 'data'); - $storage->write('space ', 'data'); - $storage->close(); - - $storage->open('', 'sid'); - $readDataCaseSensitive = $storage->read('ID'); - $readDataNoCharFolding = $storage->read('tést'); - $readDataKeepSpace = $storage->read('space '); - $readDataExtraSpace = $storage->read('space '); - $storage->close(); - - $this->assertSame('', $readDataCaseSensitive, 'Retrieval by ID should be case-sensitive (collation setting)'); - $this->assertSame('', $readDataNoCharFolding, 'Retrieval by ID should not do character folding (collation setting)'); - $this->assertSame('data', $readDataKeepSpace, 'Retrieval by ID requires spaces as-is'); - $this->assertSame('', $readDataExtraSpace, 'Retrieval by ID requires spaces as-is'); - } - - /** - * Simulates session_regenerate_id(true) which will require an INSERT or UPDATE (replace). - */ - public function testWriteDifferentSessionIdThanRead() - { - $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); - $storage->open('', 'sid'); - $storage->read('id'); - $storage->destroy('id'); - $storage->write('new_id', 'data_of_new_session_id'); - $storage->close(); - - $storage->open('', 'sid'); - $data = $storage->read('new_id'); - $storage->close(); - - $this->assertSame('data_of_new_session_id', $data, 'Data of regenerated session id is available'); - } - - public function testWrongUsageStillWorks() - { - // wrong method sequence that should no happen, but still works - $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); - $storage->write('id', 'data'); - $storage->write('other_id', 'other_data'); - $storage->destroy('inexistent'); - $storage->open('', 'sid'); - $data = $storage->read('id'); - $otherData = $storage->read('other_id'); - $storage->close(); - - $this->assertSame('data', $data); - $this->assertSame('other_data', $otherData); - } - - public function testSessionDestroy() - { - $pdo = $this->getMemorySqlitePdo(); - $storage = new PdoSessionHandler($pdo); - - $storage->open('', 'sid'); - $storage->read('id'); - $storage->write('id', 'data'); - $storage->close(); - $this->assertEquals(1, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn()); - - $storage->open('', 'sid'); - $storage->read('id'); - $storage->destroy('id'); - $storage->close(); - $this->assertEquals(0, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn()); - - $storage->open('', 'sid'); - $data = $storage->read('id'); - $storage->close(); - $this->assertSame('', $data, 'Destroyed session returns empty string'); - } - - /** - * @runInSeparateProcess - */ - public function testSessionGC() - { - $previousLifeTime = ini_set('session.gc_maxlifetime', 1000); - $pdo = $this->getMemorySqlitePdo(); - $storage = new PdoSessionHandler($pdo); - - $storage->open('', 'sid'); - $storage->read('id'); - $storage->write('id', 'data'); - $storage->close(); - - $storage->open('', 'sid'); - $storage->read('gc_id'); - ini_set('session.gc_maxlifetime', -1); // test that you can set lifetime of a session after it has been read - $storage->write('gc_id', 'data'); - $storage->close(); - $this->assertEquals(2, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn(), 'No session pruned because gc not called'); - - $storage->open('', 'sid'); - $data = $storage->read('gc_id'); - $storage->gc(-1); - $storage->close(); - - ini_set('session.gc_maxlifetime', $previousLifeTime); - - $this->assertSame('', $data, 'Session already considered garbage, so not returning data even if it is not pruned yet'); - $this->assertEquals(1, $pdo->query('SELECT COUNT(*) FROM sessions')->fetchColumn(), 'Expired session is pruned'); - } - - public function testGetConnection() - { - $storage = new PdoSessionHandler($this->getMemorySqlitePdo()); - - $method = new \ReflectionMethod($storage, 'getConnection'); - $method->setAccessible(true); - - $this->assertInstanceOf('\PDO', $method->invoke($storage)); - } - - public function testGetConnectionConnectsIfNeeded() - { - $storage = new PdoSessionHandler('sqlite::memory:'); - - $method = new \ReflectionMethod($storage, 'getConnection'); - $method->setAccessible(true); - - $this->assertInstanceOf('\PDO', $method->invoke($storage)); - } - - /** - * @dataProvider provideUrlDsnPairs - */ - public function testUrlDsn($url, $expectedDsn, $expectedUser = null, $expectedPassword = null) - { - $storage = new PdoSessionHandler($url); - $reflection = new \ReflectionClass(PdoSessionHandler::class); - - foreach (['dsn' => $expectedDsn, 'username' => $expectedUser, 'password' => $expectedPassword] as $property => $expectedValue) { - if (!isset($expectedValue)) { - continue; - } - $property = $reflection->getProperty($property); - $property->setAccessible(true); - $this->assertSame($expectedValue, $property->getValue($storage)); - } - } - - public function provideUrlDsnPairs() - { - yield ['mysql://localhost/test', 'mysql:host=localhost;dbname=test;']; - yield ['mysql://localhost:56/test', 'mysql:host=localhost;port=56;dbname=test;']; - yield ['mysql2://root:pwd@localhost/test', 'mysql:host=localhost;dbname=test;', 'root', 'pwd']; - yield ['postgres://localhost/test', 'pgsql:host=localhost;dbname=test;']; - yield ['postgresql://localhost:5634/test', 'pgsql:host=localhost;port=5634;dbname=test;']; - yield ['postgres://root:pwd@localhost/test', 'pgsql:host=localhost;dbname=test;', 'root', 'pwd']; - yield 'sqlite relative path' => ['sqlite://localhost/tmp/test', 'sqlite:tmp/test']; - yield 'sqlite absolute path' => ['sqlite://localhost//tmp/test', 'sqlite:/tmp/test']; - yield 'sqlite relative path without host' => ['sqlite:///tmp/test', 'sqlite:tmp/test']; - yield 'sqlite absolute path without host' => ['sqlite3:////tmp/test', 'sqlite:/tmp/test']; - yield ['sqlite://localhost/:memory:', 'sqlite::memory:']; - yield ['mssql://localhost/test', 'sqlsrv:server=localhost;Database=test']; - yield ['mssql://localhost:56/test', 'sqlsrv:server=localhost,56;Database=test']; - } - - private function createStream($content) - { - $stream = tmpfile(); - fwrite($stream, $content); - fseek($stream, 0); - - return $stream; - } -} - -class MockPdo extends \PDO -{ - public $prepareResult; - private $driverName; - private $errorMode; - - public function __construct($driverName = null, $errorMode = null) - { - $this->driverName = $driverName; - $this->errorMode = null !== $errorMode ?: \PDO::ERRMODE_EXCEPTION; - } - - public function getAttribute($attribute) - { - if (\PDO::ATTR_ERRMODE === $attribute) { - return $this->errorMode; - } - - if (\PDO::ATTR_DRIVER_NAME === $attribute) { - return $this->driverName; - } - - return parent::getAttribute($attribute); - } - - public function prepare($statement, $driverOptions = []) - { - return \is_callable($this->prepareResult) - ? \call_user_func($this->prepareResult, $statement, $driverOptions) - : $this->prepareResult; - } - - public function beginTransaction() - { - } - - public function rollBack() - { - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/StrictSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/StrictSessionHandlerTest.php deleted file mode 100644 index 6a0d1687..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/StrictSessionHandlerTest.php +++ /dev/null @@ -1,189 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; - -class StrictSessionHandlerTest extends TestCase -{ - public function testOpen() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('open') - ->with('path', 'name')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertInstanceOf('SessionUpdateTimestampHandlerInterface', $proxy); - $this->assertInstanceOf(AbstractSessionHandler::class, $proxy); - $this->assertTrue($proxy->open('path', 'name')); - } - - public function testCloseSession() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('close') - ->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->close()); - } - - public function testValidateIdOK() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn('data'); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->validateId('id')); - } - - public function testValidateIdKO() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn(''); - $proxy = new StrictSessionHandler($handler); - - $this->assertFalse($proxy->validateId('id')); - } - - public function testRead() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn('data'); - $proxy = new StrictSessionHandler($handler); - - $this->assertSame('data', $proxy->read('id')); - } - - public function testReadWithValidateIdOK() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn('data'); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->validateId('id')); - $this->assertSame('data', $proxy->read('id')); - } - - public function testReadWithValidateIdMismatch() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->exactly(2))->method('read') - ->withConsecutive(['id1'], ['id2']) - ->will($this->onConsecutiveCalls('data1', 'data2')); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->validateId('id1')); - $this->assertSame('data2', $proxy->read('id2')); - } - - public function testUpdateTimestamp() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('write') - ->with('id', 'data')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->updateTimestamp('id', 'data')); - } - - public function testWrite() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('write') - ->with('id', 'data')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->write('id', 'data')); - } - - public function testWriteEmptyNewSession() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn(''); - $handler->expects($this->never())->method('write'); - $handler->expects($this->once())->method('destroy')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertFalse($proxy->validateId('id')); - $this->assertSame('', $proxy->read('id')); - $this->assertTrue($proxy->write('id', '')); - } - - public function testWriteEmptyExistingSession() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn('data'); - $handler->expects($this->never())->method('write'); - $handler->expects($this->once())->method('destroy')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertSame('data', $proxy->read('id')); - $this->assertTrue($proxy->write('id', '')); - } - - public function testDestroy() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('destroy') - ->with('id')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->destroy('id')); - } - - public function testDestroyNewSession() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn(''); - $handler->expects($this->once())->method('destroy')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertSame('', $proxy->read('id')); - $this->assertTrue($proxy->destroy('id')); - } - - public function testDestroyNonEmptyNewSession() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('read') - ->with('id')->willReturn(''); - $handler->expects($this->once())->method('write') - ->with('id', 'data')->willReturn(true); - $handler->expects($this->once())->method('destroy') - ->with('id')->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertSame('', $proxy->read('id')); - $this->assertTrue($proxy->write('id', 'data')); - $this->assertTrue($proxy->destroy('id')); - } - - public function testGc() - { - $handler = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $handler->expects($this->once())->method('gc') - ->with(123)->willReturn(true); - $proxy = new StrictSessionHandler($handler); - - $this->assertTrue($proxy->gc(123)); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php deleted file mode 100644 index b89454f8..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php +++ /dev/null @@ -1,97 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler; - -/** - * @author Adrien Brault - * - * @group legacy - */ -class WriteCheckSessionHandlerTest extends TestCase -{ - public function test() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('close') - ->with() - ->willReturn(true) - ; - - $this->assertTrue($writeCheckSessionHandler->close()); - } - - public function testWrite() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('write') - ->with('foo', 'bar') - ->willReturn(true) - ; - - $this->assertTrue($writeCheckSessionHandler->write('foo', 'bar')); - } - - public function testSkippedWrite() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('read') - ->with('foo') - ->willReturn('bar') - ; - - $wrappedSessionHandlerMock - ->expects($this->never()) - ->method('write') - ; - - $this->assertEquals('bar', $writeCheckSessionHandler->read('foo')); - $this->assertTrue($writeCheckSessionHandler->write('foo', 'bar')); - } - - public function testNonSkippedWrite() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('read') - ->with('foo') - ->willReturn('bar') - ; - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('write') - ->with('foo', 'baZZZ') - ->willReturn(true) - ; - - $this->assertEquals('bar', $writeCheckSessionHandler->read('foo')); - $this->assertTrue($writeCheckSessionHandler->write('foo', 'baZZZ')); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/MetadataBagTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/MetadataBagTest.php deleted file mode 100644 index 2c4758b9..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/MetadataBagTest.php +++ /dev/null @@ -1,139 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag; - -/** - * Test class for MetadataBag. - * - * @group time-sensitive - */ -class MetadataBagTest extends TestCase -{ - /** - * @var MetadataBag - */ - protected $bag; - - protected $array = []; - - protected function setUp() - { - parent::setUp(); - $this->bag = new MetadataBag(); - $this->array = [MetadataBag::CREATED => 1234567, MetadataBag::UPDATED => 12345678, MetadataBag::LIFETIME => 0]; - $this->bag->initialize($this->array); - } - - protected function tearDown() - { - $this->array = []; - $this->bag = null; - parent::tearDown(); - } - - public function testInitialize() - { - $sessionMetadata = []; - - $bag1 = new MetadataBag(); - $bag1->initialize($sessionMetadata); - $this->assertGreaterThanOrEqual(time(), $bag1->getCreated()); - $this->assertEquals($bag1->getCreated(), $bag1->getLastUsed()); - - sleep(1); - $bag2 = new MetadataBag(); - $bag2->initialize($sessionMetadata); - $this->assertEquals($bag1->getCreated(), $bag2->getCreated()); - $this->assertEquals($bag1->getLastUsed(), $bag2->getLastUsed()); - $this->assertEquals($bag2->getCreated(), $bag2->getLastUsed()); - - sleep(1); - $bag3 = new MetadataBag(); - $bag3->initialize($sessionMetadata); - $this->assertEquals($bag1->getCreated(), $bag3->getCreated()); - $this->assertGreaterThan($bag2->getLastUsed(), $bag3->getLastUsed()); - $this->assertNotEquals($bag3->getCreated(), $bag3->getLastUsed()); - } - - public function testGetSetName() - { - $this->assertEquals('__metadata', $this->bag->getName()); - $this->bag->setName('foo'); - $this->assertEquals('foo', $this->bag->getName()); - } - - public function testGetStorageKey() - { - $this->assertEquals('_sf2_meta', $this->bag->getStorageKey()); - } - - public function testGetLifetime() - { - $bag = new MetadataBag(); - $array = [MetadataBag::CREATED => 1234567, MetadataBag::UPDATED => 12345678, MetadataBag::LIFETIME => 1000]; - $bag->initialize($array); - $this->assertEquals(1000, $bag->getLifetime()); - } - - public function testGetCreated() - { - $this->assertEquals(1234567, $this->bag->getCreated()); - } - - public function testGetLastUsed() - { - $this->assertLessThanOrEqual(time(), $this->bag->getLastUsed()); - } - - public function testClear() - { - $this->bag->clear(); - - // the clear method has no side effects, we just want to ensure it doesn't trigger any exceptions - $this->addToAssertionCount(1); - } - - public function testSkipLastUsedUpdate() - { - $bag = new MetadataBag('', 30); - $timeStamp = time(); - - $created = $timeStamp - 15; - $sessionMetadata = [ - MetadataBag::CREATED => $created, - MetadataBag::UPDATED => $created, - MetadataBag::LIFETIME => 1000, - ]; - $bag->initialize($sessionMetadata); - - $this->assertEquals($created, $sessionMetadata[MetadataBag::UPDATED]); - } - - public function testDoesNotSkipLastUsedUpdate() - { - $bag = new MetadataBag('', 30); - $timeStamp = time(); - - $created = $timeStamp - 45; - $sessionMetadata = [ - MetadataBag::CREATED => $created, - MetadataBag::UPDATED => $created, - MetadataBag::LIFETIME => 1000, - ]; - $bag->initialize($sessionMetadata); - - $this->assertEquals($timeStamp, $sessionMetadata[MetadataBag::UPDATED]); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/MockArraySessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/MockArraySessionStorageTest.php deleted file mode 100644 index 7e0d303b..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/MockArraySessionStorageTest.php +++ /dev/null @@ -1,129 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; -use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; - -/** - * Test class for MockArraySessionStorage. - * - * @author Drak - */ -class MockArraySessionStorageTest extends TestCase -{ - /** - * @var MockArraySessionStorage - */ - private $storage; - - /** - * @var AttributeBag - */ - private $attributes; - - /** - * @var FlashBag - */ - private $flashes; - - private $data; - - protected function setUp() - { - $this->attributes = new AttributeBag(); - $this->flashes = new FlashBag(); - - $this->data = [ - $this->attributes->getStorageKey() => ['foo' => 'bar'], - $this->flashes->getStorageKey() => ['notice' => 'hello'], - ]; - - $this->storage = new MockArraySessionStorage(); - $this->storage->registerBag($this->flashes); - $this->storage->registerBag($this->attributes); - $this->storage->setSessionData($this->data); - } - - protected function tearDown() - { - $this->data = null; - $this->flashes = null; - $this->attributes = null; - $this->storage = null; - } - - public function testStart() - { - $this->assertEquals('', $this->storage->getId()); - $this->storage->start(); - $id = $this->storage->getId(); - $this->assertNotEquals('', $id); - $this->storage->start(); - $this->assertEquals($id, $this->storage->getId()); - } - - public function testRegenerate() - { - $this->storage->start(); - $id = $this->storage->getId(); - $this->storage->regenerate(); - $this->assertNotEquals($id, $this->storage->getId()); - $this->assertEquals(['foo' => 'bar'], $this->storage->getBag('attributes')->all()); - $this->assertEquals(['notice' => 'hello'], $this->storage->getBag('flashes')->peekAll()); - - $id = $this->storage->getId(); - $this->storage->regenerate(true); - $this->assertNotEquals($id, $this->storage->getId()); - $this->assertEquals(['foo' => 'bar'], $this->storage->getBag('attributes')->all()); - $this->assertEquals(['notice' => 'hello'], $this->storage->getBag('flashes')->peekAll()); - } - - public function testGetId() - { - $this->assertEquals('', $this->storage->getId()); - $this->storage->start(); - $this->assertNotEquals('', $this->storage->getId()); - } - - public function testClearClearsBags() - { - $this->storage->clear(); - - $this->assertSame([], $this->storage->getBag('attributes')->all()); - $this->assertSame([], $this->storage->getBag('flashes')->peekAll()); - } - - public function testClearStartsSession() - { - $this->storage->clear(); - - $this->assertTrue($this->storage->isStarted()); - } - - public function testClearWithNoBagsStartsSession() - { - $storage = new MockArraySessionStorage(); - - $storage->clear(); - - $this->assertTrue($storage->isStarted()); - } - - public function testUnstartedSave() - { - $this->expectException('RuntimeException'); - $this->storage->save(); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php deleted file mode 100644 index 73d15458..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php +++ /dev/null @@ -1,125 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; -use Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage; - -/** - * Test class for MockFileSessionStorage. - * - * @author Drak - */ -class MockFileSessionStorageTest extends TestCase -{ - /** - * @var string - */ - private $sessionDir; - - /** - * @var MockFileSessionStorage - */ - protected $storage; - - protected function setUp() - { - $this->sessionDir = sys_get_temp_dir().'/sf2test'; - $this->storage = $this->getStorage(); - } - - protected function tearDown() - { - array_map('unlink', glob($this->sessionDir.'/*')); - if (is_dir($this->sessionDir)) { - @rmdir($this->sessionDir); - } - $this->sessionDir = null; - $this->storage = null; - } - - public function testStart() - { - $this->assertEquals('', $this->storage->getId()); - $this->assertTrue($this->storage->start()); - $id = $this->storage->getId(); - $this->assertNotEquals('', $this->storage->getId()); - $this->assertTrue($this->storage->start()); - $this->assertEquals($id, $this->storage->getId()); - } - - public function testRegenerate() - { - $this->storage->start(); - $this->storage->getBag('attributes')->set('regenerate', 1234); - $this->storage->regenerate(); - $this->assertEquals(1234, $this->storage->getBag('attributes')->get('regenerate')); - $this->storage->regenerate(true); - $this->assertEquals(1234, $this->storage->getBag('attributes')->get('regenerate')); - } - - public function testGetId() - { - $this->assertEquals('', $this->storage->getId()); - $this->storage->start(); - $this->assertNotEquals('', $this->storage->getId()); - } - - public function testSave() - { - $this->storage->start(); - $id = $this->storage->getId(); - $this->assertNotEquals('108', $this->storage->getBag('attributes')->get('new')); - $this->assertFalse($this->storage->getBag('flashes')->has('newkey')); - $this->storage->getBag('attributes')->set('new', '108'); - $this->storage->getBag('flashes')->set('newkey', 'test'); - $this->storage->save(); - - $storage = $this->getStorage(); - $storage->setId($id); - $storage->start(); - $this->assertEquals('108', $storage->getBag('attributes')->get('new')); - $this->assertTrue($storage->getBag('flashes')->has('newkey')); - $this->assertEquals(['test'], $storage->getBag('flashes')->peek('newkey')); - } - - public function testMultipleInstances() - { - $storage1 = $this->getStorage(); - $storage1->start(); - $storage1->getBag('attributes')->set('foo', 'bar'); - $storage1->save(); - - $storage2 = $this->getStorage(); - $storage2->setId($storage1->getId()); - $storage2->start(); - $this->assertEquals('bar', $storage2->getBag('attributes')->get('foo'), 'values persist between instances'); - } - - public function testSaveWithoutStart() - { - $this->expectException('RuntimeException'); - $storage1 = $this->getStorage(); - $storage1->save(); - } - - private function getStorage() - { - $storage = new MockFileSessionStorage($this->sessionDir); - $storage->registerBag(new FlashBag()); - $storage->registerBag(new AttributeBag()); - - return $storage; - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php deleted file mode 100644 index d86f56eb..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php +++ /dev/null @@ -1,303 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; -use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; -use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; -use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; - -/** - * Test class for NativeSessionStorage. - * - * @author Drak - * - * These tests require separate processes. - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - */ -class NativeSessionStorageTest extends TestCase -{ - private $savePath; - - protected function setUp() - { - $this->iniSet('session.save_handler', 'files'); - $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sftest'); - if (!is_dir($this->savePath)) { - mkdir($this->savePath); - } - } - - protected function tearDown() - { - session_write_close(); - array_map('unlink', glob($this->savePath.'/*')); - if (is_dir($this->savePath)) { - @rmdir($this->savePath); - } - - $this->savePath = null; - } - - /** - * @return NativeSessionStorage - */ - protected function getStorage(array $options = []) - { - $storage = new NativeSessionStorage($options); - $storage->registerBag(new AttributeBag()); - - return $storage; - } - - public function testBag() - { - $storage = $this->getStorage(); - $bag = new FlashBag(); - $storage->registerBag($bag); - $this->assertSame($bag, $storage->getBag($bag->getName())); - } - - public function testRegisterBagException() - { - $this->expectException('InvalidArgumentException'); - $storage = $this->getStorage(); - $storage->getBag('non_existing'); - } - - public function testRegisterBagForAStartedSessionThrowsException() - { - $this->expectException('LogicException'); - $storage = $this->getStorage(); - $storage->start(); - $storage->registerBag(new AttributeBag()); - } - - public function testGetId() - { - $storage = $this->getStorage(); - $this->assertSame('', $storage->getId(), 'Empty ID before starting session'); - - $storage->start(); - $id = $storage->getId(); - $this->assertIsString($id); - $this->assertNotSame('', $id); - - $storage->save(); - $this->assertSame($id, $storage->getId(), 'ID stays after saving session'); - } - - public function testRegenerate() - { - $storage = $this->getStorage(); - $storage->start(); - $id = $storage->getId(); - $storage->getBag('attributes')->set('lucky', 7); - $storage->regenerate(); - $this->assertNotEquals($id, $storage->getId()); - $this->assertEquals(7, $storage->getBag('attributes')->get('lucky')); - } - - public function testRegenerateDestroy() - { - $storage = $this->getStorage(); - $storage->start(); - $id = $storage->getId(); - $storage->getBag('attributes')->set('legs', 11); - $storage->regenerate(true); - $this->assertNotEquals($id, $storage->getId()); - $this->assertEquals(11, $storage->getBag('attributes')->get('legs')); - } - - public function testRegenerateWithCustomLifetime() - { - $storage = $this->getStorage(); - $storage->start(); - $id = $storage->getId(); - $lifetime = 999999; - $storage->getBag('attributes')->set('legs', 11); - $storage->regenerate(false, $lifetime); - $this->assertNotEquals($id, $storage->getId()); - $this->assertEquals(11, $storage->getBag('attributes')->get('legs')); - $this->assertEquals($lifetime, ini_get('session.cookie_lifetime')); - } - - public function testSessionGlobalIsUpToDateAfterIdRegeneration() - { - $storage = $this->getStorage(); - $storage->start(); - $storage->getBag('attributes')->set('lucky', 7); - $storage->regenerate(); - $storage->getBag('attributes')->set('lucky', 42); - - $this->assertEquals(42, $_SESSION['_sf2_attributes']['lucky']); - } - - public function testRegenerationFailureDoesNotFlagStorageAsStarted() - { - $storage = $this->getStorage(); - $this->assertFalse($storage->regenerate()); - $this->assertFalse($storage->isStarted()); - } - - public function testDefaultSessionCacheLimiter() - { - $this->iniSet('session.cache_limiter', 'nocache'); - - new NativeSessionStorage(); - $this->assertEquals('', ini_get('session.cache_limiter')); - } - - public function testExplicitSessionCacheLimiter() - { - $this->iniSet('session.cache_limiter', 'nocache'); - - new NativeSessionStorage(['cache_limiter' => 'public']); - $this->assertEquals('public', ini_get('session.cache_limiter')); - } - - public function testCookieOptions() - { - $options = [ - 'cookie_lifetime' => 123456, - 'cookie_path' => '/my/cookie/path', - 'cookie_domain' => 'symfony.example.com', - 'cookie_secure' => true, - 'cookie_httponly' => false, - ]; - - if (\PHP_VERSION_ID >= 70300) { - $options['cookie_samesite'] = 'lax'; - } - - $this->getStorage($options); - $temp = session_get_cookie_params(); - $gco = []; - - foreach ($temp as $key => $value) { - $gco['cookie_'.$key] = $value; - } - - $this->assertEquals($options, $gco); - } - - public function testSessionOptions() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM is not handled in this test case.'); - } - - $options = [ - 'url_rewriter.tags' => 'a=href', - 'cache_expire' => '200', - ]; - - $this->getStorage($options); - - $this->assertSame('a=href', ini_get('url_rewriter.tags')); - $this->assertSame('200', ini_get('session.cache_expire')); - } - - public function testSetSaveHandlerException() - { - $this->expectException('InvalidArgumentException'); - $storage = $this->getStorage(); - $storage->setSaveHandler(new \stdClass()); - } - - public function testSetSaveHandler() - { - $this->iniSet('session.save_handler', 'files'); - $storage = $this->getStorage(); - $storage->setSaveHandler(); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(null); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new SessionHandlerProxy(new NativeFileSessionHandler())); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new NativeFileSessionHandler()); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new SessionHandlerProxy(new NullSessionHandler())); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - $storage->setSaveHandler(new NullSessionHandler()); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); - } - - public function testStarted() - { - $this->expectException('RuntimeException'); - $storage = $this->getStorage(); - - $this->assertFalse($storage->getSaveHandler()->isActive()); - $this->assertFalse($storage->isStarted()); - - session_start(); - $this->assertTrue(isset($_SESSION)); - $this->assertTrue($storage->getSaveHandler()->isActive()); - - // PHP session might have started, but the storage driver has not, so false is correct here - $this->assertFalse($storage->isStarted()); - - $key = $storage->getMetadataBag()->getStorageKey(); - $this->assertArrayNotHasKey($key, $_SESSION); - $storage->start(); - } - - public function testRestart() - { - $storage = $this->getStorage(); - $storage->start(); - $id = $storage->getId(); - $storage->getBag('attributes')->set('lucky', 7); - $storage->save(); - $storage->start(); - $this->assertSame($id, $storage->getId(), 'Same session ID after restarting'); - $this->assertSame(7, $storage->getBag('attributes')->get('lucky'), 'Data still available'); - } - - public function testCanCreateNativeSessionStorageWhenSessionAlreadyStarted() - { - session_start(); - $this->getStorage(); - - // Assert no exception has been thrown by `getStorage()` - $this->addToAssertionCount(1); - } - - public function testSetSessionOptionsOnceSessionStartedIsIgnored() - { - session_start(); - $this->getStorage([ - 'name' => 'something-else', - ]); - - // Assert no exception has been thrown by `getStorage()` - $this->addToAssertionCount(1); - } - - public function testGetBagsOnceSessionStartedIsIgnored() - { - session_start(); - $bag = new AttributeBag(); - $bag->setName('flashes'); - - $storage = $this->getStorage(); - $storage->registerBag($bag); - - $this->assertEquals($storage->getBag('flashes'), $bag); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php deleted file mode 100644 index e60b91b1..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php +++ /dev/null @@ -1,96 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; -use Symfony\Component\HttpFoundation\Session\Storage\PhpBridgeSessionStorage; - -/** - * Test class for PhpSessionStorage. - * - * @author Drak - * - * These tests require separate processes. - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - */ -class PhpBridgeSessionStorageTest extends TestCase -{ - private $savePath; - - protected function setUp() - { - $this->iniSet('session.save_handler', 'files'); - $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sf2test'); - if (!is_dir($this->savePath)) { - mkdir($this->savePath); - } - } - - protected function tearDown() - { - session_write_close(); - array_map('unlink', glob($this->savePath.'/*')); - if (is_dir($this->savePath)) { - @rmdir($this->savePath); - } - - $this->savePath = null; - } - - /** - * @return PhpBridgeSessionStorage - */ - protected function getStorage() - { - $storage = new PhpBridgeSessionStorage(); - $storage->registerBag(new AttributeBag()); - - return $storage; - } - - public function testPhpSession() - { - $storage = $this->getStorage(); - - $this->assertFalse($storage->getSaveHandler()->isActive()); - $this->assertFalse($storage->isStarted()); - - session_start(); - $this->assertTrue(isset($_SESSION)); - // in PHP 5.4 we can reliably detect a session started - $this->assertTrue($storage->getSaveHandler()->isActive()); - // PHP session might have started, but the storage driver has not, so false is correct here - $this->assertFalse($storage->isStarted()); - - $key = $storage->getMetadataBag()->getStorageKey(); - $this->assertArrayNotHasKey($key, $_SESSION); - $storage->start(); - $this->assertArrayHasKey($key, $_SESSION); - } - - public function testClear() - { - $storage = $this->getStorage(); - session_start(); - $_SESSION['drak'] = 'loves symfony'; - $storage->getBag('attributes')->set('symfony', 'greatness'); - $key = $storage->getBag('attributes')->getStorageKey(); - $this->assertEquals(['symfony' => 'greatness'], $_SESSION[$key]); - $this->assertEquals('loves symfony', $_SESSION['drak']); - $storage->clear(); - $this->assertEquals([], $_SESSION[$key]); - $this->assertEquals('loves symfony', $_SESSION['drak']); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/AbstractProxyTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/AbstractProxyTest.php deleted file mode 100644 index ae40f2c2..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/AbstractProxyTest.php +++ /dev/null @@ -1,113 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Proxy; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; -use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; - -/** - * Test class for AbstractProxy. - * - * @author Drak - */ -class AbstractProxyTest extends TestCase -{ - /** - * @var AbstractProxy - */ - protected $proxy; - - protected function setUp() - { - $this->proxy = $this->getMockForAbstractClass(AbstractProxy::class); - } - - protected function tearDown() - { - $this->proxy = null; - } - - public function testGetSaveHandlerName() - { - $this->assertNull($this->proxy->getSaveHandlerName()); - } - - public function testIsSessionHandlerInterface() - { - $this->assertFalse($this->proxy->isSessionHandlerInterface()); - $sh = new SessionHandlerProxy(new \SessionHandler()); - $this->assertTrue($sh->isSessionHandlerInterface()); - } - - public function testIsWrapper() - { - $this->assertFalse($this->proxy->isWrapper()); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testIsActive() - { - $this->assertFalse($this->proxy->isActive()); - session_start(); - $this->assertTrue($this->proxy->isActive()); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testName() - { - $this->assertEquals(session_name(), $this->proxy->getName()); - $this->proxy->setName('foo'); - $this->assertEquals('foo', $this->proxy->getName()); - $this->assertEquals(session_name(), $this->proxy->getName()); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testNameException() - { - $this->expectException('LogicException'); - session_start(); - $this->proxy->setName('foo'); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testId() - { - $this->assertEquals(session_id(), $this->proxy->getId()); - $this->proxy->setId('foo'); - $this->assertEquals('foo', $this->proxy->getId()); - $this->assertEquals(session_id(), $this->proxy->getId()); - } - - /** - * @runInSeparateProcess - * @preserveGlobalState disabled - */ - public function testIdException() - { - $this->expectException('LogicException'); - session_start(); - $this->proxy->setId('foo'); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php deleted file mode 100644 index ed4fee6b..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Proxy; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy; - -/** - * Test class for NativeProxy. - * - * @group legacy - * - * @author Drak - */ -class NativeProxyTest extends TestCase -{ - public function testIsWrapper() - { - $proxy = new NativeProxy(); - $this->assertFalse($proxy->isWrapper()); - } - - public function testGetSaveHandlerName() - { - $name = ini_get('session.save_handler'); - $proxy = new NativeProxy(); - $this->assertEquals($name, $proxy->getSaveHandlerName()); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php deleted file mode 100644 index 3310cf9c..00000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php +++ /dev/null @@ -1,162 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Proxy; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; - -/** - * Tests for SessionHandlerProxy class. - * - * @author Drak - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - */ -class SessionHandlerProxyTest extends TestCase -{ - /** - * @var \PHPUnit\Framework\MockObject\Matcher - */ - private $mock; - - /** - * @var SessionHandlerProxy - */ - private $proxy; - - protected function setUp() - { - $this->mock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $this->proxy = new SessionHandlerProxy($this->mock); - } - - protected function tearDown() - { - $this->mock = null; - $this->proxy = null; - } - - public function testOpenTrue() - { - $this->mock->expects($this->once()) - ->method('open') - ->willReturn(true); - - $this->assertFalse($this->proxy->isActive()); - $this->proxy->open('name', 'id'); - $this->assertFalse($this->proxy->isActive()); - } - - public function testOpenFalse() - { - $this->mock->expects($this->once()) - ->method('open') - ->willReturn(false); - - $this->assertFalse($this->proxy->isActive()); - $this->proxy->open('name', 'id'); - $this->assertFalse($this->proxy->isActive()); - } - - public function testClose() - { - $this->mock->expects($this->once()) - ->method('close') - ->willReturn(true); - - $this->assertFalse($this->proxy->isActive()); - $this->proxy->close(); - $this->assertFalse($this->proxy->isActive()); - } - - public function testCloseFalse() - { - $this->mock->expects($this->once()) - ->method('close') - ->willReturn(false); - - $this->assertFalse($this->proxy->isActive()); - $this->proxy->close(); - $this->assertFalse($this->proxy->isActive()); - } - - public function testRead() - { - $this->mock->expects($this->once()) - ->method('read'); - - $this->proxy->read('id'); - } - - public function testWrite() - { - $this->mock->expects($this->once()) - ->method('write'); - - $this->proxy->write('id', 'data'); - } - - public function testDestroy() - { - $this->mock->expects($this->once()) - ->method('destroy'); - - $this->proxy->destroy('id'); - } - - public function testGc() - { - $this->mock->expects($this->once()) - ->method('gc'); - - $this->proxy->gc(86400); - } - - /** - * @requires PHPUnit 5.1 - */ - public function testValidateId() - { - $mock = $this->getMockBuilder(TestSessionHandler::class)->getMock(); - $mock->expects($this->once()) - ->method('validateId'); - - $proxy = new SessionHandlerProxy($mock); - $proxy->validateId('id'); - - $this->assertTrue($this->proxy->validateId('id')); - } - - /** - * @requires PHPUnit 5.1 - */ - public function testUpdateTimestamp() - { - $mock = $this->getMockBuilder(TestSessionHandler::class)->getMock(); - $mock->expects($this->once()) - ->method('updateTimestamp') - ->willReturn(false); - - $proxy = new SessionHandlerProxy($mock); - $proxy->updateTimestamp('id', 'data'); - - $this->mock->expects($this->once()) - ->method('write'); - - $this->proxy->updateTimestamp('id', 'data'); - } -} - -abstract class TestSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface -{ -} diff --git a/vendor/symfony/http-foundation/Tests/StreamedResponseTest.php b/vendor/symfony/http-foundation/Tests/StreamedResponseTest.php deleted file mode 100644 index a084e917..00000000 --- a/vendor/symfony/http-foundation/Tests/StreamedResponseTest.php +++ /dev/null @@ -1,140 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpFoundation\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\StreamedResponse; - -class StreamedResponseTest extends TestCase -{ - public function testConstructor() - { - $response = new StreamedResponse(function () { echo 'foo'; }, 404, ['Content-Type' => 'text/plain']); - - $this->assertEquals(404, $response->getStatusCode()); - $this->assertEquals('text/plain', $response->headers->get('Content-Type')); - } - - public function testPrepareWith11Protocol() - { - $response = new StreamedResponse(function () { echo 'foo'; }); - $request = Request::create('/'); - $request->server->set('SERVER_PROTOCOL', 'HTTP/1.1'); - - $response->prepare($request); - - $this->assertEquals('1.1', $response->getProtocolVersion()); - $this->assertNotEquals('chunked', $response->headers->get('Transfer-Encoding'), 'Apache assumes responses with a Transfer-Encoding header set to chunked to already be encoded.'); - } - - public function testPrepareWith10Protocol() - { - $response = new StreamedResponse(function () { echo 'foo'; }); - $request = Request::create('/'); - $request->server->set('SERVER_PROTOCOL', 'HTTP/1.0'); - - $response->prepare($request); - - $this->assertEquals('1.0', $response->getProtocolVersion()); - $this->assertNull($response->headers->get('Transfer-Encoding')); - } - - public function testPrepareWithHeadRequest() - { - $response = new StreamedResponse(function () { echo 'foo'; }, 200, ['Content-Length' => '123']); - $request = Request::create('/', 'HEAD'); - - $response->prepare($request); - - $this->assertSame('123', $response->headers->get('Content-Length')); - } - - public function testPrepareWithCacheHeaders() - { - $response = new StreamedResponse(function () { echo 'foo'; }, 200, ['Cache-Control' => 'max-age=600, public']); - $request = Request::create('/', 'GET'); - - $response->prepare($request); - $this->assertEquals('max-age=600, public', $response->headers->get('Cache-Control')); - } - - public function testSendContent() - { - $called = 0; - - $response = new StreamedResponse(function () use (&$called) { ++$called; }); - - $response->sendContent(); - $this->assertEquals(1, $called); - - $response->sendContent(); - $this->assertEquals(1, $called); - } - - public function testSendContentWithNonCallable() - { - $this->expectException('LogicException'); - $response = new StreamedResponse(null); - $response->sendContent(); - } - - public function testSetContent() - { - $this->expectException('LogicException'); - $response = new StreamedResponse(function () { echo 'foo'; }); - $response->setContent('foo'); - } - - public function testGetContent() - { - $response = new StreamedResponse(function () { echo 'foo'; }); - $this->assertFalse($response->getContent()); - } - - public function testCreate() - { - $response = StreamedResponse::create(function () {}, 204); - - $this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response); - $this->assertEquals(204, $response->getStatusCode()); - } - - public function testReturnThis() - { - $response = new StreamedResponse(function () {}); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response->sendContent()); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response->sendContent()); - - $response = new StreamedResponse(function () {}); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response->sendHeaders()); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response->sendHeaders()); - } - - public function testSetNotModified() - { - $response = new StreamedResponse(function () { echo 'foo'; }); - $modified = $response->setNotModified(); - $this->assertObjectHasAttribute('headers', $modified); - $this->assertObjectHasAttribute('content', $modified); - $this->assertObjectHasAttribute('version', $modified); - $this->assertObjectHasAttribute('statusCode', $modified); - $this->assertObjectHasAttribute('statusText', $modified); - $this->assertObjectHasAttribute('charset', $modified); - $this->assertEquals(304, $modified->getStatusCode()); - - ob_start(); - $modified->sendContent(); - $string = ob_get_clean(); - $this->assertEmpty($string); - } -} diff --git a/vendor/symfony/http-foundation/Tests/schema/http-status-codes.rng b/vendor/symfony/http-foundation/Tests/schema/http-status-codes.rng deleted file mode 100644 index 73708ca6..00000000 --- a/vendor/symfony/http-foundation/Tests/schema/http-status-codes.rng +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vendor/symfony/http-foundation/Tests/schema/iana-registry.rng b/vendor/symfony/http-foundation/Tests/schema/iana-registry.rng deleted file mode 100644 index b9c3ca9d..00000000 --- a/vendor/symfony/http-foundation/Tests/schema/iana-registry.rng +++ /dev/null @@ -1,198 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - uri - - - - rfc - - - (rfc|bcp|std)\d+ - - - - - rfc-errata - - - - draft - - - (draft|RFC)(-[a-zA-Z0-9]+)+ - - - - - registry - - - - person - - - - text - - - note - - - - unicode - - - ucd\d+\.\d+\.\d+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (\d+|0x[\da-fA-F]+)(\s*-\s*(\d+|0x[\da-fA-F]+))? - - - - - - - - - - - - - 0x[0-9]{8} - - - - - - [0-1]+ - - - - - - - - - - - - - - - - - - - - - - legacy - mib - template - json - - - - - - - - - - diff --git a/vendor/symfony/http-foundation/UrlHelper.php b/vendor/symfony/http-foundation/UrlHelper.php new file mode 100644 index 00000000..90659947 --- /dev/null +++ b/vendor/symfony/http-foundation/UrlHelper.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation; + +use Symfony\Component\Routing\RequestContext; +use Symfony\Component\Routing\RequestContextAwareInterface; + +/** + * A helper service for manipulating URLs within and outside the request scope. + * + * @author Valentin Udaltsov + */ +final class UrlHelper +{ + private $requestStack; + private $requestContext; + + /** + * @param RequestContextAwareInterface|RequestContext|null $requestContext + */ + public function __construct(RequestStack $requestStack, $requestContext = null) + { + if (null !== $requestContext && !$requestContext instanceof RequestContext && !$requestContext instanceof RequestContextAwareInterface) { + throw new \TypeError(__METHOD__.': Argument #2 ($requestContext) must of type Symfony\Component\Routing\RequestContextAwareInterface|Symfony\Component\Routing\RequestContext|null, '.get_debug_type($requestContext).' given.'); + } + + $this->requestStack = $requestStack; + $this->requestContext = $requestContext; + } + + public function getAbsoluteUrl(string $path): string + { + if (str_contains($path, '://') || '//' === substr($path, 0, 2)) { + return $path; + } + + if (null === $request = $this->requestStack->getMainRequest()) { + return $this->getAbsoluteUrlFromContext($path); + } + + if ('#' === $path[0]) { + $path = $request->getRequestUri().$path; + } elseif ('?' === $path[0]) { + $path = $request->getPathInfo().$path; + } + + if (!$path || '/' !== $path[0]) { + $prefix = $request->getPathInfo(); + $last = \strlen($prefix) - 1; + if ($last !== $pos = strrpos($prefix, '/')) { + $prefix = substr($prefix, 0, $pos).'/'; + } + + return $request->getUriForPath($prefix.$path); + } + + return $request->getSchemeAndHttpHost().$path; + } + + public function getRelativePath(string $path): string + { + if (str_contains($path, '://') || '//' === substr($path, 0, 2)) { + return $path; + } + + if (null === $request = $this->requestStack->getMainRequest()) { + return $path; + } + + return $request->getRelativeUriForPath($path); + } + + private function getAbsoluteUrlFromContext(string $path): string + { + if (null === $context = $this->requestContext) { + return $path; + } + + if ($context instanceof RequestContextAwareInterface) { + $context = $context->getContext(); + } + + if ('' === $host = $context->getHost()) { + return $path; + } + + $scheme = $context->getScheme(); + $port = ''; + + if ('http' === $scheme && 80 !== $context->getHttpPort()) { + $port = ':'.$context->getHttpPort(); + } elseif ('https' === $scheme && 443 !== $context->getHttpsPort()) { + $port = ':'.$context->getHttpsPort(); + } + + if ('#' === $path[0]) { + $queryString = $context->getQueryString(); + $path = $context->getPathInfo().($queryString ? '?'.$queryString : '').$path; + } elseif ('?' === $path[0]) { + $path = $context->getPathInfo().$path; + } + + if ('/' !== $path[0]) { + $path = rtrim($context->getBaseUrl(), '/').'/'.$path; + } + + return $scheme.'://'.$host.$port.$path; + } +} diff --git a/vendor/symfony/http-foundation/composer.json b/vendor/symfony/http-foundation/composer.json index 2f5ad1a3..cb8d59ff 100644 --- a/vendor/symfony/http-foundation/composer.json +++ b/vendor/symfony/http-foundation/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/http-foundation", "type": "library", - "description": "Symfony HttpFoundation Component", + "description": "Defines an object-oriented layer for the HTTP specification", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,12 +16,22 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" + }, + "suggest" : { + "symfony/mime": "To use the file extension guesser" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" }, diff --git a/vendor/symfony/http-foundation/phpunit.xml.dist b/vendor/symfony/http-foundation/phpunit.xml.dist deleted file mode 100644 index f57bc9e6..00000000 --- a/vendor/symfony/http-foundation/phpunit.xml.dist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/http-kernel/.gitignore b/vendor/symfony/http-kernel/.gitignore deleted file mode 100644 index 94a6a252..00000000 --- a/vendor/symfony/http-kernel/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -vendor/ -composer.lock -phpunit.xml -Tests/Fixtures/cache/ -Tests/Fixtures/logs/ diff --git a/vendor/symfony/http-kernel/Bundle/Bundle.php b/vendor/symfony/http-kernel/Bundle/Bundle.php index d0f9811e..e8057737 100644 --- a/vendor/symfony/http-kernel/Bundle/Bundle.php +++ b/vendor/symfony/http-kernel/Bundle/Bundle.php @@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; -use Symfony\Component\Finder\Finder; /** * An implementation of BundleInterface that adds a few conventions for DependencyInjection extensions. @@ -116,16 +115,9 @@ public function getPath() } /** - * {@inheritdoc} + * Returns the bundle name (the class short name). */ - public function getParent() - { - } - - /** - * {@inheritdoc} - */ - final public function getName() + final public function getName(): string { if (null === $this->name) { $this->parseClassName(); @@ -134,48 +126,8 @@ final public function getName() return $this->name; } - /** - * Finds and registers Commands. - * - * Override this method if your bundle commands do not follow the conventions: - * - * * Commands are in the 'Command' sub-directory - * * Commands extend Symfony\Component\Console\Command\Command - */ public function registerCommands(Application $application) { - if (!is_dir($dir = $this->getPath().'/Command')) { - return; - } - - if (!class_exists('Symfony\Component\Finder\Finder')) { - throw new \RuntimeException('You need the symfony/finder component to register bundle commands.'); - } - - $finder = new Finder(); - $finder->files()->name('*Command.php')->in($dir); - - $prefix = $this->getNamespace().'\\Command'; - foreach ($finder as $file) { - $ns = $prefix; - if ($relativePath = $file->getRelativePath()) { - $ns .= '\\'.str_replace('/', '\\', $relativePath); - } - $class = $ns.'\\'.$file->getBasename('.php'); - if ($this->container) { - $commandIds = $this->container->hasParameter('console.command.ids') ? $this->container->getParameter('console.command.ids') : []; - $alias = 'console.command.'.strtolower(str_replace('\\', '_', $class)); - if (isset($commandIds[$alias]) || $this->container->has($alias)) { - continue; - } - } - $r = new \ReflectionClass($class); - if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract() && !$r->getConstructor()->getNumberOfRequiredParameters()) { - @trigger_error(sprintf('Auto-registration of the command "%s" is deprecated since Symfony 3.4 and won\'t be supported in 4.0. Use PSR-4 based service discovery instead.', $class), \E_USER_DEPRECATED); - - $application->add($r->newInstance()); - } - } } /** diff --git a/vendor/symfony/http-kernel/Bundle/BundleInterface.php b/vendor/symfony/http-kernel/Bundle/BundleInterface.php index 14a7f6f4..88a95d83 100644 --- a/vendor/symfony/http-kernel/Bundle/BundleInterface.php +++ b/vendor/symfony/http-kernel/Bundle/BundleInterface.php @@ -46,19 +46,6 @@ public function build(ContainerBuilder $container); */ public function getContainerExtension(); - /** - * Returns the bundle name that this bundle overrides. - * - * Despite its name, this method does not imply any parent/child relationship - * between the bundles, just a way to extend and override an existing - * bundle. - * - * @return string The Bundle name it overrides or null if no parent - * - * @deprecated This method is deprecated as of 3.4 and will be removed in 4.0. - */ - public function getParent(); - /** * Returns the bundle name (the class short name). * diff --git a/vendor/symfony/http-kernel/CHANGELOG.md b/vendor/symfony/http-kernel/CHANGELOG.md index fb29f769..08a8cfdd 100644 --- a/vendor/symfony/http-kernel/CHANGELOG.md +++ b/vendor/symfony/http-kernel/CHANGELOG.md @@ -1,6 +1,96 @@ CHANGELOG ========= +4.4.0 +----- + + * The `DebugHandlersListener` class has been marked as `final` + * Added new Bundle directory convention consistent with standard skeletons + * Deprecated the second and third argument of `KernelInterface::locateResource` + * Deprecated the second and third argument of `FileLocator::__construct` + * Deprecated loading resources from `%kernel.root_dir%/Resources` and `%kernel.root_dir%` as + fallback directories. Resources like service definitions are usually loaded relative to the + current directory or with a glob pattern. The fallback directories have never been advocated + so you likely do not use those in any app based on the SF Standard or Flex edition. + * Marked all dispatched event classes as `@final` + * Added `ErrorController` to enable the preview and error rendering mechanism + * Getting the container from a non-booted kernel is deprecated. + * Marked the `AjaxDataCollector`, `ConfigDataCollector`, `EventDataCollector`, + `ExceptionDataCollector`, `LoggerDataCollector`, `MemoryDataCollector`, + `RequestDataCollector` and `TimeDataCollector` classes as `@final`. + * Marked the `RouterDataCollector::collect()` method as `@final`. + * The `DataCollectorInterface::collect()` and `Profiler::collect()` methods third parameter signature + will be `\Throwable $exception = null` instead of `\Exception $exception = null` in Symfony 5.0. + * Deprecated methods `ExceptionEvent::get/setException()`, use `get/setThrowable()` instead + * Deprecated class `ExceptionListener`, use `ErrorListener` instead + +4.3.0 +----- + + * renamed `Client` to `HttpKernelBrowser` + * `KernelInterface` doesn't extend `Serializable` anymore + * deprecated the `Kernel::serialize()` and `unserialize()` methods + * increased the priority of `Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener` + * made `Symfony\Component\HttpKernel\EventListener\LocaleListener` set the default locale early + * deprecated `TranslatorListener` in favor of `LocaleAwareListener` + * added the registration of all `LocaleAwareInterface` implementations into the `LocaleAwareListener` + * made `FileLinkFormatter` final and not implement `Serializable` anymore + * the base `DataCollector` doesn't implement `Serializable` anymore, you should + store all the serialized state in the data property instead + * `DumpDataCollector` has been marked as `final` + * added an event listener to prevent search engines from indexing applications in debug mode. + * renamed `FilterControllerArgumentsEvent` to `ControllerArgumentsEvent` + * renamed `FilterControllerEvent` to `ControllerEvent` + * renamed `FilterResponseEvent` to `ResponseEvent` + * renamed `GetResponseEvent` to `RequestEvent` + * renamed `GetResponseForControllerResultEvent` to `ViewEvent` + * renamed `GetResponseForExceptionEvent` to `ExceptionEvent` + * renamed `PostResponseEvent` to `TerminateEvent` + * added `HttpClientKernel` for handling requests with an `HttpClientInterface` instance + * added `trace_header` and `trace_level` configuration options to `HttpCache` + +4.2.0 +----- + + * deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter + * deprecated `KernelInterface::getName()` and the `kernel.name` parameter + * deprecated the first and second constructor argument of `ConfigDataCollector` + * deprecated `ConfigDataCollector::getApplicationName()` + * deprecated `ConfigDataCollector::getApplicationVersion()` + +4.1.0 +----- + + * added orphaned events support to `EventDataCollector` + * `ExceptionListener` now logs exceptions at priority `0` (previously logged at `-128`) + * Added support for using `service::method` to reference controllers, making it consistent with other cases. It is recommended over the `service:action` syntax with a single colon, which will be deprecated in the future. + * Added the ability to profile individual argument value resolvers via the + `Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver` + +4.0.0 +----- + + * removed the `DataCollector::varToString()` method, use `DataCollector::cloneVar()` + instead + * using the `DataCollector::cloneVar()` method requires the VarDumper component + * removed the `ValueExporter` class + * removed `ControllerResolverInterface::getArguments()` + * removed `TraceableControllerResolver::getArguments()` + * removed `ControllerResolver::getArguments()` and the ability to resolve arguments + * removed the `argument_resolver` service dependency from the `debug.controller_resolver` + * removed `LazyLoadingFragmentHandler::addRendererService()` + * removed `Psr6CacheClearer::addPool()` + * removed `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` + * removed `Kernel::loadClassCache()`, `Kernel::doLoadClassCache()`, `Kernel::setClassCache()`, + and `Kernel::getEnvParameters()` + * support for the `X-Status-Code` when handling exceptions in the `HttpKernel` + has been dropped, use the `HttpKernel::allowCustomResponseCode()` method + instead + * removed convention-based commands registration + * removed the `ChainCacheClearer::add()` method + * removed the `CacheaWarmerAggregate::add()` and `setWarmers()` methods + * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final + 3.4.0 ----- diff --git a/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php b/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php index a71cc405..5061a8d1 100644 --- a/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php +++ b/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php @@ -16,18 +16,13 @@ * * @author Dustin Dobervich * - * @final since version 3.4 + * @final */ class ChainCacheClearer implements CacheClearerInterface { - protected $clearers; + private $clearers; - /** - * Constructs a new instance of ChainCacheClearer. - * - * @param array $clearers The initial clearers - */ - public function __construct($clearers = []) + public function __construct(iterable $clearers = []) { $this->clearers = $clearers; } @@ -41,16 +36,4 @@ public function clear($cacheDir) $clearer->clear($cacheDir); } } - - /** - * Adds a cache clearer to the aggregate. - * - * @deprecated since version 3.4, to be removed in 4.0, inject the list of clearers as a constructor argument instead. - */ - public function add(CacheClearerInterface $clearer) - { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0, inject the list of clearers as a constructor argument instead.', __METHOD__), \E_USER_DEPRECATED); - - $this->clearers[] = $clearer; - } } diff --git a/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php b/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php index 4271e0f8..f5670f1b 100644 --- a/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php +++ b/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php @@ -11,8 +11,6 @@ namespace Symfony\Component\HttpKernel\CacheClearer; -use Psr\Cache\CacheItemPoolInterface; - /** * @author Nicolas Grekas */ @@ -25,16 +23,18 @@ public function __construct(array $pools = []) $this->pools = $pools; } - public function addPool(CacheItemPoolInterface $pool) + public function hasPool($name) { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Pass an array of pools indexed by name to the constructor instead.', __METHOD__), \E_USER_DEPRECATED); - - $this->pools[] = $pool; + return isset($this->pools[$name]); } - public function hasPool($name) + public function getPool($name) { - return isset($this->pools[$name]); + if (!$this->hasPool($name)) { + throw new \InvalidArgumentException(sprintf('Cache pool not found: "%s".', $name)); + } + + return $this->pools[$name]; } public function clearPool($name) diff --git a/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php b/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php index 010a3998..30832259 100644 --- a/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php +++ b/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php @@ -16,20 +16,21 @@ * * @author Fabien Potencier * - * @final since version 3.4 + * @final */ class CacheWarmerAggregate implements CacheWarmerInterface { - protected $warmers = []; - protected $optionalsEnabled = false; - private $triggerDeprecation = false; + private $warmers; + private $debug; + private $deprecationLogsFilepath; + private $optionalsEnabled = false; + private $onlyOptionalsEnabled = false; - public function __construct($warmers = []) + public function __construct(iterable $warmers = [], bool $debug = false, string $deprecationLogsFilepath = null) { - foreach ($warmers as $warmer) { - $this->add($warmer); - } - $this->triggerDeprecation = true; + $this->warmers = $warmers; + $this->debug = $debug; + $this->deprecationLogsFilepath = $deprecationLogsFilepath; } public function enableOptionalWarmers() @@ -37,6 +38,11 @@ public function enableOptionalWarmers() $this->optionalsEnabled = true; } + public function enableOnlyOptionalWarmers() + { + $this->onlyOptionalsEnabled = $this->optionalsEnabled = true; + } + /** * Warms up the cache. * @@ -44,12 +50,65 @@ public function enableOptionalWarmers() */ public function warmUp($cacheDir) { - foreach ($this->warmers as $warmer) { - if (!$this->optionalsEnabled && $warmer->isOptional()) { - continue; + if ($collectDeprecations = $this->debug && !\defined('PHPUNIT_COMPOSER_INSTALL')) { + $collectedLogs = []; + $previousHandler = set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) { + if (\E_USER_DEPRECATED !== $type && \E_DEPRECATED !== $type) { + return $previousHandler ? $previousHandler($type, $message, $file, $line) : false; + } + + if (isset($collectedLogs[$message])) { + ++$collectedLogs[$message]['count']; + + return null; + } + + $backtrace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 3); + // Clean the trace by removing first frames added by the error handler itself. + for ($i = 0; isset($backtrace[$i]); ++$i) { + if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { + $backtrace = \array_slice($backtrace, 1 + $i); + break; + } + } + + $collectedLogs[$message] = [ + 'type' => $type, + 'message' => $message, + 'file' => $file, + 'line' => $line, + 'trace' => $backtrace, + 'count' => 1, + ]; + + return null; + }); + } + + try { + foreach ($this->warmers as $warmer) { + if (!$this->optionalsEnabled && $warmer->isOptional()) { + continue; + } + if ($this->onlyOptionalsEnabled && !$warmer->isOptional()) { + continue; + } + + $warmer->warmUp($cacheDir); } + } finally { + if ($collectDeprecations) { + restore_error_handler(); + + if (file_exists($this->deprecationLogsFilepath)) { + $previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath)); + if (\is_array($previousLogs)) { + $collectedLogs = array_merge($previousLogs, $collectedLogs); + } + } - $warmer->warmUp($cacheDir); + file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs))); + } } } @@ -58,33 +117,8 @@ public function warmUp($cacheDir) * * @return bool always false */ - public function isOptional() + public function isOptional(): bool { return false; } - - /** - * @deprecated since version 3.4, to be removed in 4.0, inject the list of clearers as a constructor argument instead. - */ - public function setWarmers(array $warmers) - { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0, inject the list of clearers as a constructor argument instead.', __METHOD__), \E_USER_DEPRECATED); - - $this->warmers = []; - foreach ($warmers as $warmer) { - $this->add($warmer); - } - } - - /** - * @deprecated since version 3.4, to be removed in 4.0, inject the list of clearers as a constructor argument instead. - */ - public function add(CacheWarmerInterface $warmer) - { - if ($this->triggerDeprecation) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0, inject the list of clearers as a constructor argument instead.', __METHOD__), \E_USER_DEPRECATED); - } - - $this->warmers[] = $warmer; - } } diff --git a/vendor/symfony/http-kernel/Client.php b/vendor/symfony/http-kernel/Client.php index 14794727..5c9169ce 100644 --- a/vendor/symfony/http-kernel/Client.php +++ b/vendor/symfony/http-kernel/Client.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel; -use Symfony\Component\BrowserKit\Client as BaseClient; +use Symfony\Component\BrowserKit\AbstractBrowser; use Symfony\Component\BrowserKit\CookieJar; use Symfony\Component\BrowserKit\History; use Symfony\Component\BrowserKit\Request as DomRequest; @@ -21,23 +21,20 @@ use Symfony\Component\HttpFoundation\Response; /** - * Client simulates a browser and makes requests to a Kernel object. + * Client simulates a browser and makes requests to an HttpKernel instance. * - * @author Fabien Potencier + * @method Request getRequest() A Request instance + * @method Response getResponse() A Response instance * - * @method Request|null getRequest() A Request instance - * @method Response|null getResponse() A Response instance + * @deprecated since Symfony 4.3, use HttpKernelBrowser instead. */ -class Client extends BaseClient +class Client extends AbstractBrowser { protected $kernel; private $catchExceptions = true; /** - * @param HttpKernelInterface $kernel An HttpKernel instance - * @param array $server The server parameters (equivalent of $_SERVER) - * @param History $history A History instance to store the browser history - * @param CookieJar $cookieJar A CookieJar instance to store the cookies + * @param array $server The server parameters (equivalent of $_SERVER) */ public function __construct(HttpKernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) { @@ -88,9 +85,9 @@ protected function getScript($request) $requires = ''; foreach (get_declared_classes() as $class) { - if (0 === strpos($class, 'ComposerAutoloaderInit')) { + if (str_starts_with($class, 'ComposerAutoloaderInit')) { $r = new \ReflectionClass($class); - $file = \dirname(\dirname($r->getFileName())).'/autoload.php'; + $file = \dirname($r->getFileName(), 2).'/autoload.php'; if (file_exists($file)) { $requires .= 'require_once '.var_export($file, true).";\n"; } @@ -169,7 +166,6 @@ protected function filterFiles(array $files) '', $value->getClientOriginalName(), $value->getClientMimeType(), - 0, \UPLOAD_ERR_INI_SIZE, true ); @@ -178,7 +174,6 @@ protected function filterFiles(array $files) $value->getPathname(), $value->getClientOriginalName(), $value->getClientMimeType(), - $value->getClientSize(), $value->getError(), true ); diff --git a/vendor/symfony/http-kernel/Config/EnvParametersResource.php b/vendor/symfony/http-kernel/Config/EnvParametersResource.php deleted file mode 100644 index 26869ced..00000000 --- a/vendor/symfony/http-kernel/Config/EnvParametersResource.php +++ /dev/null @@ -1,105 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Config; - -use Symfony\Component\Config\Resource\SelfCheckingResourceInterface; - -/** - * EnvParametersResource represents resources stored in prefixed environment variables. - * - * @author Chris Wilkinson - * - * @deprecated since version 3.4, to be removed in 4.0 - */ -class EnvParametersResource implements SelfCheckingResourceInterface, \Serializable -{ - /** - * @var string - */ - private $prefix; - - /** - * @var string - */ - private $variables; - - /** - * @param string $prefix - */ - public function __construct($prefix) - { - $this->prefix = $prefix; - $this->variables = $this->findVariables(); - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return serialize($this->getResource()); - } - - /** - * @return array An array with two keys: 'prefix' for the prefix used and 'variables' containing all the variables watched by this resource - */ - public function getResource() - { - return ['prefix' => $this->prefix, 'variables' => $this->variables]; - } - - /** - * {@inheritdoc} - */ - public function isFresh($timestamp) - { - return $this->findVariables() === $this->variables; - } - - /** - * @internal - */ - public function serialize() - { - return serialize(['prefix' => $this->prefix, 'variables' => $this->variables]); - } - - /** - * @internal - */ - public function unserialize($serialized) - { - if (\PHP_VERSION_ID >= 70000) { - $unserialized = unserialize($serialized, ['allowed_classes' => false]); - } else { - $unserialized = unserialize($serialized); - } - - $this->prefix = $unserialized['prefix']; - $this->variables = $unserialized['variables']; - } - - private function findVariables() - { - $variables = []; - - foreach ($_SERVER as $key => $value) { - if (0 === strpos($key, $this->prefix)) { - $variables[$key] = $value; - } - } - - ksort($variables); - - return $variables; - } -} diff --git a/vendor/symfony/http-kernel/Config/FileLocator.php b/vendor/symfony/http-kernel/Config/FileLocator.php index fd5c8a32..2dda2347 100644 --- a/vendor/symfony/http-kernel/Config/FileLocator.php +++ b/vendor/symfony/http-kernel/Config/FileLocator.php @@ -22,19 +22,28 @@ class FileLocator extends BaseFileLocator { private $kernel; - private $path; /** - * @param KernelInterface $kernel A KernelInterface instance - * @param string|null $path The path the global resource directory - * @param array $paths An array of paths where to look for resources + * @deprecated since Symfony 4.4 */ - public function __construct(KernelInterface $kernel, $path = null, array $paths = []) + private $path; + + public function __construct(KernelInterface $kernel/* , string $path = null, array $paths = [], bool $triggerDeprecation = true */) { $this->kernel = $kernel; - if (null !== $path) { - $this->path = $path; - $paths[] = $path; + + if (2 <= \func_num_args()) { + $this->path = func_get_arg(1); + $paths = 3 <= \func_num_args() ? func_get_arg(2) : []; + if (null !== $this->path) { + $paths[] = $this->path; + } + + if (4 !== \func_num_args() || func_get_arg(3)) { + @trigger_error(sprintf('Passing more than one argument to %s is deprecated since Symfony 4.4 and will be removed in 5.0.', __METHOD__), \E_USER_DEPRECATED); + } + } else { + $paths = []; } parent::__construct($paths); @@ -46,9 +55,36 @@ public function __construct(KernelInterface $kernel, $path = null, array $paths public function locate($file, $currentPath = null, $first = true) { if (isset($file[0]) && '@' === $file[0]) { - return $this->kernel->locateResource($file, $this->path, $first); + return $this->kernel->locateResource($file, $this->path, $first, false); + } + + $locations = parent::locate($file, $currentPath, $first); + + if (isset($file[0]) && !( + '/' === $file[0] || '\\' === $file[0] + || (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && ('\\' === $file[2] || '/' === $file[2])) + || null !== parse_url($file, \PHP_URL_SCHEME) + )) { + $deprecation = false; + + // no need to trigger deprecations when the loaded file is given as absolute path + foreach ($this->paths as $deprecatedPath) { + foreach ((array) $locations as $location) { + if (null !== $currentPath && str_starts_with($location, $currentPath)) { + return $locations; + } + + if (str_starts_with($location, $deprecatedPath) && (null === $currentPath || !str_contains($location, $currentPath))) { + $deprecation = sprintf('Loading the file "%s" from the global resource directory "%s" is deprecated since Symfony 4.4 and will be removed in 5.0.', $file, $deprecatedPath); + } + } + } + + if ($deprecation) { + @trigger_error($deprecation, \E_USER_DEPRECATED); + } } - return parent::locate($file, $currentPath, $first); + return $locations; } } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver.php index 9d5f96ed..421d10f1 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver.php @@ -34,16 +34,16 @@ final class ArgumentResolver implements ArgumentResolverInterface */ private $argumentValueResolvers; - public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, $argumentValueResolvers = []) + public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = []) { - $this->argumentMetadataFactory = $argumentMetadataFactory ?: new ArgumentMetadataFactory(); + $this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory(); $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers(); } /** * {@inheritdoc} */ - public function getArguments(Request $request, $controller) + public function getArguments(Request $request, $controller): array { $arguments = []; @@ -55,14 +55,16 @@ public function getArguments(Request $request, $controller) $resolved = $resolver->resolve($request, $metadata); - if (!$resolved instanceof \Generator) { - throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', \get_class($resolver))); - } - + $atLeastOne = false; foreach ($resolved as $append) { + $atLeastOne = true; $arguments[] = $append; } + if (!$atLeastOne) { + throw new \InvalidArgumentException(sprintf('"%s::resolve()" must yield at least one value.', \get_class($resolver))); + } + // continue to the next controller argument continue 2; } @@ -81,7 +83,7 @@ public function getArguments(Request $request, $controller) return $arguments; } - public static function getDefaultArgumentValueResolvers() + public static function getDefaultArgumentValueResolvers(): iterable { return [ new RequestAttributeValueResolver(), diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php index e58fd3ab..32a0e071 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/DefaultValueResolver.php @@ -25,7 +25,7 @@ final class DefaultValueResolver implements ArgumentValueResolverInterface /** * {@inheritdoc} */ - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { return $argument->hasDefaultValue() || (null !== $argument->getType() && $argument->isNullable() && !$argument->isVariadic()); } @@ -33,7 +33,7 @@ public function supports(Request $request, ArgumentMetadata $argument) /** * {@inheritdoc} */ - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $argument->hasDefaultValue() ? $argument->getDefaultValue() : null; } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php new file mode 100644 index 00000000..48ea6e74 --- /dev/null +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; + +use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; + +/** + * Provides an intuitive error message when controller fails because it is not registered as a service. + * + * @author Simeon Kolev + */ +final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface +{ + private $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function supports(Request $request, ArgumentMetadata $argument): bool + { + $controller = $request->attributes->get('_controller'); + + if (\is_array($controller) && \is_callable($controller, true) && \is_string($controller[0])) { + $controller = $controller[0].'::'.$controller[1]; + } elseif (!\is_string($controller) || '' === $controller) { + return false; + } + + if ('\\' === $controller[0]) { + $controller = ltrim($controller, '\\'); + } + + if (!$this->container->has($controller) && false !== $i = strrpos($controller, ':')) { + $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); + } + + return false === $this->container->has($controller); + } + + /** + * {@inheritdoc} + */ + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + if (\is_array($controller = $request->attributes->get('_controller'))) { + $controller = $controller[0].'::'.$controller[1]; + } + + if ('\\' === $controller[0]) { + $controller = ltrim($controller, '\\'); + } + + if (!$this->container->has($controller)) { + $controller = (false !== $i = strrpos($controller, ':')) + ? substr($controller, 0, $i).strtolower(substr($controller, $i)) + : $controller.'::__invoke'; + } + + $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); + $message = sprintf('Could not resolve %s, maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?', $what); + + throw new RuntimeException($message); + } +} diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php index 05be372d..c62d327b 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestAttributeValueResolver.php @@ -25,7 +25,7 @@ final class RequestAttributeValueResolver implements ArgumentValueResolverInterf /** * {@inheritdoc} */ - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { return !$argument->isVariadic() && $request->attributes->has($argument->getName()); } @@ -33,7 +33,7 @@ public function supports(Request $request, ArgumentMetadata $argument) /** * {@inheritdoc} */ - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $request->attributes->get($argument->getName()); } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php index 2a5060a6..75cbd97e 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/RequestValueResolver.php @@ -25,7 +25,7 @@ final class RequestValueResolver implements ArgumentValueResolverInterface /** * {@inheritdoc} */ - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { return Request::class === $argument->getType() || is_subclass_of($argument->getType(), Request::class); } @@ -33,7 +33,7 @@ public function supports(Request $request, ArgumentMetadata $argument) /** * {@inheritdoc} */ - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $request; } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php index 3294ec86..4ffb8c99 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; @@ -33,7 +34,7 @@ public function __construct(ContainerInterface $container) /** * {@inheritdoc} */ - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { $controller = $request->attributes->get('_controller'); @@ -57,7 +58,7 @@ public function supports(Request $request, ArgumentMetadata $argument) /** * {@inheritdoc} */ - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { if (\is_array($controller = $request->attributes->get('_controller'))) { $controller = $controller[0].'::'.$controller[1]; @@ -72,6 +73,21 @@ public function resolve(Request $request, ArgumentMetadata $argument) $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } - yield $this->container->get($controller)->get($argument->getName()); + try { + yield $this->container->get($controller)->get($argument->getName()); + } catch (RuntimeException $e) { + $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); + $message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage()); + + if ($e->getMessage() === $message) { + $message = sprintf('Cannot resolve %s: %s', $what, $message); + } + + $r = new \ReflectionProperty($e, 'message'); + $r->setAccessible(true); + $r->setValue($e, $message); + + throw $e; + } } } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php index 9e656d28..a1e6b431 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php @@ -26,8 +26,12 @@ final class SessionValueResolver implements ArgumentValueResolverInterface /** * {@inheritdoc} */ - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { + if (!$request->hasSession()) { + return false; + } + $type = $argument->getType(); if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) { return false; @@ -39,7 +43,7 @@ public function supports(Request $request, ArgumentMetadata $argument) /** * {@inheritdoc} */ - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { yield $request->getSession(); } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php new file mode 100644 index 00000000..bde3c90c --- /dev/null +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * Provides timing information via the stopwatch. + * + * @author Iltar van der Berg + */ +final class TraceableValueResolver implements ArgumentValueResolverInterface +{ + private $inner; + private $stopwatch; + + public function __construct(ArgumentValueResolverInterface $inner, Stopwatch $stopwatch) + { + $this->inner = $inner; + $this->stopwatch = $stopwatch; + } + + /** + * {@inheritdoc} + */ + public function supports(Request $request, ArgumentMetadata $argument): bool + { + $method = \get_class($this->inner).'::'.__FUNCTION__; + $this->stopwatch->start($method, 'controller.argument_value_resolver'); + + $return = $this->inner->supports($request, $argument); + + $this->stopwatch->stop($method); + + return $return; + } + + /** + * {@inheritdoc} + */ + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + $method = \get_class($this->inner).'::'.__FUNCTION__; + $this->stopwatch->start($method, 'controller.argument_value_resolver'); + + yield from $this->inner->resolve($request, $argument); + + $this->stopwatch->stop($method); + } +} diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php index 7ee2d7af..ed61420e 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/VariadicValueResolver.php @@ -25,7 +25,7 @@ final class VariadicValueResolver implements ArgumentValueResolverInterface /** * {@inheritdoc} */ - public function supports(Request $request, ArgumentMetadata $argument) + public function supports(Request $request, ArgumentMetadata $argument): bool { return $argument->isVariadic() && $request->attributes->has($argument->getName()); } @@ -33,7 +33,7 @@ public function supports(Request $request, ArgumentMetadata $argument) /** * {@inheritdoc} */ - public function resolve(Request $request, ArgumentMetadata $argument) + public function resolve(Request $request, ArgumentMetadata $argument): iterable { $values = $request->attributes->get($argument->getName()); @@ -41,8 +41,6 @@ public function resolve(Request $request, ArgumentMetadata $argument) throw new \InvalidArgumentException(sprintf('The action argument "...$%1$s" is required to be an array, the request attribute "%1$s" contains a type of "%2$s" instead.', $argument->getName(), \gettype($values))); } - foreach ($values as $value) { - yield $value; - } + yield from $values; } } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php b/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php index 6b14ed5b..1317707b 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentValueResolverInterface.php @@ -31,7 +31,7 @@ public function supports(Request $request, ArgumentMetadata $argument); /** * Returns the possible value(s). * - * @return \Generator + * @return iterable */ public function resolve(Request $request, ArgumentMetadata $argument); } diff --git a/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php b/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php index b08877da..7eb028de 100644 --- a/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php @@ -14,7 +14,6 @@ use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Container; -use Symfony\Component\HttpFoundation\Request; /** * A controller resolver searching for a controller in a psr-11 container when using the "service:method" notation. @@ -33,58 +32,14 @@ public function __construct(ContainerInterface $container, LoggerInterface $logg parent::__construct($logger); } - /** - * {@inheritdoc} - */ - public function getController(Request $request) - { - $controller = parent::getController($request); - - if (\is_array($controller) && isset($controller[0]) && \is_string($controller[0]) && $this->container->has($controller[0])) { - $controller[0] = $this->instantiateController($controller[0]); - } - - return $controller; - } - - /** - * Returns a callable for the given controller. - * - * @param string $controller A Controller string - * - * @return mixed A PHP callable - * - * @throws \LogicException When the name could not be parsed - * @throws \InvalidArgumentException When the controller class does not exist - */ protected function createController($controller) { - if (false !== strpos($controller, '::')) { - return parent::createController($controller); - } - - $method = null; - if (1 == substr_count($controller, ':')) { - // controller in the "service:method" notation - list($controller, $method) = explode(':', $controller, 2); + if (1 === substr_count($controller, ':')) { + $controller = str_replace(':', '::', $controller); + // TODO deprecate this in 5.1 } - if (!$this->container->has($controller)) { - $this->throwExceptionIfControllerWasRemoved($controller); - - throw new \LogicException(sprintf('Controller not found: service "%s" does not exist.', $controller)); - } - - $service = $this->container->get($controller); - if (null !== $method) { - return [$service, $method]; - } - - if (!method_exists($service, '__invoke')) { - throw new \LogicException(sprintf('Controller "%s" cannot be called without a method name. Did you forget an "__invoke" method?', $controller)); - } - - return $service; + return parent::createController($controller); } /** @@ -92,30 +47,30 @@ protected function createController($controller) */ protected function instantiateController($class) { + $class = ltrim($class, '\\'); + if ($this->container->has($class)) { return $this->container->get($class); } try { return parent::instantiateController($class); - } catch (\ArgumentCountError $e) { - } catch (\ErrorException $e) { - } catch (\TypeError $e) { + } catch (\Error $e) { } $this->throwExceptionIfControllerWasRemoved($class, $e); - throw $e; + if ($e instanceof \ArgumentCountError) { + throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define the controller as a service?', $class), 0, $e); + } + + throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class.', $class), 0, $e); } - /** - * @param string $controller - * @param \Exception|\Throwable|null $previous - */ - private function throwExceptionIfControllerWasRemoved($controller, $previous = null) + private function throwExceptionIfControllerWasRemoved(string $controller, \Throwable $previous) { if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) { - throw new \LogicException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); + throw new \InvalidArgumentException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); } } } diff --git a/vendor/symfony/http-kernel/Controller/ControllerReference.php b/vendor/symfony/http-kernel/Controller/ControllerReference.php index e1e9c813..b4fdadd2 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerReference.php +++ b/vendor/symfony/http-kernel/Controller/ControllerReference.php @@ -35,7 +35,7 @@ class ControllerReference * @param array $attributes An array of parameters to add to the Request attributes * @param array $query An array of parameters to add to the Request query string */ - public function __construct($controller, array $attributes = [], array $query = []) + public function __construct(string $controller, array $attributes = [], array $query = []) { $this->controller = $controller; $this->attributes = $attributes; diff --git a/vendor/symfony/http-kernel/Controller/ControllerResolver.php b/vendor/symfony/http-kernel/Controller/ControllerResolver.php index 6248be18..7b8deeff 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/ControllerResolver.php @@ -16,44 +16,22 @@ /** * This implementation uses the '_controller' request attribute to determine - * the controller to execute and uses the request attributes to determine - * the controller method arguments. + * the controller to execute. * * @author Fabien Potencier + * @author Tobias Schultze */ -class ControllerResolver implements ArgumentResolverInterface, ControllerResolverInterface +class ControllerResolver implements ControllerResolverInterface { private $logger; - /** - * If the ...$arg functionality is available. - * - * Requires at least PHP 5.6.0 or HHVM 3.9.1 - * - * @var bool - */ - private $supportsVariadic; - - /** - * If scalar types exists. - * - * @var bool - */ - private $supportsScalarTypes; - public function __construct(LoggerInterface $logger = null) { $this->logger = $logger; - - $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic'); - $this->supportsScalarTypes = method_exists('ReflectionParameter', 'getType'); } /** * {@inheritdoc} - * - * This method looks for a '_controller' request attribute that represents - * the controller name (a string like ClassName::MethodName). */ public function getController(Request $request) { @@ -66,23 +44,42 @@ public function getController(Request $request) } if (\is_array($controller)) { + if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) { + try { + $controller[0] = $this->instantiateController($controller[0]); + } catch (\Error|\LogicException $e) { + try { + // We cannot just check is_callable but have to use reflection because a non-static method + // can still be called statically in PHP but we don't want that. This is deprecated in PHP 7, so we + // could simplify this with PHP 8. + if ((new \ReflectionMethod($controller[0], $controller[1]))->isStatic()) { + return $controller; + } + } catch (\ReflectionException $reflectionException) { + throw $e; + } + + throw $e; + } + } + + if (!\is_callable($controller)) { + throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$this->getControllerError($controller)); + } + return $controller; } if (\is_object($controller)) { - if (method_exists($controller, '__invoke')) { - return $controller; + if (!\is_callable($controller)) { + throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: '.$this->getControllerError($controller), $request->getPathInfo())); } - throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', \get_class($controller), $request->getPathInfo())); + return $controller; } - if (\is_string($controller) && false === strpos($controller, ':')) { - if (method_exists($controller, '__invoke')) { - return $this->instantiateController($controller); - } elseif (\function_exists($controller)) { - return $controller; - } + if (\function_exists($controller)) { + return $controller; } try { @@ -91,71 +88,11 @@ public function getController(Request $request) throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: ', $request->getPathInfo()).$e->getMessage(), 0, $e); } - return $callable; - } - - /** - * {@inheritdoc} - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Implement the ArgumentResolverInterface and inject it in the HttpKernel instead. - */ - public function getArguments(Request $request, $controller) - { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), \E_USER_DEPRECATED); - - if (\is_array($controller)) { - $r = new \ReflectionMethod($controller[0], $controller[1]); - } elseif (\is_object($controller) && !$controller instanceof \Closure) { - $r = new \ReflectionObject($controller); - $r = $r->getMethod('__invoke'); - } else { - $r = new \ReflectionFunction($controller); + if (!\is_callable($callable)) { + throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable: '.$this->getControllerError($callable), $request->getPathInfo())); } - return $this->doGetArguments($request, $controller, $r->getParameters()); - } - - /** - * @param callable $controller - * @param \ReflectionParameter[] $parameters - * - * @return array The arguments to use when calling the action - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Implement the ArgumentResolverInterface and inject it in the HttpKernel instead. - */ - protected function doGetArguments(Request $request, $controller, array $parameters) - { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), \E_USER_DEPRECATED); - - $attributes = $request->attributes->all(); - $arguments = []; - foreach ($parameters as $param) { - if (\array_key_exists($param->name, $attributes)) { - if ($this->supportsVariadic && $param->isVariadic() && \is_array($attributes[$param->name])) { - $arguments = array_merge($arguments, array_values($attributes[$param->name])); - } else { - $arguments[] = $attributes[$param->name]; - } - } elseif ($this->typeMatchesRequestClass($param, $request)) { - $arguments[] = $request; - } elseif ($param->isDefaultValueAvailable()) { - $arguments[] = $param->getDefaultValue(); - } elseif ($this->supportsScalarTypes && $param->hasType() && $param->allowsNull()) { - $arguments[] = null; - } else { - if (\is_array($controller)) { - $repr = sprintf('%s::%s()', \get_class($controller[0]), $controller[1]); - } elseif (\is_object($controller)) { - $repr = \get_class($controller); - } else { - $repr = $controller; - } - - throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->name)); - } - } - - return $arguments; + return $callable; } /** @@ -169,17 +106,31 @@ protected function doGetArguments(Request $request, $controller, array $paramete */ protected function createController($controller) { - if (false === strpos($controller, '::')) { - throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller)); - } + if (!str_contains($controller, '::')) { + $controller = $this->instantiateController($controller); - list($class, $method) = explode('::', $controller, 2); + if (!\is_callable($controller)) { + throw new \InvalidArgumentException($this->getControllerError($controller)); + } - if (!class_exists($class)) { - throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); + return $controller; } - $controller = [$this->instantiateController($class), $method]; + [$class, $method] = explode('::', $controller, 2); + + try { + $controller = [$this->instantiateController($class), $method]; + } catch (\Error|\LogicException $e) { + try { + if ((new \ReflectionMethod($class, $method))->isStatic()) { + return $class.'::'.$method; + } + } catch (\ReflectionException $reflectionException) { + throw $e; + } + + throw $e; + } if (!\is_callable($controller)) { throw new \InvalidArgumentException($this->getControllerError($controller)); @@ -200,31 +151,32 @@ protected function instantiateController($class) return new $class(); } - private function getControllerError($callable) + private function getControllerError($callable): string { if (\is_string($callable)) { - if (false !== strpos($callable, '::')) { - $callable = explode('::', $callable); + if (str_contains($callable, '::')) { + $callable = explode('::', $callable, 2); + } else { + return sprintf('Function "%s" does not exist.', $callable); } + } - if (class_exists($callable) && !method_exists($callable, '__invoke')) { - return sprintf('Class "%s" does not have a method "__invoke".', $callable); - } + if (\is_object($callable)) { + $availableMethods = $this->getClassMethodsWithoutMagicMethods($callable); + $alternativeMsg = $availableMethods ? sprintf(' or use one of the available methods: "%s"', implode('", "', $availableMethods)) : ''; - if (!\function_exists($callable)) { - return sprintf('Function "%s" does not exist.', $callable); - } + return sprintf('Controller class "%s" cannot be called without a method name. You need to implement "__invoke"%s.', \get_class($callable), $alternativeMsg); } if (!\is_array($callable)) { - return sprintf('Invalid type for controller given, expected string or array, got "%s".', \gettype($callable)); + return sprintf('Invalid type for controller given, expected string, array or object, got "%s".', \gettype($callable)); } - if (2 !== \count($callable)) { - return 'Invalid format for controller, expected [controller, method] or controller::method.'; + if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \count($callable)) { + return 'Invalid array callable, expected [controller, method].'; } - list($controller, $method) = $callable; + [$controller, $method] = $callable; if (\is_string($controller) && !class_exists($controller)) { return sprintf('Class "%s" does not exist.', $controller); @@ -236,14 +188,14 @@ private function getControllerError($callable) return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className); } - $collection = get_class_methods($controller); + $collection = $this->getClassMethodsWithoutMagicMethods($controller); $alternatives = []; foreach ($collection as $item) { $lev = levenshtein($method, $item); - if ($lev <= \strlen($method) / 3 || false !== strpos($item, $method)) { + if ($lev <= \strlen($method) / 3 || str_contains($item, $method)) { $alternatives[] = $item; } } @@ -261,21 +213,12 @@ private function getControllerError($callable) return $message; } - /** - * @return bool - */ - private function typeMatchesRequestClass(\ReflectionParameter $param, Request $request) + private function getClassMethodsWithoutMagicMethods($classOrObject): array { - if (!method_exists($param, 'getType')) { - return $param->getClass() && $param->getClass()->isInstance($request); - } - - if (!($type = $param->getType()) || $type->isBuiltin()) { - return false; - } - - $class = new \ReflectionClass($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type); + $methods = get_class_methods($classOrObject); - return $class && $class->isInstance($request); + return array_filter($methods, function (string $method) { + return 0 !== strncmp($method, '__', 2); + }); } } diff --git a/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php b/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php index 95c59036..8b70a88f 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php +++ b/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php @@ -17,8 +17,6 @@ * A ControllerResolverInterface implementation knows how to determine the * controller to execute based on a Request object. * - * It can also determine the arguments to pass to the Controller. - * * A Controller can be any valid PHP callable. * * @author Fabien Potencier @@ -37,21 +35,7 @@ interface ControllerResolverInterface * @return callable|false A PHP callable representing the Controller, * or false if this resolver is not able to determine the controller * - * @throws \LogicException If the controller can't be found + * @throws \LogicException If a controller was found based on the request but it is not callable */ public function getController(Request $request); - - /** - * Returns the arguments to pass to the controller. - * - * @param Request $request A Request instance - * @param callable $controller A PHP callable - * - * @return array An array of arguments to pass to the controller - * - * @throws \RuntimeException When value for argument given is not provided - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Please use the {@see ArgumentResolverInterface} instead. - */ - public function getArguments(Request $request, $controller); } diff --git a/vendor/symfony/http-kernel/Controller/ErrorController.php b/vendor/symfony/http-kernel/Controller/ErrorController.php new file mode 100644 index 00000000..b6c44010 --- /dev/null +++ b/vendor/symfony/http-kernel/Controller/ErrorController.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Controller; + +use Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\HttpException; +use Symfony\Component\HttpKernel\HttpKernelInterface; + +/** + * Renders error or exception pages from a given FlattenException. + * + * @author Yonel Ceruto + * @author Matthias Pigulla + */ +class ErrorController +{ + private $kernel; + private $controller; + private $errorRenderer; + + public function __construct(HttpKernelInterface $kernel, $controller, ErrorRendererInterface $errorRenderer) + { + $this->kernel = $kernel; + $this->controller = $controller; + $this->errorRenderer = $errorRenderer; + } + + public function __invoke(\Throwable $exception): Response + { + $exception = $this->errorRenderer->render($exception); + + return new Response($exception->getAsString(), $exception->getStatusCode(), $exception->getHeaders()); + } + + public function preview(Request $request, int $code): Response + { + /* + * This Request mimics the parameters set by + * \Symfony\Component\HttpKernel\EventListener\ErrorListener::duplicateRequest, with + * the additional "showException" flag. + */ + $subRequest = $request->duplicate(null, null, [ + '_controller' => $this->controller, + 'exception' => new HttpException($code, 'This is a sample exception.'), + 'logger' => null, + 'showException' => false, + ]); + + return $this->kernel->handle($subRequest, HttpKernelInterface::SUB_REQUEST); + } +} diff --git a/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php b/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php index 09701cfe..bf6b6aa1 100644 --- a/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php @@ -17,26 +17,15 @@ /** * @author Fabien Potencier */ -class TraceableControllerResolver implements ControllerResolverInterface, ArgumentResolverInterface +class TraceableControllerResolver implements ControllerResolverInterface { private $resolver; private $stopwatch; - private $argumentResolver; - public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch, ArgumentResolverInterface $argumentResolver = null) + public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch) { $this->resolver = $resolver; $this->stopwatch = $stopwatch; - $this->argumentResolver = $argumentResolver; - - // BC - if (null === $this->argumentResolver) { - $this->argumentResolver = $resolver; - } - - if (!$this->argumentResolver instanceof TraceableArgumentResolver) { - $this->argumentResolver = new TraceableArgumentResolver($this->argumentResolver, $this->stopwatch); - } } /** @@ -52,18 +41,4 @@ public function getController(Request $request) return $ret; } - - /** - * {@inheritdoc} - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. - */ - public function getArguments(Request $request, $controller) - { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Please use the %s instead.', __METHOD__, TraceableArgumentResolver::class), \E_USER_DEPRECATED); - - $ret = $this->argumentResolver->getArguments($request, $controller); - - return $ret; - } } diff --git a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php index 6df388d8..6fc7e703 100644 --- a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php +++ b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php @@ -25,15 +25,7 @@ class ArgumentMetadata private $defaultValue; private $isNullable; - /** - * @param string $name - * @param string $type - * @param bool $isVariadic - * @param bool $hasDefaultValue - * @param mixed $defaultValue - * @param bool $isNullable - */ - public function __construct($name, $type, $isVariadic, $hasDefaultValue, $defaultValue, $isNullable = false) + public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false) { $this->name = $name; $this->type = $type; diff --git a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php index 14e7ca3d..994d5310 100644 --- a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php +++ b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php @@ -18,118 +18,52 @@ */ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface { - /** - * If the ...$arg functionality is available. - * - * Requires at least PHP 5.6.0 or HHVM 3.9.1 - * - * @var bool - */ - private $supportsVariadic; - - /** - * If the reflection supports the getType() method to resolve types. - * - * Requires at least PHP 7.0.0 or HHVM 3.11.0 - * - * @var bool - */ - private $supportsParameterType; - - public function __construct() - { - $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic'); - $this->supportsParameterType = method_exists('ReflectionParameter', 'getType'); - } - /** * {@inheritdoc} */ - public function createArgumentMetadata($controller) + public function createArgumentMetadata($controller): array { $arguments = []; if (\is_array($controller)) { $reflection = new \ReflectionMethod($controller[0], $controller[1]); + $class = $reflection->class; } elseif (\is_object($controller) && !$controller instanceof \Closure) { - $reflection = (new \ReflectionObject($controller))->getMethod('__invoke'); + $reflection = new \ReflectionMethod($controller, '__invoke'); + $class = $reflection->class; } else { $reflection = new \ReflectionFunction($controller); + if ($class = str_contains($reflection->name, '{closure}') ? null : $reflection->getClosureScopeClass()) { + $class = $class->name; + } } foreach ($reflection->getParameters() as $param) { - $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $this->isVariadic($param), $this->hasDefaultValue($param), $this->getDefaultValue($param), $param->allowsNull()); + $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $class), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull()); } return $arguments; } - /** - * Returns whether an argument is variadic. - * - * @return bool - */ - private function isVariadic(\ReflectionParameter $parameter) - { - return $this->supportsVariadic && $parameter->isVariadic(); - } - - /** - * Determines whether an argument has a default value. - * - * @return bool - */ - private function hasDefaultValue(\ReflectionParameter $parameter) - { - return $parameter->isDefaultValueAvailable(); - } - - /** - * Returns a default value if available. - * - * @return mixed|null - */ - private function getDefaultValue(\ReflectionParameter $parameter) - { - return $this->hasDefaultValue($parameter) ? $parameter->getDefaultValue() : null; - } - /** * Returns an associated type to the given parameter if available. - * - * @return string|null */ - private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function) + private function getType(\ReflectionParameter $parameter, ?string $class): ?string { - if ($this->supportsParameterType) { - if (!$type = $parameter->getType()) { - return null; - } - $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - if ('array' === $name && !$type->isBuiltin()) { - // Special case for HHVM with variadics - return null; - } - } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $name)) { - $name = $name[1]; - } else { + if (!$type = $parameter->getType()) { return null; } - $lcName = strtolower($name); + $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - if ('self' !== $lcName && 'parent' !== $lcName) { - return $name; - } - if (!$function instanceof \ReflectionMethod) { - return null; - } - if ('self' === $lcName) { - return $function->getDeclaringClass()->name; - } - if ($parent = $function->getDeclaringClass()->getParentClass()) { - return $parent->name; + if (null !== $class) { + switch (strtolower($name)) { + case 'self': + return $class; + case 'parent': + return get_parent_class($class) ?: null; + } } - return null; + return $name; } } diff --git a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php index 6ea179d7..a34befc2 100644 --- a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php +++ b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactoryInterface.php @@ -19,7 +19,7 @@ interface ArgumentMetadataFactoryInterface { /** - * @param mixed $controller The controller to resolve the arguments for + * @param string|object|array $controller The controller to resolve the arguments for * * @return ArgumentMetadata[] */ diff --git a/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php b/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php index 370a874f..a134ebc2 100644 --- a/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/AjaxDataCollector.php @@ -18,10 +18,17 @@ * AjaxDataCollector. * * @author Bart van den Burg + * + * @final since Symfony 4.4 */ class AjaxDataCollector extends DataCollector { - public function collect(Request $request, Response $response, \Exception $exception = null) + /** + * {@inheritdoc} + * + * @param \Throwable|null $exception + */ + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { // all collecting is done client side } diff --git a/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php b/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php index 8ad6279e..91b62899 100644 --- a/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php @@ -15,10 +15,12 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\KernelInterface; -use Symfony\Component\VarDumper\Caster\LinkStub; +use Symfony\Component\VarDumper\Caster\ClassStub; /** * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface { @@ -28,17 +30,18 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte private $kernel; private $name; private $version; - private $hasVarDumper; - /** - * @param string $name The name of the application using the web profiler - * @param string $version The version of the application using the web profiler - */ - public function __construct($name = null, $version = null) + public function __construct(string $name = null, string $version = null) { + if (1 <= \func_num_args()) { + @trigger_error(sprintf('The "$name" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); + } + if (2 <= \func_num_args()) { + @trigger_error(sprintf('The "$version" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); + } + $this->name = $name; $this->version = $version; - $this->hasVarDumper = class_exists(LinkStub::class); } /** @@ -51,40 +54,41 @@ public function setKernel(KernelInterface $kernel = null) /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { + $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE); + $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE); + $this->data = [ 'app_name' => $this->name, 'app_version' => $this->version, 'token' => $response->headers->get('X-Debug-Token'), 'symfony_version' => Kernel::VERSION, - 'symfony_state' => 'unknown', - 'name' => isset($this->kernel) ? $this->kernel->getName() : 'n/a', + 'symfony_minor_version' => sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION), + 'symfony_lts' => 4 === Kernel::MINOR_VERSION, + 'symfony_state' => $this->determineSymfonyState(), + 'symfony_eom' => $eom->format('F Y'), + 'symfony_eol' => $eol->format('F Y'), 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a', 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a', 'php_version' => \PHP_VERSION, 'php_architecture' => \PHP_INT_SIZE * 8, - 'php_intl_locale' => class_exists('Locale', false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', + 'php_intl_locale' => class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', 'php_timezone' => date_default_timezone_get(), 'xdebug_enabled' => \extension_loaded('xdebug'), - 'apcu_enabled' => \extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), - 'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), + 'apcu_enabled' => \extension_loaded('apcu') && filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN), + 'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN), 'bundles' => [], 'sapi_name' => \PHP_SAPI, ]; if (isset($this->kernel)) { foreach ($this->kernel->getBundles() as $name => $bundle) { - $this->data['bundles'][$name] = $this->hasVarDumper ? new LinkStub($bundle->getPath()) : $bundle->getPath(); + $this->data['bundles'][$name] = new ClassStub(\get_class($bundle)); } - - $this->data['symfony_state'] = $this->determineSymfonyState(); - $this->data['symfony_minor_version'] = sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION); - $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE); - $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE); - $this->data['symfony_eom'] = $eom->format('F Y'); - $this->data['symfony_eol'] = $eol->format('F Y'); } if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) { @@ -106,13 +110,23 @@ public function lateCollect() $this->data = $this->cloneVar($this->data); } + /** + * @deprecated since Symfony 4.2 + */ public function getApplicationName() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); + return $this->data['app_name']; } + /** + * @deprecated since Symfony 4.2 + */ public function getApplicationVersion() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); + return $this->data['app_version']; } @@ -158,7 +172,15 @@ public function getSymfonyMinorVersion() } /** - * Returns the human redable date when this Symfony version ends its + * Returns if the current Symfony version is a Long-Term Support one. + */ + public function isSymfonyLts(): bool + { + return $this->data['symfony_lts']; + } + + /** + * Returns the human readable date when this Symfony version ends its * maintenance period. * * @return string @@ -169,7 +191,7 @@ public function getSymfonyEom() } /** - * Returns the human redable date when this Symfony version reaches its + * Returns the human readable date when this Symfony version reaches its * "end of life" and won't receive bugs or security fixes. * * @return string @@ -196,7 +218,7 @@ public function getPhpVersion() */ public function getPhpVersionExtra() { - return isset($this->data['php_version_extra']) ? $this->data['php_version_extra'] : null; + return $this->data['php_version_extra'] ?? null; } /** @@ -227,10 +249,14 @@ public function getPhpTimezone() * Gets the application name. * * @return string The application name + * + * @deprecated since Symfony 4.2 */ public function getAppName() { - return $this->data['name']; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), \E_USER_DEPRECATED); + + return 'n/a'; } /** @@ -311,7 +337,7 @@ public function getName() * * @return string One of: dev, stable, eom, eol */ - private function determineSymfonyState() + private function determineSymfonyState(): string { $now = new \DateTime(); $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month'); diff --git a/vendor/symfony/http-kernel/DataCollector/DataCollector.php b/vendor/symfony/http-kernel/DataCollector/DataCollector.php index 7119545b..3938dab6 100644 --- a/vendor/symfony/http-kernel/DataCollector/DataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DataCollector.php @@ -11,8 +11,8 @@ namespace Symfony\Component\HttpKernel\DataCollector; -use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter; use Symfony\Component\VarDumper\Caster\CutStub; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\Stub; @@ -26,33 +26,38 @@ * @author Fabien Potencier * @author Bernhard Schussek */ -abstract class DataCollector implements DataCollectorInterface, \Serializable +abstract class DataCollector implements DataCollectorInterface { /** * @var array|Data */ protected $data = []; - /** - * @var ValueExporter - */ - private $valueExporter; - /** * @var ClonerInterface */ private $cloner; + /** + * @deprecated since Symfony 4.3, store all the serialized state in the data property instead + */ public function serialize() { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), \E_USER_DEPRECATED); + $trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); $isCalledFromOverridingMethod = isset($trace[1]['function'], $trace[1]['object']) && 'serialize' === $trace[1]['function'] && $this === $trace[1]['object']; return $isCalledFromOverridingMethod ? $this->data : serialize($this->data); } + /** + * @deprecated since Symfony 4.3, store all the serialized state in the data property instead + */ public function unserialize($data) { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3, store all the serialized state in the data property instead.', __METHOD__), \E_USER_DEPRECATED); + $this->data = \is_array($data) ? $data : unserialize($data); } @@ -72,52 +77,20 @@ protected function cloneVar($var) return $var; } if (null === $this->cloner) { - if (class_exists(CutStub::class)) { - $this->cloner = new VarCloner(); - $this->cloner->setMaxItems(-1); - $this->cloner->addCasters($this->getCasters()); - } else { - @trigger_error(sprintf('Using the %s() method without the VarDumper component is deprecated since Symfony 3.2 and won\'t be supported in 4.0. Install symfony/var-dumper version 3.2 or above.', __METHOD__), \E_USER_DEPRECATED); - $this->cloner = false; - } - } - if (false === $this->cloner) { - if (null === $this->valueExporter) { - $this->valueExporter = new ValueExporter(); - } - - return $this->valueExporter->exportValue($var); + $this->cloner = new VarCloner(); + $this->cloner->setMaxItems(-1); + $this->cloner->addCasters($this->getCasters()); } return $this->cloner->cloneVar($var); } - /** - * Converts a PHP variable to a string. - * - * @param mixed $var A PHP variable - * - * @return string The string representation of the variable - * - * @deprecated since version 3.2, to be removed in 4.0. Use cloneVar() instead. - */ - protected function varToString($var) - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.2 and will be removed in 4.0. Use cloneVar() instead.', __METHOD__), \E_USER_DEPRECATED); - - if (null === $this->valueExporter) { - $this->valueExporter = new ValueExporter(); - } - - return $this->valueExporter->exportValue($var); - } - /** * @return callable[] The casters to add to the cloner */ protected function getCasters() { - return [ + $casters = [ '*' => function ($v, array $a, Stub $s, $isNested) { if (!$v instanceof Stub) { foreach ($a as $k => $v) { @@ -129,6 +102,33 @@ protected function getCasters() return $a; }, - ]; + ] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO; + + return $casters; + } + + /** + * @return array + */ + public function __sleep() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), \E_USER_DEPRECATED); + $this->data = $this->serialize(); + } + + return ['data']; + } + + public function __wakeup() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'unserialize'))->getDeclaringClass()->name) { + if (\is_object($this->data)) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + @trigger_error(sprintf('Implementing the "%s::unserialize()" method is deprecated since Symfony 4.3, store all the serialized state in the "data" property instead.', $c), \E_USER_DEPRECATED); + $this->unserialize($this->data); + } } } diff --git a/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php b/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php index 2470089b..2ee955ba 100644 --- a/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php +++ b/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php @@ -13,20 +13,21 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\Service\ResetInterface; /** * DataCollectorInterface. * * @author Fabien Potencier - * - * @method reset() Resets this data collector to its initial state. */ -interface DataCollectorInterface +interface DataCollectorInterface extends ResetInterface { /** * Collects data for the given Request and Response. + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null); + public function collect(Request $request, Response $response/* , \Throwable $exception = null */); /** * Returns the name of the collector. diff --git a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php index e5c276de..155d41c3 100644 --- a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php @@ -14,16 +14,20 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; use Symfony\Component\VarDumper\Dumper\HtmlDumper; -use Twig\Template; +use Symfony\Component\VarDumper\Server\Connection; /** * @author Nicolas Grekas + * + * @final since Symfony 4.3 */ class DumpDataCollector extends DataCollector implements DataDumperInterface { @@ -37,16 +41,20 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface private $charset; private $requestStack; private $dumper; - private $dumperIsInjected; + private $sourceContextProvider; - public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, $charset = null, RequestStack $requestStack = null, DataDumperInterface $dumper = null) + /** + * @param string|FileLinkFormatter|null $fileLinkFormat + * @param DataDumperInterface|Connection|null $dumper + */ + public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, $dumper = null) { + $fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); $this->stopwatch = $stopwatch; - $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); - $this->charset = $charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'; + $this->fileLinkFormat = $fileLinkFormat instanceof FileLinkFormatter && false === $fileLinkFormat->format('', 0) ? false : $fileLinkFormat; + $this->charset = $charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'; $this->requestStack = $requestStack; $this->dumper = $dumper; - $this->dumperIsInjected = null !== $dumper; // All clones share these properties by reference: $this->rootRefs = [ @@ -55,6 +63,8 @@ public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, &$this->isCollected, &$this->clonesCount, ]; + + $this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset); } public function __clone() @@ -67,67 +77,22 @@ public function dump(Data $data) if ($this->stopwatch) { $this->stopwatch->start('dump'); } - if ($this->isCollected && !$this->dumper) { - $this->isCollected = false; - } - $trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, 7); - - $file = $trace[0]['file']; - $line = $trace[0]['line']; - $name = false; - $fileExcerpt = false; - - for ($i = 1; $i < 7; ++$i) { - if (isset($trace[$i]['class'], $trace[$i]['function']) - && 'dump' === $trace[$i]['function'] - && 'Symfony\Component\VarDumper\VarDumper' === $trace[$i]['class'] - ) { - $file = $trace[$i]['file']; - $line = $trace[$i]['line']; - - while (++$i < 7) { - if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos($trace[$i]['function'], 'call_user_func')) { - $file = $trace[$i]['file']; - $line = $trace[$i]['line']; - - break; - } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof Template) { - $template = $trace[$i]['object']; - $name = $template->getTemplateName(); - $src = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : false); - $info = $template->getDebugInfo(); - if (isset($info[$trace[$i - 1]['line']])) { - $line = $info[$trace[$i - 1]['line']]; - $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; - - if ($src) { - $src = explode("\n", $src); - $fileExcerpt = []; - - for ($i = max($line - 3, 1), $max = min($line + 3, \count($src)); $i <= $max; ++$i) { - $fileExcerpt[] = ''.$this->htmlEncode($src[$i - 1]).'
  • '; - } - - $fileExcerpt = '
      '.implode("\n", $fileExcerpt).'
    '; - } - } - break; - } - } - break; - } - } + ['name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt] = $this->sourceContextProvider->getContext(); - if (false === $name) { - $name = str_replace('\\', '/', $file); - $name = substr($name, strrpos($name, '/') + 1); + if ($this->dumper instanceof Connection) { + if (!$this->dumper->write($data)) { + $this->isCollected = false; + } + } elseif ($this->dumper) { + $this->doDump($this->dumper, $data, $name, $file, $line); + } else { + $this->isCollected = false; } - if ($this->dumper) { - $this->doDump($data, $name, $file, $line); + if (!$this->dataCount) { + $this->data = []; } - $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt'); ++$this->dataCount; @@ -136,8 +101,17 @@ public function dump(Data $data) } } - public function collect(Request $request, Response $response, \Exception $exception = null) + /** + * {@inheritdoc} + * + * @param \Throwable|null $exception + */ + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { + if (!$this->dataCount) { + $this->data = []; + } + // Sub-requests and programmatic calls stay in the collected profile. if ($this->dumper || ($this->requestStack && $this->requestStack->getMasterRequest() !== $request) || $request->isXmlHttpRequest() || $request->headers->has('Origin')) { return; @@ -147,19 +121,22 @@ public function collect(Request $request, Response $response, \Exception $except if (!$this->requestStack || !$response->headers->has('X-Debug-Token') || $response->isRedirection() - || ($response->headers->has('Content-Type') && false === strpos($response->headers->get('Content-Type'), 'html')) + || ($response->headers->has('Content-Type') && !str_contains($response->headers->get('Content-Type'), 'html')) || 'html' !== $request->getRequestFormat() || false === strripos($response->getContent(), '') ) { - if ($response->headers->has('Content-Type') && false !== strpos($response->headers->get('Content-Type'), 'html')) { - $this->dumper = new HtmlDumper('php://output', $this->charset); - $this->dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); + if ($response->headers->has('Content-Type') && str_contains($response->headers->get('Content-Type'), 'html')) { + $dumper = new HtmlDumper('php://output', $this->charset); + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { - $this->dumper = new CliDumper('php://output', $this->charset); + $dumper = new CliDumper('php://output', $this->charset); + if (method_exists($dumper, 'setDisplayOptions')) { + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); + } } foreach ($this->data as $dump) { - $this->doDump($dump['data'], $dump['name'], $dump['file'], $dump['line']); + $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']); } } } @@ -176,32 +153,44 @@ public function reset() $this->clonesIndex = 0; } - public function serialize() + /** + * @internal + */ + public function __sleep(): array { + if (!$this->dataCount) { + $this->data = []; + } + if ($this->clonesCount !== $this->clonesIndex) { - return 'a:0:{}'; + return []; } $this->data[] = $this->fileLinkFormat; $this->data[] = $this->charset; - $ser = serialize($this->data); - $this->data = []; $this->dataCount = 0; $this->isCollected = true; - if (!$this->dumperIsInjected) { - $this->dumper = null; - } - return $ser; + return parent::__sleep(); } - public function unserialize($data) + /** + * @internal + */ + public function __wakeup() { - $this->data = unserialize($data); + parent::__wakeup(); + $charset = array_pop($this->data); $fileLinkFormat = array_pop($this->data); $this->dataCount = \count($this->data); - self::__construct($this->stopwatch, $fileLinkFormat, $charset); + foreach ($this->data as $dump) { + if (!\is_string($dump['name']) || !\is_string($dump['file']) || !\is_int($dump['line'])) { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + } + + self::__construct($this->stopwatch, \is_string($fileLinkFormat) || $fileLinkFormat instanceof FileLinkFormatter ? $fileLinkFormat : null, \is_string($charset) ? $charset : null); } public function getDumpsCount() @@ -211,7 +200,7 @@ public function getDumpsCount() public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1) { - $data = fopen('php://memory', 'r+b'); + $data = fopen('php://memory', 'r+'); if ('html' === $format) { $dumper = new HtmlDumper($data, $this->charset); @@ -221,6 +210,10 @@ public function getDumps($format, $maxDepthLimit = -1, $maxItemsPerDepth = -1) } $dumps = []; + if (!$this->dataCount) { + return $this->data = []; + } + foreach ($this->data as $dump) { $dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth)); $dump['data'] = stream_get_contents($data, -1, 0); @@ -239,27 +232,30 @@ public function getName() public function __destruct() { - if (0 === $this->clonesCount-- && !$this->isCollected && $this->data) { + if (0 === $this->clonesCount-- && !$this->isCollected && $this->dataCount) { $this->clonesCount = 0; $this->isCollected = true; $h = headers_list(); $i = \count($h); - array_unshift($h, 'Content-Type: '.ini_get('default_mimetype')); + array_unshift($h, 'Content-Type: '.\ini_get('default_mimetype')); while (0 !== stripos($h[$i], 'Content-Type:')) { --$i; } if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && stripos($h[$i], 'html')) { - $this->dumper = new HtmlDumper('php://output', $this->charset); - $this->dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); + $dumper = new HtmlDumper('php://output', $this->charset); + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { - $this->dumper = new CliDumper('php://output', $this->charset); + $dumper = new CliDumper('php://output', $this->charset); + if (method_exists($dumper, 'setDisplayOptions')) { + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); + } } foreach ($this->data as $i => $dump) { $this->data[$i] = null; - $this->doDump($dump['data'], $dump['name'], $dump['file'], $dump['line']); + $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']); } $this->data = []; @@ -267,9 +263,9 @@ public function __destruct() } } - private function doDump($data, $name, $file, $line) + private function doDump(DataDumperInterface $dumper, Data $data, string $name, string $file, int $line) { - if ($this->dumper instanceof CliDumper) { + if ($dumper instanceof CliDumper) { $contextDumper = function ($name, $file, $line, $fmt) { if ($this instanceof HtmlDumper) { if ($file) { @@ -290,26 +286,12 @@ private function doDump($data, $name, $file, $line) } $this->dumpLine(0); }; - $contextDumper = $contextDumper->bindTo($this->dumper, $this->dumper); + $contextDumper = $contextDumper->bindTo($dumper, $dumper); $contextDumper($name, $file, $line, $this->fileLinkFormat); } else { $cloner = new VarCloner(); - $this->dumper->dump($cloner->cloneVar($name.' on line '.$line.':')); + $dumper->dump($cloner->cloneVar($name.' on line '.$line.':')); } - $this->dumper->dump($data); - } - - private function htmlEncode($s) - { - $html = ''; - - $dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset); - $dumper->setDumpHeader(''); - $dumper->setDumpBoundaries('', ''); - - $cloner = new VarCloner(); - $dumper->dump($cloner->cloneVar($s)); - - return substr(strip_tags($html), 1, -1); + $dumper->dump($data); } } diff --git a/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php b/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php index e3f8576c..24ed5596 100644 --- a/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php @@ -11,36 +11,45 @@ namespace Symfony\Component\HttpKernel\DataCollector; +use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Service\ResetInterface; /** * EventDataCollector. * * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class EventDataCollector extends DataCollector implements LateDataCollectorInterface { protected $dispatcher; + private $requestStack; + private $currentRequest; - public function __construct(EventDispatcherInterface $dispatcher = null) + public function __construct(EventDispatcherInterface $dispatcher = null, RequestStack $requestStack = null) { - if ($dispatcher instanceof TraceableEventDispatcherInterface && !method_exists($dispatcher, 'reset')) { - @trigger_error(sprintf('Implementing "%s" without the "reset()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".', TraceableEventDispatcherInterface::class, \get_class($dispatcher)), \E_USER_DEPRECATED); - } $this->dispatcher = $dispatcher; + $this->requestStack = $requestStack; } /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { + $this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null; $this->data = [ 'called_listeners' => [], 'not_called_listeners' => [], + 'orphaned_events' => [], ]; } @@ -48,11 +57,7 @@ public function reset() { $this->data = []; - if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { - if (!method_exists($this->dispatcher, 'reset')) { - return; // @deprecated - } - + if ($this->dispatcher instanceof ResetInterface) { $this->dispatcher->reset(); } } @@ -60,9 +65,14 @@ public function reset() public function lateCollect() { if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { - $this->setCalledListeners($this->dispatcher->getCalledListeners()); - $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners()); + $this->setCalledListeners($this->dispatcher->getCalledListeners($this->currentRequest)); + $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners($this->currentRequest)); + } + + if ($this->dispatcher instanceof TraceableEventDispatcher) { + $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest)); } + $this->data = $this->cloneVar($this->data); } @@ -71,7 +81,7 @@ public function lateCollect() * * @param array $listeners An array of called listeners * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function setCalledListeners(array $listeners) { @@ -83,7 +93,7 @@ public function setCalledListeners(array $listeners) * * @return array An array of called listeners * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function getCalledListeners() { @@ -93,9 +103,7 @@ public function getCalledListeners() /** * Sets the not called listeners. * - * @param array $listeners An array of not called listeners - * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function setNotCalledListeners(array $listeners) { @@ -105,15 +113,39 @@ public function setNotCalledListeners(array $listeners) /** * Gets the not called listeners. * - * @return array An array of not called listeners + * @return array * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function getNotCalledListeners() { return $this->data['not_called_listeners']; } + /** + * Sets the orphaned events. + * + * @param array $events An array of orphaned events + * + * @see TraceableEventDispatcher + */ + public function setOrphanedEvents(array $events) + { + $this->data['orphaned_events'] = $events; + } + + /** + * Gets the orphaned events. + * + * @return array An array of orphaned events + * + * @see TraceableEventDispatcher + */ + public function getOrphanedEvents() + { + return $this->data['orphaned_events']; + } + /** * {@inheritdoc} */ diff --git a/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php b/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php index f9be5bdd..9868659b 100644 --- a/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/ExceptionDataCollector.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel\DataCollector; -use Symfony\Component\Debug\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -19,17 +19,23 @@ * ExceptionDataCollector. * * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class ExceptionDataCollector extends DataCollector { /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { + $exception = 2 < \func_num_args() ? func_get_arg(2) : null; + if (null !== $exception) { $this->data = [ - 'exception' => FlattenException::create($exception), + 'exception' => FlattenException::createFromThrowable($exception), ]; } } diff --git a/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php b/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php index c2c337a0..849adfd8 100644 --- a/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php @@ -11,40 +11,42 @@ namespace Symfony\Component\HttpKernel\DataCollector; -use Symfony\Component\Debug\Exception\SilencedErrorContext; +use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; /** - * LogDataCollector. - * * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class LoggerDataCollector extends DataCollector implements LateDataCollectorInterface { private $logger; private $containerPathPrefix; + private $currentRequest; + private $requestStack; - public function __construct($logger = null, $containerPathPrefix = null) + public function __construct($logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null) { if (null !== $logger && $logger instanceof DebugLoggerInterface) { - if (!method_exists($logger, 'clear')) { - @trigger_error(sprintf('Implementing "%s" without the "clear()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".', DebugLoggerInterface::class, \get_class($logger)), \E_USER_DEPRECATED); - } - $this->logger = $logger; } $this->containerPathPrefix = $containerPathPrefix; + $this->requestStack = $requestStack; } /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { - // everything is done as late as possible + $this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null; } /** @@ -52,7 +54,7 @@ public function collect(Request $request, Response $response, \Exception $except */ public function reset() { - if ($this->logger && method_exists($this->logger, 'clear')) { + if ($this->logger instanceof DebugLoggerInterface) { $this->logger->clear(); } $this->data = []; @@ -66,45 +68,48 @@ public function lateCollect() if (null !== $this->logger) { $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); - $this->data['compiler_logs'] = $this->getContainerCompilerLogs(); - $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs(), $containerDeprecationLogs)); + // get compiler logs later (only when they are needed) to improve performance + $this->data['compiler_logs'] = []; + $this->data['compiler_logs_filepath'] = $this->containerPathPrefix.'Compiler.log'; + $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs)); $this->data = $this->cloneVar($this->data); } + $this->currentRequest = null; } public function getLogs() { - return isset($this->data['logs']) ? $this->data['logs'] : []; + return $this->data['logs'] ?? []; } public function getPriorities() { - return isset($this->data['priorities']) ? $this->data['priorities'] : []; + return $this->data['priorities'] ?? []; } public function countErrors() { - return isset($this->data['error_count']) ? $this->data['error_count'] : 0; + return $this->data['error_count'] ?? 0; } public function countDeprecations() { - return isset($this->data['deprecation_count']) ? $this->data['deprecation_count'] : 0; + return $this->data['deprecation_count'] ?? 0; } public function countWarnings() { - return isset($this->data['warning_count']) ? $this->data['warning_count'] : 0; + return $this->data['warning_count'] ?? 0; } public function countScreams() { - return isset($this->data['scream_count']) ? $this->data['scream_count'] : 0; + return $this->data['scream_count'] ?? 0; } public function getCompilerLogs() { - return isset($this->data['compiler_logs']) ? $this->data['compiler_logs'] : []; + return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null)); } /** @@ -115,7 +120,7 @@ public function getName() return 'logger'; } - private function getContainerDeprecationLogs() + private function getContainerDeprecationLogs(): array { if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Deprecations.log')) { return []; @@ -132,7 +137,7 @@ private function getContainerDeprecationLogs() $log['timestamp'] = $bootTime; $log['priority'] = 100; $log['priorityName'] = 'DEBUG'; - $log['channel'] = '-'; + $log['channel'] = null; $log['scream'] = false; unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']); $logs[] = $log; @@ -141,14 +146,14 @@ private function getContainerDeprecationLogs() return $logs; } - private function getContainerCompilerLogs() + private function getContainerCompilerLogs(string $compilerLogsFilepath = null): array { - if (null === $this->containerPathPrefix || !file_exists($file = $this->containerPathPrefix.'Compiler.log')) { + if (!file_exists($compilerLogsFilepath)) { return []; } $logs = []; - foreach (file($file, \FILE_IGNORE_NEW_LINES) as $log) { + foreach (file($compilerLogsFilepath, \FILE_IGNORE_NEW_LINES) as $log) { $log = explode(': ', $log, 2); if (!isset($log[1]) || !preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+(?:\\\\[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+)++$/', $log[0])) { $log = ['Unknown Compiler Pass', implode(': ', $log)]; @@ -160,7 +165,7 @@ private function getContainerCompilerLogs() return $logs; } - private function sanitizeLogs($logs) + private function sanitizeLogs(array $logs) { $sanitizedLogs = []; $silencedLogs = []; @@ -209,7 +214,7 @@ private function sanitizeLogs($logs) return array_values($sanitizedLogs); } - private function isSilencedOrDeprecationErrorLog(array $log) + private function isSilencedOrDeprecationErrorLog(array $log): bool { if (!isset($log['context']['exception'])) { return false; @@ -228,18 +233,18 @@ private function isSilencedOrDeprecationErrorLog(array $log) return false; } - private function computeErrorsCount(array $containerDeprecationLogs) + private function computeErrorsCount(array $containerDeprecationLogs): array { $silencedLogs = []; $count = [ - 'error_count' => $this->logger->countErrors(), + 'error_count' => $this->logger->countErrors($this->currentRequest), 'deprecation_count' => 0, 'warning_count' => 0, 'scream_count' => 0, 'priorities' => [], ]; - foreach ($this->logger->getLogs() as $log) { + foreach ($this->logger->getLogs($this->currentRequest) as $log) { if (isset($count['priorities'][$log['priority']])) { ++$count['priorities'][$log['priority']]['count']; } else { diff --git a/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php b/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php index 7a6e1c06..f6015baf 100644 --- a/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/MemoryDataCollector.php @@ -18,6 +18,8 @@ * MemoryDataCollector. * * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class MemoryDataCollector extends DataCollector implements LateDataCollectorInterface { @@ -28,8 +30,10 @@ public function __construct() /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { $this->updateMemoryUsage(); } @@ -41,7 +45,7 @@ public function reset() { $this->data = [ 'memory' => 0, - 'memory_limit' => $this->convertToBytes(ini_get('memory_limit')), + 'memory_limit' => $this->convertToBytes(\ini_get('memory_limit')), ]; } @@ -89,7 +93,10 @@ public function getName() return 'memory'; } - private function convertToBytes($memoryLimit) + /** + * @return int|float + */ + private function convertToBytes(string $memoryLimit) { if ('-1' === $memoryLimit) { return -1; @@ -97,9 +104,9 @@ private function convertToBytes($memoryLimit) $memoryLimit = strtolower($memoryLimit); $max = strtolower(ltrim($memoryLimit, '+')); - if (0 === strpos($max, '0x')) { + if (str_starts_with($max, '0x')) { $max = \intval($max, 16); - } elseif (0 === strpos($max, '0')) { + } elseif (str_starts_with($max, '0')) { $max = \intval($max, 8); } else { $max = (int) $max; diff --git a/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php b/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php index 41372a56..2147c678 100644 --- a/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php @@ -22,6 +22,8 @@ /** * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class RequestDataCollector extends DataCollector implements EventSubscriberInterface, LateDataCollectorInterface { @@ -34,8 +36,10 @@ public function __construct() /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { // attributes are serialized and as they can be anything, they need to be converted to strings. $attributes = []; @@ -49,12 +53,7 @@ public function collect(Request $request, Response $response, \Exception $except } } - try { - $content = $request->getContent(); - } catch (\LogicException $e) { - // the user already got the request content as a resource - $content = false; - } + $content = $request->getContent(); $sessionMetadata = []; $sessionAttributes = []; @@ -77,15 +76,23 @@ public function collect(Request $request, Response $response, \Exception $except $responseCookies[$cookie->getName()] = $cookie; } + $dotenvVars = []; + foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) { + if ('' !== $name && isset($_ENV[$name])) { + $dotenvVars[$name] = $_ENV[$name]; + } + } + $this->data = [ 'method' => $request->getMethod(), 'format' => $request->getRequestFormat(), 'content' => $content, 'content_type' => $response->headers->get('Content-Type', 'text/html'), - 'status_text' => isset(Response::$statusTexts[$statusCode]) ? Response::$statusTexts[$statusCode] : '', + 'status_text' => Response::$statusTexts[$statusCode] ?? '', 'status_code' => $statusCode, 'request_query' => $request->query->all(), 'request_request' => $request->request->all(), + 'request_files' => $request->files->all(), 'request_headers' => $request->headers->all(), 'request_server' => $request->server->all(), 'request_cookies' => $request->cookies->all(), @@ -99,6 +106,7 @@ public function collect(Request $request, Response $response, \Exception $except 'path_info' => $request->getPathInfo(), 'controller' => 'n/a', 'locale' => $request->getLocale(), + 'dotenv_vars' => $dotenvVars, ]; if (isset($this->data['request_headers']['php-auth-pw'])) { @@ -142,12 +150,17 @@ public function collect(Request $request, Response $response, \Exception $except 'method' => $request->getMethod(), 'controller' => $this->parseController($request->attributes->get('_controller')), 'status_code' => $statusCode, - 'status_text' => Response::$statusTexts[(int) $statusCode], - ]) + 'status_text' => Response::$statusTexts[$statusCode], + ]), + 0, '/', null, $request->isSecure(), true, false, 'lax' )); } $this->data['identifier'] = $this->data['route'] ?: (\is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']); + + if ($response->headers->has('x-previous-debug-token')) { + $this->data['forward_token'] = $response->headers->get('x-previous-debug-token'); + } } public function lateCollect() @@ -181,6 +194,11 @@ public function getRequestQuery() return new ParameterBag($this->data['request_query']->getValue()); } + public function getRequestFiles() + { + return new ParameterBag($this->data['request_files']->getValue()); + } + public function getRequestHeaders() { return new ParameterBag($this->data['request_headers']->getValue()); @@ -231,6 +249,18 @@ public function getContent() return $this->data['content']; } + public function isJsonRequest() + { + return 1 === preg_match('{^application/(?:\w+\++)*json$}i', $this->data['request_headers']['content-type']); + } + + public function getPrettyJson() + { + $decoded = json_decode($this->getContent()); + + return \JSON_ERROR_NONE === json_last_error() ? json_encode($decoded, \JSON_PRETTY_PRINT) : null; + } + public function getContentType() { return $this->data['content_type']; @@ -256,6 +286,11 @@ public function getLocale() return $this->data['locale']; } + public function getDotenvVars() + { + return new ParameterBag($this->data['dotenv_vars']->getValue()); + } + /** * Gets the route name. * @@ -304,14 +339,25 @@ public function getController() */ public function getRedirect() { - return isset($this->data['redirect']) ? $this->data['redirect'] : false; + return $this->data['redirect'] ?? false; } + public function getForwardToken() + { + return $this->data['forward_token'] ?? null; + } + + /** + * @final since Symfony 4.3 + */ public function onKernelController(FilterControllerEvent $event) { $this->controllers[$event->getRequest()] = $event->getController(); } + /** + * @final since Symfony 4.3 + */ public function onKernelResponse(FilterResponseEvent $event) { if (!$event->isMasterRequest()) { @@ -342,13 +388,13 @@ public function getName() /** * Parse a controller. * - * @param mixed $controller The controller to parse + * @param string|object|array|null $controller The controller to parse * * @return array|string An array of controller data or a simple string */ protected function parseController($controller) { - if (\is_string($controller) && false !== strpos($controller, '::')) { + if (\is_string($controller) && str_contains($controller, '::')) { $controller = explode('::', $controller); } @@ -385,7 +431,7 @@ protected function parseController($controller) 'line' => $r->getStartLine(), ]; - if (false !== strpos($r->name, '{closure}')) { + if (str_contains($r->name, '{closure}')) { return $controller; } $controller['method'] = $r->name; diff --git a/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php b/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php index 432dc361..8ff676cc 100644 --- a/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php @@ -17,8 +17,6 @@ use Symfony\Component\HttpKernel\Event\FilterControllerEvent; /** - * RouterDataCollector. - * * @author Fabien Potencier */ class RouterDataCollector extends DataCollector @@ -35,8 +33,12 @@ public function __construct() /** * {@inheritdoc} + * + * @param \Throwable|null $exception + * + * @final since Symfony 4.4 */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { if ($response instanceof RedirectResponse) { $this->data['redirect'] = true; @@ -68,6 +70,8 @@ protected function guessRoute(Request $request, $controller) /** * Remembers the controller associated to each request. + * + * @final since Symfony 4.3 */ public function onKernelController(FilterControllerEvent $event) { diff --git a/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php b/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php index cb490c2b..c6166c8a 100644 --- a/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/TimeDataCollector.php @@ -19,6 +19,8 @@ /** * @author Fabien Potencier + * + * @final since Symfony 4.4 */ class TimeDataCollector extends DataCollector implements LateDataCollectorInterface { @@ -33,8 +35,10 @@ public function __construct(KernelInterface $kernel = null, Stopwatch $stopwatch /** * {@inheritdoc} + * + * @param \Throwable|null $exception */ - public function collect(Request $request, Response $response, \Exception $exception = null) + public function collect(Request $request, Response $response/* , \Throwable $exception = null */) { if (null !== $this->kernel) { $startTime = $this->kernel->getStartTime(); @@ -43,7 +47,7 @@ public function collect(Request $request, Response $response, \Exception $except } $this->data = [ - 'token' => $response->headers->get('X-Debug-Token'), + 'token' => $request->attributes->get('_stopwatch_token'), 'start_time' => $startTime * 1000, 'events' => [], 'stopwatch_installed' => class_exists(Stopwatch::class, false), diff --git a/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php b/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php deleted file mode 100644 index f84aeeae..00000000 --- a/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php +++ /dev/null @@ -1,99 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\DataCollector\Util; - -@trigger_error('The '.__NAMESPACE__.'\ValueExporter class is deprecated since Symfony 3.2 and will be removed in 4.0. Use the VarDumper component instead.', \E_USER_DEPRECATED); - -/** - * @author Bernhard Schussek - * - * @deprecated since version 3.2, to be removed in 4.0. Use the VarDumper component instead. - */ -class ValueExporter -{ - /** - * Converts a PHP value to a string. - * - * @param mixed $value The PHP value - * @param int $depth Only for internal usage - * @param bool $deep Only for internal usage - * - * @return string The string representation of the given value - */ - public function exportValue($value, $depth = 1, $deep = false) - { - if ($value instanceof \__PHP_Incomplete_Class) { - return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($value)); - } - - if (\is_object($value)) { - if ($value instanceof \DateTimeInterface) { - return sprintf('Object(%s) - %s', \get_class($value), $value->format(\DateTime::ATOM)); - } - - return sprintf('Object(%s)', \get_class($value)); - } - - if (\is_array($value)) { - if (empty($value)) { - return '[]'; - } - - $indent = str_repeat(' ', $depth); - - $a = []; - foreach ($value as $k => $v) { - if (\is_array($v)) { - $deep = true; - } - $a[] = sprintf('%s => %s', $k, $this->exportValue($v, $depth + 1, $deep)); - } - - if ($deep) { - return sprintf("[\n%s%s\n%s]", $indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1)); - } - - $s = sprintf('[%s]', implode(', ', $a)); - - if (80 > \strlen($s)) { - return $s; - } - - return sprintf("[\n%s%s\n]", $indent, implode(sprintf(",\n%s", $indent), $a)); - } - - if (\is_resource($value)) { - return sprintf('Resource(%s#%d)', get_resource_type($value), $value); - } - - if (null === $value) { - return 'null'; - } - - if (false === $value) { - return 'false'; - } - - if (true === $value) { - return 'true'; - } - - return (string) $value; - } - - private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value) - { - $array = new \ArrayObject($value); - - return $array['__PHP_Incomplete_Class_Name']; - } -} diff --git a/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php b/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php index 63ae6e6a..c235b1db 100644 --- a/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php +++ b/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php @@ -13,15 +13,16 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\Routing\Exception\ExceptionInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * Formats debug file links. * * @author Jérémy Romey + * + * @final since Symfony 4.3 */ -class FileLinkFormatter implements \Serializable +class FileLinkFormatter { private $fileLinkFormat; private $requestStack; @@ -29,12 +30,12 @@ class FileLinkFormatter implements \Serializable private $urlFormat; /** - * @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand + * @param string|array|null $fileLinkFormat + * @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand */ - public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, $baseDir = null, $urlFormat = null) + public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, $urlFormat = null) { - $fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); - if ($fileLinkFormat && !\is_array($fileLinkFormat)) { + if (!\is_array($fileLinkFormat) && $fileLinkFormat = $fileLinkFormat ?: \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')) { $i = strpos($f = $fileLinkFormat, '&', max(strrpos($f, '%f'), strrpos($f, '%l'))) ?: \strlen($f); $fileLinkFormat = [substr($f, 0, $i)] + preg_split('/&([^>]++)>/', substr($f, $i), -1, \PREG_SPLIT_DELIM_CAPTURE); } @@ -49,7 +50,7 @@ public function format($file, $line) { if ($fmt = $this->getFileLinkFormat()) { for ($i = 1; isset($fmt[$i]); ++$i) { - if (0 === strpos($file, $k = $fmt[$i++])) { + if (str_starts_with($file, $k = $fmt[$i++])) { $file = substr_replace($file, $fmt[$i], 0, \strlen($k)); break; } @@ -64,21 +65,11 @@ public function format($file, $line) /** * @internal */ - public function serialize() + public function __sleep(): array { - return serialize($this->getFileLinkFormat()); - } + $this->fileLinkFormat = $this->getFileLinkFormat(); - /** - * @internal - */ - public function unserialize($serialized) - { - if (\PHP_VERSION_ID >= 70000) { - $this->fileLinkFormat = unserialize($serialized, ['allowed_classes' => false]); - } else { - $this->fileLinkFormat = unserialize($serialized); - } + return ['fileLinkFormat']; } /** @@ -88,7 +79,7 @@ public static function generateUrlFormat(UrlGeneratorInterface $router, $routeNa { try { return $router->generate($routeName).$queryString; - } catch (ExceptionInterface $e) { + } catch (\Throwable $e) { return null; } } @@ -98,13 +89,11 @@ private function getFileLinkFormat() if ($this->fileLinkFormat) { return $this->fileLinkFormat; } + if ($this->requestStack && $this->baseDir && $this->urlFormat) { $request = $this->requestStack->getMasterRequest(); - if ($request instanceof Request) { - if ($this->urlFormat instanceof \Closure && !$this->urlFormat = \call_user_func($this->urlFormat)) { - return null; - } + if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) { return [ $request->getSchemeAndHttpHost().$this->urlFormat, $this->baseDir.\DIRECTORY_SEPARATOR, '', diff --git a/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php b/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php index c265b601..832bfb58 100644 --- a/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php +++ b/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpKernel\Debug; use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher as BaseTraceableEventDispatcher; -use Symfony\Component\EventDispatcher\Event; use Symfony\Component\HttpKernel\KernelEvents; /** @@ -27,10 +26,11 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher /** * {@inheritdoc} */ - protected function preDispatch($eventName, Event $event) + protected function beforeDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::REQUEST: + $event->getRequest()->attributes->set('_stopwatch_token', substr(hash('sha256', uniqid(mt_rand(), true)), 0, 6)); $this->stopwatch->openSection(); break; case KernelEvents::VIEW: @@ -41,8 +41,8 @@ protected function preDispatch($eventName, Event $event) } break; case KernelEvents::TERMINATE: - $token = $event->getResponse()->headers->get('X-Debug-Token'); - if (null === $token) { + $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); + if (null === $sectionId) { break; } // There is a very special case when using built-in AppCache class as kernel wrapper, in the case @@ -51,7 +51,7 @@ protected function preDispatch($eventName, Event $event) // is equal to the [A] debug token. Trying to reopen section with the [B] token throws an exception // which must be caught. try { - $this->stopwatch->openSection($token); + $this->stopwatch->openSection($sectionId); } catch (\LogicException $e) { } break; @@ -61,28 +61,28 @@ protected function preDispatch($eventName, Event $event) /** * {@inheritdoc} */ - protected function postDispatch($eventName, Event $event) + protected function afterDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::CONTROLLER_ARGUMENTS: $this->stopwatch->start('controller', 'section'); break; case KernelEvents::RESPONSE: - $token = $event->getResponse()->headers->get('X-Debug-Token'); - if (null === $token) { + $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); + if (null === $sectionId) { break; } - $this->stopwatch->stopSection($token); + $this->stopwatch->stopSection($sectionId); break; case KernelEvents::TERMINATE: // In the special case described in the `preDispatch` method above, the `$token` section // does not exist, then closing it throws an exception which must be caught. - $token = $event->getResponse()->headers->get('X-Debug-Token'); - if (null === $token) { + $sectionId = $event->getRequest()->attributes->get('_stopwatch_token'); + if (null === $sectionId) { break; } try { - $this->stopwatch->stopSection($token); + $this->stopwatch->stopSection($sectionId); } catch (\LogicException $e) { } break; diff --git a/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php b/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php index b5994937..9825151a 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @@ -12,9 +12,10 @@ namespace Symfony\Component\HttpKernel\DependencyInjection; use Composer\Autoload\ClassLoader; -use Symfony\Component\Debug\DebugClassLoader; +use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\ErrorHandler\DebugClassLoader; use Symfony\Component\HttpKernel\Kernel; /** @@ -36,23 +37,15 @@ public function __construct(Kernel $kernel) */ public function process(ContainerBuilder $container) { - $classes = []; - $annotatedClasses = []; + $annotatedClasses = $this->kernel->getAnnotatedClassesToCompile(); foreach ($container->getExtensions() as $extension) { if ($extension instanceof Extension) { - if (\PHP_VERSION_ID < 70000) { - $classes = array_merge($classes, $extension->getClassesToCompile()); - } $annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile()); } } $existingClasses = $this->getClassesInComposerClassMaps(); - if (\PHP_VERSION_ID < 70000) { - $classes = $container->getParameterBag()->resolveValue($classes); - $this->kernel->setClassCache($this->expandClasses($classes, $existingClasses)); - } $annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses); $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses)); } @@ -62,16 +55,14 @@ public function process(ContainerBuilder $container) * * @param array $patterns The class patterns to expand * @param array $classes The existing classes to match against the patterns - * - * @return array A list of classes derived from the patterns */ - private function expandClasses(array $patterns, array $classes) + private function expandClasses(array $patterns, array $classes): array { $expanded = []; // Explicit classes declared in the patterns are returned directly foreach ($patterns as $key => $pattern) { - if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) { + if (!str_ends_with($pattern, '\\') && !str_contains($pattern, '*')) { unset($patterns[$key]); $expanded[] = ltrim($pattern, '\\'); } @@ -91,7 +82,7 @@ private function expandClasses(array $patterns, array $classes) return array_unique($expanded); } - private function getClassesInComposerClassMaps() + private function getClassesInComposerClassMaps(): array { $classes = []; @@ -100,7 +91,7 @@ private function getClassesInComposerClassMaps() continue; } - if ($function[0] instanceof DebugClassLoader) { + if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) { $function = $function[0]->getClassLoader(); } @@ -112,7 +103,7 @@ private function getClassesInComposerClassMaps() return array_keys($classes); } - private function patternsToRegexps($patterns) + private function patternsToRegexps(array $patterns): array { $regexps = []; @@ -134,12 +125,12 @@ private function patternsToRegexps($patterns) return $regexps; } - private function matchAnyRegexps($class, $regexps) + private function matchAnyRegexps(string $class, array $regexps): bool { - $isTest = false !== strpos($class, 'Test'); + $isTest = str_contains($class, 'Test'); foreach ($regexps as $regex) { - if ($isTest && false === strpos($regex, 'Test')) { + if ($isTest && !str_contains($regex, 'Test')) { continue; } diff --git a/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php b/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php deleted file mode 100644 index 8b3dcb7f..00000000 --- a/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php +++ /dev/null @@ -1,25 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\DependencyInjection; - -@trigger_error('The '.__NAMESPACE__.'\AddClassesToCachePass class is deprecated since Symfony 3.3 and will be removed in 4.0.', \E_USER_DEPRECATED); - -/** - * Sets the classes to compile in the cache for the container. - * - * @author Fabien Potencier - * - * @deprecated since version 3.3, to be removed in 4.0. - */ -class AddClassesToCachePass extends AddAnnotatedClassesToCachePass -{ -} diff --git a/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php b/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php index 343e217b..705c88db 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php @@ -15,6 +15,9 @@ use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; +use Symfony\Component\Stopwatch\Stopwatch; /** * Gathers and configures the argument value resolvers. @@ -27,11 +30,13 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface private $argumentResolverService; private $argumentValueResolverTag; + private $traceableResolverStopwatch; - public function __construct($argumentResolverService = 'argument_resolver', $argumentValueResolverTag = 'controller.argument_value_resolver') + public function __construct(string $argumentResolverService = 'argument_resolver', string $argumentValueResolverTag = 'controller.argument_value_resolver', string $traceableResolverStopwatch = 'debug.stopwatch') { $this->argumentResolverService = $argumentResolverService; $this->argumentValueResolverTag = $argumentValueResolverTag; + $this->traceableResolverStopwatch = $traceableResolverStopwatch; } public function process(ContainerBuilder $container) @@ -40,9 +45,20 @@ public function process(ContainerBuilder $container) return; } + $resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container); + + if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has($this->traceableResolverStopwatch)) { + foreach ($resolvers as $resolverReference) { + $id = (string) $resolverReference; + $container->register("debug.$id", TraceableValueResolver::class) + ->setDecoratedService($id) + ->setArguments([new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch)]); + } + } + $container ->getDefinition($this->argumentResolverService) - ->replaceArgument(1, new IteratorArgument($this->findAndSortTaggedServices($this->argumentValueResolverTag, $container))) + ->replaceArgument(1, new IteratorArgument($resolvers)) ; } } diff --git a/vendor/symfony/http-kernel/DependencyInjection/Extension.php b/vendor/symfony/http-kernel/DependencyInjection/Extension.php index 55a4759d..db376e6d 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/Extension.php +++ b/vendor/symfony/http-kernel/DependencyInjection/Extension.php @@ -20,25 +20,8 @@ */ abstract class Extension extends BaseExtension { - private $classes = []; private $annotatedClasses = []; - /** - * Gets the classes to cache. - * - * @return array An array of classes - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function getClassesToCompile() - { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', \E_USER_DEPRECATED); - } - - return $this->classes; - } - /** * Gets the annotated classes to cache. * @@ -49,22 +32,6 @@ public function getAnnotatedClassesToCompile() return $this->annotatedClasses; } - /** - * Adds classes to the class cache. - * - * @param array $classes An array of class patterns - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function addClassesToCompile(array $classes) - { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', \E_USER_DEPRECATED); - } - - $this->classes = array_merge($this->classes, $classes); - } - /** * Adds annotated classes to the class cache. * diff --git a/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php b/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php index a15fbaa1..432f7672 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php @@ -28,11 +28,7 @@ class FragmentRendererPass implements CompilerPassInterface private $handlerService; private $rendererTag; - /** - * @param string $handlerService Service name of the fragment handler in the container - * @param string $rendererTag Tag name used for fragments - */ - public function __construct($handlerService = 'fragment.handler', $rendererTag = 'kernel.fragment_renderer') + public function __construct(string $handlerService = 'fragment.handler', string $rendererTag = 'kernel.fragment_renderer') { $this->handlerService = $handlerService; $this->rendererTag = $rendererTag; diff --git a/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php b/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php index 4deaaf0d..526c11fa 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php +++ b/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php @@ -23,52 +23,20 @@ class LazyLoadingFragmentHandler extends FragmentHandler { private $container; - /** - * @deprecated since version 3.3, to be removed in 4.0 - */ - private $rendererIds = []; private $initialized = []; - /** - * @param ContainerInterface $container A container - * @param RequestStack $requestStack The Request stack that controls the lifecycle of requests - * @param bool $debug Whether the debug mode is enabled or not - */ - public function __construct(ContainerInterface $container, RequestStack $requestStack, $debug = false) + public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false) { $this->container = $container; parent::__construct($requestStack, [], $debug); } - /** - * Adds a service as a fragment renderer. - * - * @param string $name The service name - * @param string $renderer The render service id - * - * @deprecated since version 3.3, to be removed in 4.0 - */ - public function addRendererService($name, $renderer) - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), \E_USER_DEPRECATED); - - $this->rendererIds[$name] = $renderer; - } - /** * {@inheritdoc} */ public function render($uri, $renderer = 'inline', array $options = []) { - // BC 3.x, to be removed in 4.0 - if (isset($this->rendererIds[$renderer])) { - $this->addRenderer($this->container->get($this->rendererIds[$renderer])); - unset($this->rendererIds[$renderer]); - - return parent::render($uri, $renderer, $options); - } - if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) { $this->addRenderer($this->container->get($renderer)); $this->initialized[$renderer] = true; diff --git a/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index c7d3d279..bcf2b5d9 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -33,16 +33,20 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface { private $resolverServiceId; private $controllerTag; + private $controllerLocator; + private $notTaggedControllerResolverServiceId; - public function __construct($resolverServiceId = 'argument_resolver.service', $controllerTag = 'controller.service_arguments') + public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator', string $notTaggedControllerResolverServiceId = 'argument_resolver.not_tagged_controller') { $this->resolverServiceId = $resolverServiceId; $this->controllerTag = $controllerTag; + $this->controllerLocator = $controllerLocator; + $this->notTaggedControllerResolverServiceId = $notTaggedControllerResolverServiceId; } public function process(ContainerBuilder $container) { - if (false === $container->hasDefinition($this->resolverServiceId)) { + if (false === $container->hasDefinition($this->resolverServiceId) && false === $container->hasDefinition($this->notTaggedControllerResolverServiceId)) { return; } @@ -95,7 +99,7 @@ public function process(ContainerBuilder $container) if (!isset($methods[$action = strtolower($attributes['action'])])) { throw new InvalidArgumentException(sprintf('Invalid "action" attribute on tag "%s" for service "%s": no public "%s()" method found on class "%s".', $this->controllerTag, $id, $attributes['action'], $class)); } - list($r, $parameters) = $methods[$action]; + [$r, $parameters] = $methods[$action]; $found = false; foreach ($parameters as $p) { @@ -113,40 +117,48 @@ public function process(ContainerBuilder $container) } } - foreach ($methods as list($r, $parameters)) { + foreach ($methods as [$r, $parameters]) { /** @var \ReflectionMethod $r */ // create a per-method map of argument-names to service/type-references $args = []; foreach ($parameters as $p) { /** @var \ReflectionParameter $p */ - $type = $target = ProxyHelper::getTypeHint($r, $p, true); + $type = ltrim($target = (string) ProxyHelper::getTypeHint($r, $p), '\\'); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; if (isset($arguments[$r->name][$p->name])) { $target = $arguments[$r->name][$p->name]; if ('?' !== $target[0]) { - $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } elseif ('' === $target = (string) substr($target, 1)) { throw new InvalidArgumentException(sprintf('A "%s" tag must have non-empty "id" attributes for service "%s".', $this->controllerTag, $id)); } elseif ($p->allowsNull() && !$p->isOptional()) { $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; } - } elseif (isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) { + } elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) { $binding = $bindings[$bindingName]; - list($bindingValue, $bindingId) = $binding->getValues(); + [$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues(); + $binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]); if (!$bindingValue instanceof Reference) { - continue; + $args[$p->name] = new Reference('.value.'.$container->hash($bindingValue)); + $container->register((string) $args[$p->name], 'mixed') + ->setFactory('current') + ->addArgument([$bindingValue]); + } else { + $args[$p->name] = $bindingValue; } - $binding->setValues([$bindingValue, $bindingId, true]); - $args[$p->name] = $bindingValue; - continue; - } elseif (!$type || !$autowire) { + } elseif (!$type || !$autowire || '\\' !== $target[0]) { + continue; + } elseif (is_subclass_of($type, \UnitEnum::class)) { + // do not attempt to register enum typed arguments if not already present in bindings continue; + } elseif (!$p->allowsNull()) { + $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } if (Request::class === $type) { @@ -164,16 +176,28 @@ public function process(ContainerBuilder $container) throw new InvalidArgumentException($message); } - $args[$p->name] = $type ? new TypedReference($target, $type, $r->class, $invalidBehavior) : new Reference($target, $invalidBehavior); + $target = ltrim($target, '\\'); + $args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, $p->name) : new Reference($target, $invalidBehavior); } // register the maps as a per-method service-locators if ($args) { - $controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args); + $controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args); } } } - $container->getDefinition($this->resolverServiceId) - ->replaceArgument(0, ServiceLocatorTagPass::register($container, $controllers)); + $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers); + + if ($container->hasDefinition($this->resolverServiceId)) { + $container->getDefinition($this->resolverServiceId) + ->replaceArgument(0, $controllerLocatorRef); + } + + if ($container->hasDefinition($this->notTaggedControllerResolverServiceId)) { + $container->getDefinition($this->notTaggedControllerResolverServiceId) + ->replaceArgument(0, $controllerLocatorRef); + } + + $container->setAlias($this->controllerLocator, (string) $controllerLocatorRef); } } diff --git a/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php b/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php new file mode 100644 index 00000000..0efb164b --- /dev/null +++ b/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\DependencyInjection; + +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Register all services that have the "kernel.locale_aware" tag into the listener. + * + * @author Pierre Bobiet + */ +class RegisterLocaleAwareServicesPass implements CompilerPassInterface +{ + private $listenerServiceId; + private $localeAwareTag; + + public function __construct(string $listenerServiceId = 'locale_aware_listener', string $localeAwareTag = 'kernel.locale_aware') + { + $this->listenerServiceId = $listenerServiceId; + $this->localeAwareTag = $localeAwareTag; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->listenerServiceId)) { + return; + } + + $services = []; + + foreach ($container->findTaggedServiceIds($this->localeAwareTag) as $id => $tags) { + $services[] = new Reference($id); + } + + if (!$services) { + $container->removeDefinition($this->listenerServiceId); + + return; + } + + $container + ->getDefinition($this->listenerServiceId) + ->setArgument(0, new IteratorArgument($services)) + ; + } +} diff --git a/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php b/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php index e230a67e..c09f2bfd 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php @@ -21,21 +21,16 @@ */ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface { - private $resolverServiceId; + private $controllerLocator; - public function __construct($resolverServiceId = 'argument_resolver.service') + public function __construct(string $controllerLocator = 'argument_resolver.controller_locator') { - $this->resolverServiceId = $resolverServiceId; + $this->controllerLocator = $controllerLocator; } public function process(ContainerBuilder $container) { - if (false === $container->hasDefinition($this->resolverServiceId)) { - return; - } - - $serviceResolver = $container->getDefinition($this->resolverServiceId); - $controllerLocator = $container->getDefinition((string) $serviceResolver->getArgument(0)); + $controllerLocator = $container->findDefinition($this->controllerLocator); $controllers = $controllerLocator->getArgument(0); foreach ($controllers as $controller => $argumentRef) { @@ -47,19 +42,18 @@ public function process(ContainerBuilder $container) } else { // any methods listed for call-at-instantiation cannot be actions $reason = false; - $action = substr(strrchr($controller, ':'), 1); - $id = substr($controller, 0, -1 - \strlen($action)); + [$id, $action] = explode('::', $controller); $controllerDef = $container->getDefinition($id); - foreach ($controllerDef->getMethodCalls() as list($method)) { + foreach ($controllerDef->getMethodCalls() as [$method]) { if (0 === strcasecmp($action, $method)) { $reason = sprintf('Removing method "%s" of service "%s" from controller candidates: the method is called at instantiation, thus cannot be an action.', $action, $id); break; } } if (!$reason) { - if ($controllerDef->getClass() === $id) { - $controllers[$id.'::'.$action] = $argumentRef; - } + // Deprecated since Symfony 4.1. See Symfony\Component\HttpKernel\Controller\ContainerControllerResolver + $controllers[$id.':'.$action] = $argumentRef; + if ('__invoke' === $action) { $controllers[$id] = $argumentRef; } diff --git a/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php b/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php index 51a518dc..b5e46106 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php @@ -25,7 +25,7 @@ class ResettableServicePass implements CompilerPassInterface { private $tagName; - public function __construct($tagName = 'kernel.reset') + public function __construct(string $tagName = 'kernel.reset') { $this->tagName = $tagName; } @@ -43,16 +43,21 @@ public function process(ContainerBuilder $container) foreach ($container->findTaggedServiceIds($this->tagName, true) as $id => $tags) { $services[$id] = new Reference($id, ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE); - $attributes = $tags[0]; - if (!isset($attributes['method'])) { - throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName)); - } + foreach ($tags as $attributes) { + if (!isset($attributes['method'])) { + throw new RuntimeException(sprintf('Tag "%s" requires the "method" attribute to be set.', $this->tagName)); + } + + if (!isset($methods[$id])) { + $methods[$id] = []; + } - $methods[$id] = $attributes['method']; + $methods[$id][] = $attributes['method']; + } } - if (empty($services)) { + if (!$services) { $container->removeAlias('services_resetter'); $container->removeDefinition('services_resetter'); diff --git a/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php b/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php index b82d2fef..d9e0028c 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php +++ b/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpKernel\DependencyInjection; +use Symfony\Contracts\Service\ResetInterface; + /** * Resets provided services. * @@ -19,7 +21,7 @@ * * @internal */ -class ServicesResetter +class ServicesResetter implements ResetInterface { private $resettableServices; private $resetMethods; @@ -33,7 +35,9 @@ public function __construct(\Traversable $resettableServices, array $resetMethod public function reset() { foreach ($this->resettableServices as $id => $service) { - $service->{$this->resetMethods[$id]}(); + foreach ((array) $this->resetMethods[$id] as $resetMethod) { + $service->$resetMethod(); + } } } } diff --git a/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php b/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php new file mode 100644 index 00000000..5efb80cf --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows filtering of controller arguments. + * + * You can call getController() to retrieve the controller and getArguments + * to retrieve the current arguments. With setArguments() you can replace + * arguments that are used to call the controller. + * + * Arguments set in the event must be compatible with the signature of the + * controller. + * + * @author Christophe Coevoet + * + * @final since Symfony 4.4 + */ +class ControllerArgumentsEvent extends FilterControllerArgumentsEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/ControllerEvent.php b/vendor/symfony/http-kernel/Event/ControllerEvent.php new file mode 100644 index 00000000..7b642eaa --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ControllerEvent.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows filtering of a controller callable. + * + * You can call getController() to retrieve the current controller. With + * setController() you can set a new controller that is used in the processing + * of the request. + * + * Controllers should be callables. + * + * @author Bernhard Schussek + * + * @final since Symfony 4.4 + */ +class ControllerEvent extends FilterControllerEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/ExceptionEvent.php b/vendor/symfony/http-kernel/Event/ExceptionEvent.php new file mode 100644 index 00000000..313a3615 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ExceptionEvent.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows to create a response for a thrown exception. + * + * Call setResponse() to set the response that will be returned for the + * current request. The propagation of this event is stopped as soon as a + * response is set. + * + * You can also call setThrowable() to replace the thrown exception. This + * exception will be thrown if no response is set during processing of this + * event. + * + * @author Bernhard Schussek + * + * @final since Symfony 4.4 + */ +class ExceptionEvent extends GetResponseForExceptionEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php b/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php index 043e0584..f3c5dc34 100644 --- a/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php @@ -15,22 +15,13 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * Allows filtering of controller arguments. - * - * You can call getController() to retrieve the controller and getArguments - * to retrieve the current arguments. With setArguments() you can replace - * arguments that are used to call the controller. - * - * Arguments set in the event must be compatible with the signature of the - * controller. - * - * @author Christophe Coevoet + * @deprecated since Symfony 4.3, use ControllerArgumentsEvent instead */ class FilterControllerArgumentsEvent extends FilterControllerEvent { private $arguments; - public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, $requestType) + public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, ?int $requestType) { parent::__construct($kernel, $controller, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/FilterControllerEvent.php b/vendor/symfony/http-kernel/Event/FilterControllerEvent.php index a4cfd625..74fa681f 100644 --- a/vendor/symfony/http-kernel/Event/FilterControllerEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterControllerEvent.php @@ -15,21 +15,13 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * Allows filtering of a controller callable. - * - * You can call getController() to retrieve the current controller. With - * setController() you can set a new controller that is used in the processing - * of the request. - * - * Controllers should be callables. - * - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use ControllerEvent instead */ class FilterControllerEvent extends KernelEvent { private $controller; - public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, $requestType) + public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/FilterResponseEvent.php b/vendor/symfony/http-kernel/Event/FilterResponseEvent.php index 1b80e34b..eaa2e825 100644 --- a/vendor/symfony/http-kernel/Event/FilterResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterResponseEvent.php @@ -16,19 +16,13 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * Allows to filter a Response object. - * - * You can call getResponse() to retrieve the current response. With - * setResponse() you can set a new response that will be returned to the - * browser. - * - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use ResponseEvent instead */ class FilterResponseEvent extends KernelEvent { private $response; - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, Response $response) + public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/FinishRequestEvent.php b/vendor/symfony/http-kernel/Event/FinishRequestEvent.php index ee724843..9374d2db 100644 --- a/vendor/symfony/http-kernel/Event/FinishRequestEvent.php +++ b/vendor/symfony/http-kernel/Event/FinishRequestEvent.php @@ -15,6 +15,8 @@ * Triggered whenever a request is fully processed. * * @author Benjamin Eberlei + * + * @final since Symfony 4.4 */ class FinishRequestEvent extends KernelEvent { diff --git a/vendor/symfony/http-kernel/Event/GetResponseEvent.php b/vendor/symfony/http-kernel/Event/GetResponseEvent.php index c25a0f1c..fbed7bee 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseEvent.php @@ -14,13 +14,7 @@ use Symfony\Component\HttpFoundation\Response; /** - * Allows to create a response for a request. - * - * Call setResponse() to set the response that will be returned for the - * current request. The propagation of this event is stopped as soon as a - * response is set. - * - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use RequestEvent instead */ class GetResponseEvent extends KernelEvent { diff --git a/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php b/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php index d68eaa18..4e70dbc6 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php @@ -15,15 +15,9 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * Allows to create a response for the return value of a controller. - * - * Call setResponse() to set the response that will be returned for the - * current request. The propagation of this event is stopped as soon as a - * response is set. - * - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use ViewEvent instead */ -class GetResponseForControllerResultEvent extends GetResponseEvent +class GetResponseForControllerResultEvent extends RequestEvent { /** * The return value of the controller. @@ -32,7 +26,7 @@ class GetResponseForControllerResultEvent extends GetResponseEvent */ private $controllerResult; - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, $controllerResult) + public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, $controllerResult) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php b/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php index 6199838f..bfec654e 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php @@ -11,63 +11,64 @@ namespace Symfony\Component\HttpKernel\Event; +use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * Allows to create a response for a thrown exception. - * - * Call setResponse() to set the response that will be returned for the - * current request. The propagation of this event is stopped as soon as a - * response is set. - * - * You can also call setException() to replace the thrown exception. This - * exception will be thrown if no response is set during processing of this - * event. - * - * @author Bernhard Schussek + * @deprecated since Symfony 4.3, use ExceptionEvent instead */ -class GetResponseForExceptionEvent extends GetResponseEvent +class GetResponseForExceptionEvent extends RequestEvent { - /** - * The exception object. - * - * @var \Exception - */ + private $throwable; private $exception; - - /** - * @var bool - */ private $allowCustomResponseCode = false; - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, \Exception $e) + public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Throwable $e) { parent::__construct($kernel, $request, $requestType); - $this->setException($e); + $this->setThrowable($e); + } + + public function getThrowable(): \Throwable + { + return $this->throwable; } /** - * Returns the thrown exception. + * Replaces the thrown exception. + * + * This exception will be thrown if no response is set in the event. + */ + public function setThrowable(\Throwable $exception): void + { + $this->exception = null; + $this->throwable = $exception; + } + + /** + * @deprecated since Symfony 4.4, use getThrowable instead * * @return \Exception The thrown exception */ public function getException() { - return $this->exception; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "getThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED); + + return $this->exception ?? $this->exception = $this->throwable instanceof \Exception ? $this->throwable : new FatalThrowableError($this->throwable); } /** - * Replaces the thrown exception. - * - * This exception will be thrown if no response is set in the event. + * @deprecated since Symfony 4.4, use setThrowable instead * * @param \Exception $exception The thrown exception */ public function setException(\Exception $exception) { - $this->exception = $exception; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.4, use "setThrowable()" instead.', __METHOD__), \E_USER_DEPRECATED); + + $this->throwable = $this->exception = $exception; } /** diff --git a/vendor/symfony/http-kernel/Event/KernelEvent.php b/vendor/symfony/http-kernel/Event/KernelEvent.php index cccf01f3..f6dff06a 100644 --- a/vendor/symfony/http-kernel/Event/KernelEvent.php +++ b/vendor/symfony/http-kernel/Event/KernelEvent.php @@ -27,12 +27,10 @@ class KernelEvent extends Event private $requestType; /** - * @param HttpKernelInterface $kernel The kernel in which this event was thrown - * @param Request $request The request the kernel is currently processing - * @param int $requestType The request type the kernel is currently processing; one of - * HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST + * @param int $requestType The request type the kernel is currently processing; one of + * HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST */ - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType) + public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType) { $this->kernel = $kernel; $this->request = $request; diff --git a/vendor/symfony/http-kernel/Event/PostResponseEvent.php b/vendor/symfony/http-kernel/Event/PostResponseEvent.php index 0981e64c..b86bf077 100644 --- a/vendor/symfony/http-kernel/Event/PostResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/PostResponseEvent.php @@ -16,12 +16,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; /** - * Allows to execute logic after a response was sent. - * - * Since it's only triggered on master requests, the `getRequestType()` method - * will always return the value of `HttpKernelInterface::MASTER_REQUEST`. - * - * @author Jordi Boggiano + * @deprecated since Symfony 4.3, use TerminateEvent instead */ class PostResponseEvent extends KernelEvent { diff --git a/vendor/symfony/http-kernel/Event/RequestEvent.php b/vendor/symfony/http-kernel/Event/RequestEvent.php new file mode 100644 index 00000000..c1beb929 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/RequestEvent.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows to create a response for a request. + * + * Call setResponse() to set the response that will be returned for the + * current request. The propagation of this event is stopped as soon as a + * response is set. + * + * @author Bernhard Schussek + */ +class RequestEvent extends GetResponseEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/ResponseEvent.php b/vendor/symfony/http-kernel/Event/ResponseEvent.php new file mode 100644 index 00000000..eae8c39c --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ResponseEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows to filter a Response object. + * + * You can call getResponse() to retrieve the current response. With + * setResponse() you can set a new response that will be returned to the + * browser. + * + * @author Bernhard Schussek + * + * @final since Symfony 4.4 + */ +class ResponseEvent extends FilterResponseEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/TerminateEvent.php b/vendor/symfony/http-kernel/Event/TerminateEvent.php new file mode 100644 index 00000000..6a74445d --- /dev/null +++ b/vendor/symfony/http-kernel/Event/TerminateEvent.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows to execute logic after a response was sent. + * + * Since it's only triggered on master requests, the `getRequestType()` method + * will always return the value of `HttpKernelInterface::MASTER_REQUEST`. + * + * @author Jordi Boggiano + * + * @final since Symfony 4.4 + */ +class TerminateEvent extends PostResponseEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/ViewEvent.php b/vendor/symfony/http-kernel/Event/ViewEvent.php new file mode 100644 index 00000000..da50da82 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ViewEvent.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Event; + +/** + * Allows to create a response for the return value of a controller. + * + * Call setResponse() to set the response that will be returned for the + * current request. The propagation of this event is stopped as soon as a + * response is set. + * + * @author Bernhard Schussek + * + * @final since Symfony 4.4 + */ +class ViewEvent extends GetResponseForControllerResultEvent +{ +} diff --git a/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php b/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php index 0a6bb4f7..5f657bfb 100644 --- a/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpKernel\EventListener; +use Psr\Container\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -20,14 +21,32 @@ use Symfony\Component\HttpKernel\KernelEvents; /** - * Sets the session in the request. + * Sets the session onto the request on the "kernel.request" event and saves + * it on the "kernel.response" event. + * + * In addition, if the session has been started it overrides the Cache-Control + * header in such a way that all caching is disabled in that case. + * If you have a scenario where caching responses with session information in + * them makes sense, you can disable this behaviour by setting the header + * AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER on the response. * * @author Johannes M. Schmitt + * @author Tobias Schultze + * + * @internal since Symfony 4.3 */ abstract class AbstractSessionListener implements EventSubscriberInterface { + public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl'; + + protected $container; private $sessionUsageStack = []; + public function __construct(ContainerInterface $container = null) + { + $this->container = $container; + } + public function onKernelRequest(GetResponseEvent $event) { if (!$event->isMasterRequest()) { @@ -35,13 +54,13 @@ public function onKernelRequest(GetResponseEvent $event) } $request = $event->getRequest(); - $session = $this->getSession(); - $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : null; - if (null === $session || $request->hasSession()) { - return; + if (!$request->hasSession()) { + $sess = null; + $request->setSessionFactory(function () use (&$sess) { return $sess ?? $sess = $this->getSession(); }); } - $request->setSession($session); + $session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null; + $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0; } public function onKernelResponse(FilterResponseEvent $event) @@ -50,16 +69,52 @@ public function onKernelResponse(FilterResponseEvent $event) return; } - if (!$session = $event->getRequest()->getSession()) { + $response = $event->getResponse(); + $autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER); + // Always remove the internal header if present + $response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER); + + if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : ($event->getRequest()->hasSession() ? $event->getRequest()->getSession() : null)) { return; } if ($session instanceof Session ? $session->getUsageIndex() !== end($this->sessionUsageStack) : $session->isStarted()) { - $event->getResponse() - ->setExpires(new \DateTime()) - ->setPrivate() - ->setMaxAge(0) - ->headers->addCacheControlDirective('must-revalidate'); + if ($autoCacheControl) { + $response + ->setExpires(new \DateTime()) + ->setPrivate() + ->setMaxAge(0) + ->headers->addCacheControlDirective('must-revalidate'); + } + } + + if ($session->isStarted()) { + /* + * Saves the session, in case it is still open, before sending the response/headers. + * + * This ensures several things in case the developer did not save the session explicitly: + * + * * If a session save handler without locking is used, it ensures the data is available + * on the next request, e.g. after a redirect. PHPs auto-save at script end via + * session_register_shutdown is executed after fastcgi_finish_request. So in this case + * the data could be missing the next request because it might not be saved the moment + * the new request is processed. + * * A locking save handler (e.g. the native 'files') circumvents concurrency problems like + * the one above. But by saving the session before long-running things in the terminate event, + * we ensure the session is not blocked longer than needed. + * * When regenerating the session ID no locking is involved in PHPs session design. See + * https://bugs.php.net/61470 for a discussion. So in this case, the session must + * be saved anyway before sending the headers with the new session ID. Otherwise session + * data could get lost again for concurrent requests with the new ID. One result could be + * that you get logged out after just logging in. + * + * This listener should be executed as one of the last listeners, so that previous listeners + * can still operate on the open session. This prevents the overhead of restarting it. + * Listeners after closing the session can still work with the session as usual because + * Symfonys session implementation starts the session on demand. So writing to it after + * it is saved will just restart it. + */ + $session->save(); } } @@ -77,7 +132,7 @@ public static function getSubscribedEvents() { return [ KernelEvents::REQUEST => ['onKernelRequest', 128], - // low priority to come after regular response listeners, same as SaveSessionListener + // low priority to come after regular response listeners, but higher than StreamedResponseListener KernelEvents::RESPONSE => ['onKernelResponse', -1000], KernelEvents::FINISH_REQUEST => ['onFinishRequest'], ]; diff --git a/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php b/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php index 714b315a..25be3b39 100644 --- a/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php @@ -26,10 +26,18 @@ * * @author Bulat Shakirzyanov * @author Fabien Potencier + * + * @internal since Symfony 4.3 */ abstract class AbstractTestSessionListener implements EventSubscriberInterface { private $sessionId; + private $sessionOptions; + + public function __construct(array $sessionOptions = []) + { + $this->sessionOptions = $sessionOptions; + } public function onKernelRequest(GetResponseEvent $event) { @@ -38,8 +46,7 @@ public function onKernelRequest(GetResponseEvent $event) } // bootstrap the session - $session = $this->getSession(); - if (!$session) { + if (!$session = $this->getSession()) { return; } @@ -61,16 +68,23 @@ public function onKernelResponse(FilterResponseEvent $event) return; } - if (!$session = $event->getRequest()->getSession()) { + $request = $event->getRequest(); + if (!$request->hasSession()) { return; } + $session = $request->getSession(); if ($wasStarted = $session->isStarted()) { $session->save(); } if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) { - $params = session_get_cookie_params(); + $params = session_get_cookie_params() + ['samesite' => null]; + foreach ($this->sessionOptions as $k => $v) { + if (str_starts_with($k, 'cookie_')) { + $params[substr($k, 7)] = $v; + } + } foreach ($event->getResponse()->headers->getCookies() as $cookie) { if ($session->getName() === $cookie->getName() && $params['path'] === $cookie->getPath() && $params['domain'] == $cookie->getDomain()) { @@ -78,7 +92,7 @@ public function onKernelResponse(FilterResponseEvent $event) } } - $event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'])); + $event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'], false, $params['samesite'] ?: null)); $this->sessionId = $session->getId(); } } diff --git a/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php b/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php index 68d806af..47c7069c 100644 --- a/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php +++ b/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php @@ -19,6 +19,8 @@ * Adds configured formats to each request. * * @author Gildas Quemener + * + * @final since Symfony 4.3 */ class AddRequestFormatsListener implements EventSubscriberInterface { @@ -45,6 +47,6 @@ public function onKernelRequest(GetResponseEvent $event) */ public static function getSubscribedEvents() { - return [KernelEvents::REQUEST => ['onKernelRequest', 1]]; + return [KernelEvents::REQUEST => ['onKernelRequest', 100]]; } } diff --git a/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php b/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php index 5f530631..6563487f 100644 --- a/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php +++ b/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php @@ -15,8 +15,9 @@ use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\Console\Event\ConsoleEvent; use Symfony\Component\Console\Output\ConsoleOutputInterface; -use Symfony\Component\Debug\ErrorHandler; -use Symfony\Component\Debug\ExceptionHandler; +use Symfony\Component\Debug\ErrorHandler as LegacyErrorHandler; +use Symfony\Component\Debug\Exception\FatalThrowableError; +use Symfony\Component\ErrorHandler\ErrorHandler; use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; @@ -27,9 +28,12 @@ * Configures errors and exceptions handlers. * * @author Nicolas Grekas + * + * @final since Symfony 4.4 */ class DebugHandlersListener implements EventSubscriberInterface { + private $earlyHandler; private $exceptionHandler; private $logger; private $levels; @@ -41,23 +45,26 @@ class DebugHandlersListener implements EventSubscriberInterface private $hasTerminatedWithException; /** - * @param callable|null $exceptionHandler A handler that will be called on Exception - * @param LoggerInterface|null $logger A PSR-3 logger + * @param callable|null $exceptionHandler A handler that must support \Throwable instances that will be called on Exception * @param array|int $levels An array map of E_* to LogLevel::* or an integer bit field of E_* constants * @param int|null $throwAt Thrown errors in a bit field of E_* constants, or null to keep the current value * @param bool $scream Enables/disables screaming mode, where even silenced errors are logged * @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files * @param bool $scope Enables/disables scoping mode */ - public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, $throwAt = \E_ALL, $scream = true, $fileLinkFormat = null, $scope = true) + public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = \E_ALL, ?int $throwAt = \E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true) { + $handler = set_exception_handler('is_int'); + $this->earlyHandler = \is_array($handler) ? $handler[0] : null; + restore_exception_handler(); + $this->exceptionHandler = $exceptionHandler; $this->logger = $logger; - $this->levels = null === $levels ? \E_ALL : $levels; - $this->throwAt = is_numeric($throwAt) ? (int) $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null)); - $this->scream = (bool) $scream; + $this->levels = $levels ?? \E_ALL; + $this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? \E_ALL : null)); + $this->scream = $scream; $this->fileLinkFormat = $fileLinkFormat; - $this->scope = (bool) $scope; + $this->scope = $scope; } /** @@ -73,12 +80,16 @@ public function configure(Event $event = null) } $this->firstCall = $this->hasTerminatedWithException = false; - $handler = set_exception_handler('var_dump'); + $handler = set_exception_handler('is_int'); $handler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); + if (!$handler instanceof ErrorHandler && !$handler instanceof LegacyErrorHandler) { + $handler = $this->earlyHandler; + } + if ($this->logger || null !== $this->throwAt) { - if ($handler instanceof ErrorHandler) { + if ($handler instanceof ErrorHandler || $handler instanceof LegacyErrorHandler) { if ($this->logger) { $handler->setDefaultLogger($this->logger, $this->levels); if (\is_array($this->levels)) { @@ -109,10 +120,11 @@ public function configure(Event $event = null) if (method_exists($kernel = $event->getKernel(), 'terminateWithException')) { $request = $event->getRequest(); $hasRun = &$this->hasTerminatedWithException; - $this->exceptionHandler = static function (\Exception $e) use ($kernel, $request, &$hasRun) { + $this->exceptionHandler = static function (\Throwable $e) use ($kernel, $request, &$hasRun) { if ($hasRun) { throw $e; } + $hasRun = true; $kernel->terminateWithException($e, $request); }; @@ -122,26 +134,22 @@ public function configure(Event $event = null) if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } - $this->exceptionHandler = function ($e) use ($app, $output) { - $app->renderException($e, $output); + $this->exceptionHandler = static function (\Throwable $e) use ($app, $output) { + if (method_exists($app, 'renderThrowable')) { + $app->renderThrowable($e, $output); + } else { + if (!$e instanceof \Exception) { + $e = new FatalThrowableError($e); + } + + $app->renderException($e, $output); + } }; } } if ($this->exceptionHandler) { - if ($handler instanceof ErrorHandler) { - $h = $handler->setExceptionHandler('var_dump'); - if (\is_array($h) && $h[0] instanceof ExceptionHandler) { - $handler->setExceptionHandler($h); - $handler = $h[0]; - } else { - $handler->setExceptionHandler($this->exceptionHandler); - } - } - if ($handler instanceof ExceptionHandler) { - $handler->setHandler($this->exceptionHandler); - if (null !== $this->fileLinkFormat) { - $handler->setFileLinkFormat($this->fileLinkFormat); - } + if ($handler instanceof ErrorHandler || $handler instanceof LegacyErrorHandler) { + $handler->setExceptionHandler($this->exceptionHandler); } $this->exceptionHandler = null; } diff --git a/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php b/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php new file mode 100644 index 00000000..6607e49e --- /dev/null +++ b/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +/** + * Ensures that the application is not indexed by search engines. + * + * @author Gary PEGEOT + */ +class DisallowRobotsIndexingListener implements EventSubscriberInterface +{ + private const HEADER_NAME = 'X-Robots-Tag'; + + public function onResponse(ResponseEvent $event): void + { + if (!$event->getResponse()->headers->has(static::HEADER_NAME)) { + $event->getResponse()->headers->set(static::HEADER_NAME, 'noindex'); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return [ + KernelEvents::RESPONSE => ['onResponse', -255], + ]; + } +} diff --git a/vendor/symfony/http-kernel/EventListener/DumpListener.php b/vendor/symfony/http-kernel/EventListener/DumpListener.php index 2f47d106..30908a4f 100644 --- a/vendor/symfony/http-kernel/EventListener/DumpListener.php +++ b/vendor/symfony/http-kernel/EventListener/DumpListener.php @@ -15,6 +15,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; +use Symfony\Component\VarDumper\Server\Connection; use Symfony\Component\VarDumper\VarDumper; /** @@ -26,20 +27,27 @@ class DumpListener implements EventSubscriberInterface { private $cloner; private $dumper; + private $connection; - public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper) + public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, Connection $connection = null) { $this->cloner = $cloner; $this->dumper = $dumper; + $this->connection = $connection; } public function configure() { $cloner = $this->cloner; $dumper = $this->dumper; + $connection = $this->connection; - VarDumper::setHandler(function ($var) use ($cloner, $dumper) { - $dumper->dump($cloner->cloneVar($var)); + VarDumper::setHandler(static function ($var) use ($cloner, $dumper, $connection) { + $data = $cloner->cloneVar($var); + + if (!$connection || !$connection->write($data)) { + $dumper->dump($data); + } }); } diff --git a/vendor/symfony/http-kernel/EventListener/ErrorListener.php b/vendor/symfony/http-kernel/EventListener/ErrorListener.php new file mode 100644 index 00000000..1ca6c9b4 --- /dev/null +++ b/vendor/symfony/http-kernel/EventListener/ErrorListener.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Psr\Log\LoggerInterface; +use Symfony\Component\Debug\Exception\FlattenException as LegacyFlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; +use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; + +/** + * @author Fabien Potencier + */ +class ErrorListener implements EventSubscriberInterface +{ + protected $controller; + protected $logger; + protected $debug; + + public function __construct($controller, LoggerInterface $logger = null, $debug = false) + { + $this->controller = $controller; + $this->logger = $logger; + $this->debug = $debug; + } + + public function logKernelException(ExceptionEvent $event) + { + $e = FlattenException::createFromThrowable($event->getThrowable()); + + $this->logException($event->getThrowable(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine())); + } + + public function onKernelException(ExceptionEvent $event, string $eventName = null, EventDispatcherInterface $eventDispatcher = null) + { + if (null === $this->controller) { + return; + } + + $exception = $event->getThrowable(); + $request = $this->duplicateRequest($exception, $event->getRequest()); + + try { + $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false); + } catch (\Exception $e) { + $f = FlattenException::createFromThrowable($e); + + $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); + + $prev = $e; + do { + if ($exception === $wrapper = $prev) { + throw $e; + } + } while ($prev = $wrapper->getPrevious()); + + $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous'); + $prev->setAccessible(true); + $prev->setValue($wrapper, $exception); + + throw $e; + } + + $event->setResponse($response); + + if ($this->debug && $eventDispatcher instanceof EventDispatcherInterface) { + $cspRemovalListener = function ($event) use (&$cspRemovalListener, $eventDispatcher) { + $event->getResponse()->headers->remove('Content-Security-Policy'); + $eventDispatcher->removeListener(KernelEvents::RESPONSE, $cspRemovalListener); + }; + $eventDispatcher->addListener(KernelEvents::RESPONSE, $cspRemovalListener, -128); + } + } + + public function onControllerArguments(ControllerArgumentsEvent $event) + { + $e = $event->getRequest()->attributes->get('exception'); + + if (!$e instanceof \Throwable || false === $k = array_search($e, $event->getArguments(), true)) { + return; + } + + $r = new \ReflectionFunction(\Closure::fromCallable($event->getController())); + $r = $r->getParameters()[$k] ?? null; + + if ($r && (!($r = $r->getType()) instanceof \ReflectionNamedType || \in_array($r->getName(), [FlattenException::class, LegacyFlattenException::class], true))) { + $arguments = $event->getArguments(); + $arguments[$k] = FlattenException::createFromThrowable($e); + $event->setArguments($arguments); + } + } + + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::CONTROLLER_ARGUMENTS => 'onControllerArguments', + KernelEvents::EXCEPTION => [ + ['logKernelException', 0], + ['onKernelException', -128], + ], + ]; + } + + /** + * Logs an exception. + */ + protected function logException(\Throwable $exception, string $message): void + { + if (null !== $this->logger) { + if (!$exception instanceof HttpExceptionInterface || $exception->getStatusCode() >= 500) { + $this->logger->critical($message, ['exception' => $exception]); + } else { + $this->logger->error($message, ['exception' => $exception]); + } + } + } + + /** + * Clones the request for the exception. + */ + protected function duplicateRequest(\Throwable $exception, Request $request): Request + { + $attributes = [ + '_controller' => $this->controller, + 'exception' => $exception, + 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, + ]; + $request = $request->duplicate(null, null, $attributes); + $request->setMethod('GET'); + + return $request; + } +} diff --git a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php index e7e36d18..ef5a71a3 100644 --- a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php +++ b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php @@ -12,21 +12,20 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; -use Symfony\Component\Debug\Exception\FlattenException; +use Symfony\Component\ErrorHandler\Exception\FlattenException; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.4, use "ErrorListener" instead.', ExceptionListener::class), \E_USER_DEPRECATED); + /** - * ExceptionListener. - * - * @author Fabien Potencier + * @deprecated since Symfony 4.4, use ErrorListener instead */ class ExceptionListener implements EventSubscriberInterface { @@ -41,20 +40,29 @@ public function __construct($controller, LoggerInterface $logger = null, $debug $this->debug = $debug; } + public function logKernelException(GetResponseForExceptionEvent $event) + { + $e = FlattenException::createFromThrowable($event->getException()); + + $this->logException($event->getException(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine())); + } + public function onKernelException(GetResponseForExceptionEvent $event) { + if (null === $this->controller) { + return; + } + $exception = $event->getException(); - $request = $event->getRequest(); + $request = $this->duplicateRequest($exception, $event->getRequest()); $eventDispatcher = \func_num_args() > 2 ? func_get_arg(2) : null; - $this->logException($exception, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', \get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine())); - - $request = $this->duplicateRequest($exception, $request); - try { $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { - $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', \get_class($e), $e->getMessage(), $e->getFile(), $e->getLine())); + $f = FlattenException::createFromThrowable($e); + + $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); $prev = $e; do { @@ -73,7 +81,7 @@ public function onKernelException(GetResponseForExceptionEvent $event) $event->setResponse($response); if ($this->debug && $eventDispatcher instanceof EventDispatcherInterface) { - $cspRemovalListener = function (FilterResponseEvent $event) use (&$cspRemovalListener, $eventDispatcher) { + $cspRemovalListener = function ($event) use (&$cspRemovalListener, $eventDispatcher) { $event->getResponse()->headers->remove('Content-Security-Policy'); $eventDispatcher->removeListener(KernelEvents::RESPONSE, $cspRemovalListener); }; @@ -84,7 +92,10 @@ public function onKernelException(GetResponseForExceptionEvent $event) public static function getSubscribedEvents() { return [ - KernelEvents::EXCEPTION => ['onKernelException', -128], + KernelEvents::EXCEPTION => [ + ['logKernelException', 0], + ['onKernelException', -128], + ], ]; } @@ -108,16 +119,13 @@ protected function logException(\Exception $exception, $message) /** * Clones the request for the exception. * - * @param \Exception $exception The thrown exception - * @param Request $request The original request - * * @return Request The cloned request */ protected function duplicateRequest(\Exception $exception, Request $request) { $attributes = [ '_controller' => $this->controller, - 'exception' => FlattenException::create($exception), + 'exception' => FlattenException::createFromThrowable($exception), 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, ]; $request = $request->duplicate(null, null, $attributes); diff --git a/vendor/symfony/http-kernel/EventListener/FragmentListener.php b/vendor/symfony/http-kernel/EventListener/FragmentListener.php index 997f260d..5ae61daa 100644 --- a/vendor/symfony/http-kernel/EventListener/FragmentListener.php +++ b/vendor/symfony/http-kernel/EventListener/FragmentListener.php @@ -28,6 +28,8 @@ * is not signed or if it is not an internal sub-request. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class FragmentListener implements EventSubscriberInterface { @@ -35,10 +37,9 @@ class FragmentListener implements EventSubscriberInterface private $fragmentPath; /** - * @param UriSigner $signer A UriSigner instance - * @param string $fragmentPath The path that triggers this listener + * @param string $fragmentPath The path that triggers this listener */ - public function __construct(UriSigner $signer, $fragmentPath = '/_fragment') + public function __construct(UriSigner $signer, string $fragmentPath = '/_fragment') { $this->signer = $signer; $this->fragmentPath = $fragmentPath; @@ -77,7 +78,7 @@ public function onKernelRequest(GetResponseEvent $event) protected function validateRequest(Request $request) { // is the Request safe? - if (!$request->isMethodSafe(false)) { + if (!$request->isMethodSafe()) { throw new AccessDeniedHttpException(); } diff --git a/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php b/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php new file mode 100644 index 00000000..62d03026 --- /dev/null +++ b/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +/** + * Pass the current locale to the provided services. + * + * @author Pierre Bobiet + */ +class LocaleAwareListener implements EventSubscriberInterface +{ + private $localeAwareServices; + private $requestStack; + + /** + * @param LocaleAwareInterface[] $localeAwareServices + */ + public function __construct(iterable $localeAwareServices, RequestStack $requestStack) + { + $this->localeAwareServices = $localeAwareServices; + $this->requestStack = $requestStack; + } + + public function onKernelRequest(RequestEvent $event): void + { + $this->setLocale($event->getRequest()->getLocale(), $event->getRequest()->getDefaultLocale()); + } + + public function onKernelFinishRequest(FinishRequestEvent $event): void + { + if (null === $parentRequest = $this->requestStack->getParentRequest()) { + foreach ($this->localeAwareServices as $service) { + $service->setLocale($event->getRequest()->getDefaultLocale()); + } + + return; + } + + $this->setLocale($parentRequest->getLocale(), $parentRequest->getDefaultLocale()); + } + + public static function getSubscribedEvents() + { + return [ + // must be registered after the Locale listener + KernelEvents::REQUEST => [['onKernelRequest', 15]], + KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', -15]], + ]; + } + + private function setLocale(string $locale, string $defaultLocale): void + { + foreach ($this->localeAwareServices as $service) { + try { + $service->setLocale($locale); + } catch (\InvalidArgumentException $e) { + $service->setLocale($defaultLocale); + } + } + } +} diff --git a/vendor/symfony/http-kernel/EventListener/LocaleListener.php b/vendor/symfony/http-kernel/EventListener/LocaleListener.php index c7e32dbb..b09a6c76 100644 --- a/vendor/symfony/http-kernel/EventListener/LocaleListener.php +++ b/vendor/symfony/http-kernel/EventListener/LocaleListener.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\KernelEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Routing\RequestContextAwareInterface; @@ -23,6 +24,8 @@ * Initializes the locale based on the current request. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class LocaleListener implements EventSubscriberInterface { @@ -30,22 +33,21 @@ class LocaleListener implements EventSubscriberInterface private $defaultLocale; private $requestStack; - /** - * @param RequestStack $requestStack A RequestStack instance - * @param string $defaultLocale The default locale - * @param RequestContextAwareInterface|null $router The router - */ - public function __construct(RequestStack $requestStack, $defaultLocale = 'en', RequestContextAwareInterface $router = null) + public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null) { $this->defaultLocale = $defaultLocale; $this->requestStack = $requestStack; $this->router = $router; } + public function setDefaultLocale(KernelEvent $event) + { + $event->getRequest()->setDefaultLocale($this->defaultLocale); + } + public function onKernelRequest(GetResponseEvent $event) { $request = $event->getRequest(); - $request->setDefaultLocale($this->defaultLocale); $this->setLocale($request); $this->setRouterContext($request); @@ -75,8 +77,11 @@ private function setRouterContext(Request $request) public static function getSubscribedEvents() { return [ - // must be registered after the Router to have access to the _locale - KernelEvents::REQUEST => [['onKernelRequest', 16]], + KernelEvents::REQUEST => [ + ['setDefaultLocale', 100], + // must be registered after the Router to have access to the _locale + ['onKernelRequest', 16], + ], KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], ]; } diff --git a/vendor/symfony/http-kernel/EventListener/ProfilerListener.php b/vendor/symfony/http-kernel/EventListener/ProfilerListener.php index 5304b809..32e80922 100644 --- a/vendor/symfony/http-kernel/EventListener/ProfilerListener.php +++ b/vendor/symfony/http-kernel/EventListener/ProfilerListener.php @@ -12,8 +12,10 @@ namespace Symfony\Component\HttpKernel\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestMatcherInterface; use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Event\PostResponseEvent; @@ -24,6 +26,8 @@ * ProfilerListener collects data for the current request by listening to the kernel events. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class ProfilerListener implements EventSubscriberInterface { @@ -37,18 +41,15 @@ class ProfilerListener implements EventSubscriberInterface protected $parents; /** - * @param Profiler $profiler A Profiler instance - * @param RequestStack $requestStack A RequestStack instance - * @param RequestMatcherInterface|null $matcher A RequestMatcher instance - * @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise - * @param bool $onlyMasterRequests True if the profiler only collects data when the request is a master request, false otherwise + * @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise + * @param bool $onlyMasterRequests True if the profiler only collects data when the request is a master request, false otherwise */ - public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, $onlyException = false, $onlyMasterRequests = false) + public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMasterRequests = false) { $this->profiler = $profiler; $this->matcher = $matcher; - $this->onlyException = (bool) $onlyException; - $this->onlyMasterRequests = (bool) $onlyMasterRequests; + $this->onlyException = $onlyException; + $this->onlyMasterRequests = $onlyMasterRequests; $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); $this->requestStack = $requestStack; @@ -63,7 +64,7 @@ public function onKernelException(GetResponseForExceptionEvent $event) return; } - $this->exception = $event->getException(); + $this->exception = $event->getThrowable(); } /** @@ -88,8 +89,21 @@ public function onKernelResponse(FilterResponseEvent $event) return; } - if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { - return; + $session = method_exists(Request::class, 'getPreferredFormat') && $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null; + + if ($session instanceof Session) { + $usageIndexValue = $usageIndexReference = &$session->getUsageIndex(); + $usageIndexReference = \PHP_INT_MIN; + } + + try { + if (!$profile = $this->profiler->collect($request, $event->getResponse(), $exception)) { + return; + } + } finally { + if ($session instanceof Session) { + $usageIndexReference = $usageIndexValue; + } } $this->profiles[$request] = $profile; @@ -121,7 +135,7 @@ public static function getSubscribedEvents() { return [ KernelEvents::RESPONSE => ['onKernelResponse', -100], - KernelEvents::EXCEPTION => 'onKernelException', + KernelEvents::EXCEPTION => ['onKernelException', 0], KernelEvents::TERMINATE => ['onKernelTerminate', -1024], ]; } diff --git a/vendor/symfony/http-kernel/EventListener/ResponseListener.php b/vendor/symfony/http-kernel/EventListener/ResponseListener.php index 43527b7f..01973e22 100644 --- a/vendor/symfony/http-kernel/EventListener/ResponseListener.php +++ b/vendor/symfony/http-kernel/EventListener/ResponseListener.php @@ -19,12 +19,14 @@ * ResponseListener fixes the Response headers based on the Request. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class ResponseListener implements EventSubscriberInterface { private $charset; - public function __construct($charset) + public function __construct(string $charset) { $this->charset = $charset; } diff --git a/vendor/symfony/http-kernel/EventListener/RouterListener.php b/vendor/symfony/http-kernel/EventListener/RouterListener.php index 3803105e..47ee87b1 100644 --- a/vendor/symfony/http-kernel/EventListener/RouterListener.php +++ b/vendor/symfony/http-kernel/EventListener/RouterListener.php @@ -37,6 +37,8 @@ * * @author Fabien Potencier * @author Yonel Ceruto + * + * @final since Symfony 4.3 */ class RouterListener implements EventSubscriberInterface { @@ -48,16 +50,13 @@ class RouterListener implements EventSubscriberInterface private $debug; /** - * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher - * @param RequestStack $requestStack A RequestStack instance - * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) - * @param LoggerInterface|null $logger The logger + * @param UrlMatcherInterface|RequestMatcherInterface $matcher The Url or Request matcher + * @param RequestContext|null $context The RequestContext (can be null when $matcher implements RequestContextAwareInterface) * @param string $projectDir - * @param bool $debug * * @throws \InvalidArgumentException */ - public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, $projectDir = null, $debug = true) + public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, string $projectDir = null, bool $debug = true) { if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); @@ -117,7 +116,7 @@ public function onKernelRequest(GetResponseEvent $event) if (null !== $this->logger) { $this->logger->info('Matched route "{route}".', [ - 'route' => isset($parameters['_route']) ? $parameters['_route'] : 'n/a', + 'route' => $parameters['_route'] ?? 'n/a', 'route_parameters' => $parameters, 'request_uri' => $request->getUri(), 'method' => $request->getMethod(), @@ -144,7 +143,7 @@ public function onKernelRequest(GetResponseEvent $event) public function onKernelException(GetResponseForExceptionEvent $event) { - if (!$this->debug || !($e = $event->getException()) instanceof NotFoundHttpException) { + if (!$this->debug || !($e = $event->getThrowable()) instanceof NotFoundHttpException) { return; } @@ -162,14 +161,14 @@ public static function getSubscribedEvents() ]; } - private function createWelcomeResponse() + private function createWelcomeResponse(): Response { $version = Kernel::VERSION; - $baseDir = realpath($this->projectDir).\DIRECTORY_SEPARATOR; + $projectDir = realpath((string) $this->projectDir).\DIRECTORY_SEPARATOR; $docVersion = substr(Kernel::VERSION, 0, 3); ob_start(); - include __DIR__.'/../Resources/welcome.html.php'; + include \dirname(__DIR__).'/Resources/welcome.html.php'; return new Response(ob_get_clean(), Response::HTTP_NOT_FOUND); } diff --git a/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php b/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php index 5f5cd248..c3adaf84 100644 --- a/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php @@ -11,36 +11,16 @@ namespace Symfony\Component\HttpKernel\EventListener; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1, use AbstractSessionListener instead.', SaveSessionListener::class), \E_USER_DEPRECATED); + use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** - * Saves the session, in case it is still open, before sending the response/headers. - * - * This ensures several things in case the developer did not save the session explicitly: - * - * * If a session save handler without locking is used, it ensures the data is available - * on the next request, e.g. after a redirect. PHPs auto-save at script end via - * session_register_shutdown is executed after fastcgi_finish_request. So in this case - * the data could be missing the next request because it might not be saved the moment - * the new request is processed. - * * A locking save handler (e.g. the native 'files') circumvents concurrency problems like - * the one above. But by saving the session before long-running things in the terminate event, - * we ensure the session is not blocked longer than needed. - * * When regenerating the session ID no locking is involved in PHPs session design. See - * https://bugs.php.net/61470 for a discussion. So in this case, the session must - * be saved anyway before sending the headers with the new session ID. Otherwise session - * data could get lost again for concurrent requests with the new ID. One result could be - * that you get logged out after just logging in. - * - * This listener should be executed as one of the last listeners, so that previous listeners - * can still operate on the open session. This prevents the overhead of restarting it. - * Listeners after closing the session can still work with the session as usual because - * Symfonys session implementation starts the session on demand. So writing to it after - * it is saved will just restart it. - * * @author Tobias Schultze + * + * @deprecated since Symfony 4.1, use AbstractSessionListener instead */ class SaveSessionListener implements EventSubscriberInterface { @@ -50,8 +30,8 @@ public function onKernelResponse(FilterResponseEvent $event) return; } - $session = $event->getRequest()->getSession(); - if ($session && $session->isStarted()) { + $request = $event->getRequest(); + if ($request->hasSession() && ($session = $request->getSession())->isStarted()) { $session->save(); } } diff --git a/vendor/symfony/http-kernel/EventListener/SessionListener.php b/vendor/symfony/http-kernel/EventListener/SessionListener.php index 9e36b762..6cff47b8 100644 --- a/vendor/symfony/http-kernel/EventListener/SessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/SessionListener.php @@ -12,24 +12,46 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; +use Symfony\Component\HttpKernel\Event\GetResponseEvent; /** * Sets the session in the request. * + * When the passed container contains a "session_storage" entry which + * holds a NativeSessionStorage instance, the "cookie_secure" option + * will be set to true whenever the current master request is secure. + * * @author Fabien Potencier * - * @final since version 3.3 + * @final */ class SessionListener extends AbstractSessionListener { - private $container; - public function __construct(ContainerInterface $container) { $this->container = $container; } - protected function getSession() + public function onKernelRequest(GetResponseEvent $event) + { + parent::onKernelRequest($event); + + if (!$event->isMasterRequest() || !$this->container->has('session')) { + return; + } + + if ($this->container->has('session_storage') + && ($storage = $this->container->get('session_storage')) instanceof NativeSessionStorage + && ($masterRequest = $this->container->get('request_stack')->getMasterRequest()) + && $masterRequest->isSecure() + ) { + $storage->setOptions(['cookie_secure' => true]); + } + } + + protected function getSession(): ?SessionInterface { if (!$this->container->has('session')) { return null; diff --git a/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php b/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php index 895176a9..f28f5d86 100644 --- a/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php +++ b/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php @@ -21,6 +21,8 @@ * to the client. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class StreamedResponseListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/SurrogateListener.php b/vendor/symfony/http-kernel/EventListener/SurrogateListener.php index 0fddddde..9c3e960b 100644 --- a/vendor/symfony/http-kernel/EventListener/SurrogateListener.php +++ b/vendor/symfony/http-kernel/EventListener/SurrogateListener.php @@ -21,6 +21,8 @@ * SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates. * * @author Fabien Potencier + * + * @final since Symfony 4.3 */ class SurrogateListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/TestSessionListener.php b/vendor/symfony/http-kernel/EventListener/TestSessionListener.php index e2c6f5c9..ff8b4aaa 100644 --- a/vendor/symfony/http-kernel/EventListener/TestSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/TestSessionListener.php @@ -12,24 +12,26 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; +use Symfony\Component\HttpFoundation\Session\SessionInterface; /** * Sets the session in the request. * * @author Fabien Potencier * - * @final since version 3.3 + * @final */ class TestSessionListener extends AbstractTestSessionListener { private $container; - public function __construct(ContainerInterface $container) + public function __construct(ContainerInterface $container, array $sessionOptions = []) { $this->container = $container; + parent::__construct($sessionOptions); } - protected function getSession() + protected function getSession(): ?SessionInterface { if (!$this->container->has('session')) { return null; diff --git a/vendor/symfony/http-kernel/EventListener/TranslatorListener.php b/vendor/symfony/http-kernel/EventListener/TranslatorListener.php index 0f506061..6851c3b9 100644 --- a/vendor/symfony/http-kernel/EventListener/TranslatorListener.php +++ b/vendor/symfony/http-kernel/EventListener/TranslatorListener.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpKernel\EventListener; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3 and will be removed in 5.0, use LocaleAwareListener instead.', TranslatorListener::class), \E_USER_DEPRECATED); + use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -18,19 +20,28 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\LocaleAwareInterface; /** * Synchronizes the locale between the request and the translator. * * @author Fabien Potencier + * + * @deprecated since Symfony 4.3, use LocaleAwareListener instead */ class TranslatorListener implements EventSubscriberInterface { private $translator; private $requestStack; - public function __construct(TranslatorInterface $translator, RequestStack $requestStack) + /** + * @param LocaleAwareInterface $translator + */ + public function __construct($translator, RequestStack $requestStack) { + if (!$translator instanceof TranslatorInterface && !$translator instanceof LocaleAwareInterface) { + throw new \TypeError(sprintf('Argument 1 passed to "%s()" must be an instance of "%s", "%s" given.', __METHOD__, LocaleAwareInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator))); + } $this->translator = $translator; $this->requestStack = $requestStack; } diff --git a/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php b/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php index 2e921869..69c86b40 100644 --- a/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php +++ b/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php @@ -19,6 +19,8 @@ * Validates Requests. * * @author Magnus Nordlander + * + * @final since Symfony 4.3 */ class ValidateRequestListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php b/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php index 05fe7c4a..f0c81111 100644 --- a/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php @@ -18,12 +18,12 @@ class AccessDeniedHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(403, $message, $previous, [], $code); + parent::__construct(403, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php b/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php index 683ef1a9..8eccce1e 100644 --- a/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php +++ b/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php @@ -17,12 +17,12 @@ class BadRequestHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(400, $message, $previous, [], $code); + parent::__construct(400, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/ConflictHttpException.php b/vendor/symfony/http-kernel/Exception/ConflictHttpException.php index aaf258a0..72b8aa12 100644 --- a/vendor/symfony/http-kernel/Exception/ConflictHttpException.php +++ b/vendor/symfony/http-kernel/Exception/ConflictHttpException.php @@ -17,12 +17,12 @@ class ConflictHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(409, $message, $previous, [], $code); + parent::__construct(409, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php b/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php new file mode 100644 index 00000000..54c80be9 --- /dev/null +++ b/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Exception; + +/** + * @author Grégoire Pineau + */ +class ControllerDoesNotReturnResponseException extends \LogicException +{ + public function __construct(string $message, callable $controller, string $file, int $line) + { + parent::__construct($message); + + if (!$controllerDefinition = $this->parseControllerDefinition($controller)) { + return; + } + + $this->file = $controllerDefinition['file']; + $this->line = $controllerDefinition['line']; + $r = new \ReflectionProperty(\Exception::class, 'trace'); + $r->setAccessible(true); + $r->setValue($this, array_merge([ + [ + 'line' => $line, + 'file' => $file, + ], + ], $this->getTrace())); + } + + private function parseControllerDefinition(callable $controller): ?array + { + if (\is_string($controller) && str_contains($controller, '::')) { + $controller = explode('::', $controller); + } + + if (\is_array($controller)) { + try { + $r = new \ReflectionMethod($controller[0], $controller[1]); + + return [ + 'file' => $r->getFileName(), + 'line' => $r->getEndLine(), + ]; + } catch (\ReflectionException $e) { + return null; + } + } + + if ($controller instanceof \Closure) { + $r = new \ReflectionFunction($controller); + + return [ + 'file' => $r->getFileName(), + 'line' => $r->getEndLine(), + ]; + } + + if (\is_object($controller)) { + $r = new \ReflectionClass($controller); + + try { + $line = $r->getMethod('__invoke')->getEndLine(); + } catch (\ReflectionException $e) { + $line = $r->getEndLine(); + } + + return [ + 'file' => $r->getFileName(), + 'line' => $line, + ]; + } + + return null; + } +} diff --git a/vendor/symfony/http-kernel/Exception/GoneHttpException.php b/vendor/symfony/http-kernel/Exception/GoneHttpException.php index f855ba02..6bba8159 100644 --- a/vendor/symfony/http-kernel/Exception/GoneHttpException.php +++ b/vendor/symfony/http-kernel/Exception/GoneHttpException.php @@ -17,12 +17,12 @@ class GoneHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(410, $message, $previous, [], $code); + parent::__construct(410, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/HttpException.php b/vendor/symfony/http-kernel/Exception/HttpException.php index 809d29e6..f3c0c336 100644 --- a/vendor/symfony/http-kernel/Exception/HttpException.php +++ b/vendor/symfony/http-kernel/Exception/HttpException.php @@ -21,7 +21,7 @@ class HttpException extends \RuntimeException implements HttpExceptionInterface private $statusCode; private $headers; - public function __construct($statusCode, $message = null, \Exception $previous = null, array $headers = [], $code = 0) + public function __construct(int $statusCode, ?string $message = '', \Throwable $previous = null, array $headers = [], ?int $code = 0) { $this->statusCode = $statusCode; $this->headers = $headers; diff --git a/vendor/symfony/http-kernel/Exception/HttpExceptionInterface.php b/vendor/symfony/http-kernel/Exception/HttpExceptionInterface.php index 8aa50a9f..735e9c80 100644 --- a/vendor/symfony/http-kernel/Exception/HttpExceptionInterface.php +++ b/vendor/symfony/http-kernel/Exception/HttpExceptionInterface.php @@ -16,7 +16,7 @@ * * @author Kris Wallsmith */ -interface HttpExceptionInterface +interface HttpExceptionInterface extends \Throwable { /** * Returns the status code. diff --git a/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php b/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php index 8ad08f42..92f9c74d 100644 --- a/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php +++ b/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php @@ -17,12 +17,12 @@ class LengthRequiredHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(411, $message, $previous, [], $code); + parent::__construct(411, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php b/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php index f256ef86..665ae355 100644 --- a/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php @@ -17,14 +17,14 @@ class MethodNotAllowedHttpException extends HttpException { /** - * @param array $allow An array of allowed methods - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string[] $allow An array of allowed methods + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int|null $code The internal exception code */ - public function __construct(array $allow, $message = null, \Exception $previous = null, $code = 0) + public function __construct(array $allow, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { - $headers = ['Allow' => strtoupper(implode(', ', $allow))]; + $headers['Allow'] = strtoupper(implode(', ', $allow)); parent::__construct(405, $message, $previous, $headers, $code); } diff --git a/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php b/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php index a48bbe70..a985e86b 100644 --- a/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php +++ b/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php @@ -17,12 +17,12 @@ class NotAcceptableHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(406, $message, $previous, [], $code); + parent::__construct(406, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php b/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php index 01a5bd08..3be305ee 100644 --- a/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php +++ b/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php @@ -17,12 +17,12 @@ class NotFoundHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(404, $message, $previous, [], $code); + parent::__construct(404, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php b/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php index 3cf33f98..bdedea14 100644 --- a/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php @@ -17,12 +17,12 @@ class PreconditionFailedHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(412, $message, $previous, [], $code); + parent::__construct(412, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php b/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php index a2512c5c..bc268048 100644 --- a/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php +++ b/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php @@ -19,12 +19,12 @@ class PreconditionRequiredHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(428, $message, $previous, [], $code); + parent::__construct(428, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php b/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php index 52ce7513..1fb793db 100644 --- a/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php +++ b/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php @@ -17,16 +17,15 @@ class ServiceUnavailableHttpException extends HttpException { /** - * @param int|string $retryAfter The number of seconds or HTTP-date after which the request may be retried - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int|null $code The internal exception code */ - public function __construct($retryAfter = null, $message = null, \Exception $previous = null, $code = 0) + public function __construct($retryAfter = null, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { - $headers = []; if ($retryAfter) { - $headers = ['Retry-After' => $retryAfter]; + $headers['Retry-After'] = $retryAfter; } parent::__construct(503, $message, $previous, $headers, $code); diff --git a/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php b/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php index d313f7ea..e1e47d04 100644 --- a/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php +++ b/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php @@ -19,16 +19,15 @@ class TooManyRequestsHttpException extends HttpException { /** - * @param int|string $retryAfter The number of seconds or HTTP-date after which the request may be retried - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param int|string|null $retryAfter The number of seconds or HTTP-date after which the request may be retried + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int|null $code The internal exception code */ - public function __construct($retryAfter = null, $message = null, \Exception $previous = null, $code = 0) + public function __construct($retryAfter = null, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { - $headers = []; if ($retryAfter) { - $headers = ['Retry-After' => $retryAfter]; + $headers['Retry-After'] = $retryAfter; } parent::__construct(429, $message, $previous, $headers, $code); diff --git a/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php b/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php index d945df2b..ddb48f11 100644 --- a/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php @@ -17,14 +17,14 @@ class UnauthorizedHttpException extends HttpException { /** - * @param string $challenge WWW-Authenticate challenge string - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string $challenge WWW-Authenticate challenge string + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int|null $code The internal exception code */ - public function __construct($challenge, $message = null, \Exception $previous = null, $code = 0) + public function __construct(string $challenge, ?string $message = '', \Throwable $previous = null, ?int $code = 0, array $headers = []) { - $headers = ['WWW-Authenticate' => $challenge]; + $headers['WWW-Authenticate'] = $challenge; parent::__construct(401, $message, $previous, $headers, $code); } diff --git a/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php b/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php index 2263a312..237340a5 100644 --- a/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php @@ -17,12 +17,12 @@ class UnprocessableEntityHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(422, $message, $previous, [], $code); + parent::__construct(422, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php b/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php index 75f844ab..74ddbfcc 100644 --- a/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php @@ -17,12 +17,12 @@ class UnsupportedMediaTypeHttpException extends HttpException { /** - * @param string $message The internal exception message - * @param \Exception $previous The previous exception - * @param int $code The internal exception code + * @param string|null $message The internal exception message + * @param \Throwable|null $previous The previous exception + * @param int $code The internal exception code */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(?string $message = '', \Throwable $previous = null, int $code = 0, array $headers = []) { - parent::__construct(415, $message, $previous, [], $code); + parent::__construct(415, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php index 3d050c88..f59f8624 100644 --- a/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php @@ -32,9 +32,7 @@ abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRendere * The "fallback" strategy when surrogate is not available should always be an * instance of InlineFragmentRenderer. * - * @param SurrogateInterface $surrogate An Surrogate instance * @param FragmentRendererInterface $inlineStrategy The inline strategy to use when the surrogate is not supported - * @param UriSigner $signer */ public function __construct(SurrogateInterface $surrogate = null, FragmentRendererInterface $inlineStrategy, UriSigner $signer = null) { @@ -63,7 +61,7 @@ public function render($uri, Request $request, array $options = []) { if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) { if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) { - @trigger_error('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is deprecated since Symfony 3.1, and will be removed in 4.0. Use a different rendering strategy or pass scalar values.', \E_USER_DEPRECATED); + throw new \InvalidArgumentException('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.'); } return $this->inlineStrategy->render($uri, $request, $options); @@ -73,17 +71,17 @@ public function render($uri, Request $request, array $options = []) $uri = $this->generateSignedFragmentUri($uri, $request); } - $alt = isset($options['alt']) ? $options['alt'] : null; + $alt = $options['alt'] ?? null; if ($alt instanceof ControllerReference) { $alt = $this->generateSignedFragmentUri($alt, $request); } - $tag = $this->surrogate->renderIncludeTag($uri, $alt, isset($options['ignore_errors']) ? $options['ignore_errors'] : false, isset($options['comment']) ? $options['comment'] : ''); + $tag = $this->surrogate->renderIncludeTag($uri, $alt, $options['ignore_errors'] ?? false, $options['comment'] ?? ''); return new Response($tag); } - private function generateSignedFragmentUri($uri, Request $request) + private function generateSignedFragmentUri(ControllerReference $uri, Request $request): string { if (null === $this->signer) { throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.'); @@ -95,12 +93,14 @@ private function generateSignedFragmentUri($uri, Request $request) return substr($fragmentUri, \strlen($request->getSchemeAndHttpHost())); } - private function containsNonScalars(array $values) + private function containsNonScalars(array $values): bool { foreach ($values as $value) { - if (\is_array($value)) { - return $this->containsNonScalars($value); - } elseif (!is_scalar($value) && null !== $value) { + if (\is_scalar($value) || null === $value) { + continue; + } + + if (!\is_array($value) || $this->containsNonScalars($value)) { return true; } } diff --git a/vendor/symfony/http-kernel/Fragment/FragmentHandler.php b/vendor/symfony/http-kernel/Fragment/FragmentHandler.php index b98b1779..e981291b 100644 --- a/vendor/symfony/http-kernel/Fragment/FragmentHandler.php +++ b/vendor/symfony/http-kernel/Fragment/FragmentHandler.php @@ -33,11 +33,10 @@ class FragmentHandler private $requestStack; /** - * @param RequestStack $requestStack The Request stack that controls the lifecycle of requests - * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances - * @param bool $debug Whether the debug mode is enabled or not + * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances + * @param bool $debug Whether the debug mode is enabled or not */ - public function __construct(RequestStack $requestStack, array $renderers = [], $debug = false) + public function __construct(RequestStack $requestStack, array $renderers = [], bool $debug = false) { $this->requestStack = $requestStack; foreach ($renderers as $renderer) { @@ -63,7 +62,6 @@ public function addRenderer(FragmentRendererInterface $renderer) * * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance * @param string $renderer The renderer name - * @param array $options An array of options * * @return string|null The Response content or null when the Response is streamed * diff --git a/vendor/symfony/http-kernel/Fragment/FragmentRendererInterface.php b/vendor/symfony/http-kernel/Fragment/FragmentRendererInterface.php index 8e454a01..4f8ac50b 100644 --- a/vendor/symfony/http-kernel/Fragment/FragmentRendererInterface.php +++ b/vendor/symfony/http-kernel/Fragment/FragmentRendererInterface.php @@ -25,9 +25,7 @@ interface FragmentRendererInterface /** * Renders a URI and returns the Response content. * - * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance - * @param Request $request A Request instance - * @param array $options An array of options + * @param string|ControllerReference $uri A URI as a string or a ControllerReference instance * * @return Response A Response instance */ diff --git a/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php index ed0188c5..9004102f 100644 --- a/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php @@ -35,11 +35,9 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer /** * @param EngineInterface|Environment $templating An EngineInterface or a Twig instance - * @param UriSigner $signer A UriSigner instance * @param string $globalDefaultTemplate The global default content (it can be a template name or the content) - * @param string $charset */ - public function __construct($templating = null, UriSigner $signer = null, $globalDefaultTemplate = null, $charset = 'utf-8') + public function __construct($templating = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8') { $this->setTemplating($templating); $this->globalDefaultTemplate = $globalDefaultTemplate; @@ -53,6 +51,8 @@ public function __construct($templating = null, UriSigner $signer = null, $globa * @param EngineInterface|Environment|null $templating An EngineInterface or an Environment instance * * @throws \InvalidArgumentException + * + * @internal */ public function setTemplating($templating) { @@ -60,6 +60,10 @@ public function setTemplating($templating) throw new \InvalidArgumentException('The hinclude rendering strategy needs an instance of Twig\Environment or Symfony\Component\Templating\EngineInterface.'); } + if ($templating instanceof EngineInterface) { + @trigger_error(sprintf('Using a "%s" instance for "%s" is deprecated since version 4.3; use a \Twig\Environment instance instead.', EngineInterface::class, __CLASS__), \E_USER_DEPRECATED); + } + $this->templating = $templating; } @@ -96,7 +100,7 @@ public function render($uri, Request $request, array $options = []) // We need to replace ampersands in the URI with the encoded form in order to return valid html/xml content. $uri = str_replace('&', '&', $uri); - $template = isset($options['default']) ? $options['default'] : $this->globalDefaultTemplate; + $template = $options['default'] ?? $this->globalDefaultTemplate; if (null !== $this->templating && $template && $this->templateExists($template)) { $content = $this->templating->render($template); } else { @@ -122,12 +126,7 @@ public function render($uri, Request $request, array $options = []) return new Response(sprintf('%s', $uri, $renderedAttributes, $content)); } - /** - * @param string $template - * - * @return bool - */ - private function templateExists($template) + private function templateExists(string $template): bool { if ($this->templating instanceof EngineInterface) { try { diff --git a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php index ce88bd45..8f89733b 100644 --- a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php @@ -11,14 +11,15 @@ namespace Symfony\Component\HttpKernel\Fragment; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; -use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * Implements the inline rendering strategy where the Request is rendered by the current HTTP kernel. @@ -33,7 +34,7 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer public function __construct(HttpKernelInterface $kernel, EventDispatcherInterface $dispatcher = null) { $this->kernel = $kernel; - $this->dispatcher = $dispatcher; + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); } /** @@ -82,9 +83,9 @@ public function render($uri, Request $request, array $options = []) // we dispatch the exception event to trigger the logging // the response that comes back is ignored if (isset($options['ignore_errors']) && $options['ignore_errors'] && $this->dispatcher) { - $event = new GetResponseForExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e); + $event = new ExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e); - $this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event); + $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION); } // let's clean up the output buffers that were created by the sub-request @@ -118,9 +119,12 @@ protected function createSubRequest($uri, Request $request) $subRequest->headers->set('Surrogate-Capability', $request->headers->get('Surrogate-Capability')); } - if ($session = $request->getSession()) { - $subRequest->setSession($session); + static $setSession; + + if (null === $setSession) { + $setSession = \Closure::bind(static function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class); } + $setSession($subRequest, $request); if ($request->get('_format')) { $subRequest->attributes->set('_format', $request->get('_format')); diff --git a/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php index 0c1b95d4..bd86a42d 100644 --- a/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/RoutableFragmentRenderer.php @@ -39,10 +39,8 @@ public function setFragmentPath($path) /** * Generates a fragment URI for a given controller. * - * @param ControllerReference $reference A ControllerReference instance - * @param Request $request A Request instance - * @param bool $absolute Whether to generate an absolute URL or not - * @param bool $strict Whether to allow non-scalar attributes or not + * @param bool $absolute Whether to generate an absolute URL or not + * @param bool $strict Whether to allow non-scalar attributes or not * * @return string A fragment URI */ @@ -77,12 +75,12 @@ protected function generateFragmentUri(ControllerReference $reference, Request $ return $request->getBaseUrl().$path; } - private function checkNonScalar($values) + private function checkNonScalar(array $values) { foreach ($values as $key => $value) { if (\is_array($value)) { $this->checkNonScalar($value); - } elseif (!is_scalar($value) && null !== $value) { + } elseif (!\is_scalar($value) && null !== $value) { throw new \LogicException(sprintf('Controller attributes cannot contain non-scalar/non-null values (value for key "%s" is not a scalar or null).', $key)); } } diff --git a/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php b/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php index 472d87e4..9301d0c1 100644 --- a/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php +++ b/vendor/symfony/http-kernel/HttpCache/AbstractSurrogate.php @@ -57,7 +57,7 @@ public function hasSurrogateCapability(Request $request) return false; } - return false !== strpos($value, sprintf('%s/1.0', strtoupper($this->getName()))); + return str_contains($value, sprintf('%s/1.0', strtoupper($this->getName()))); } /** @@ -95,7 +95,7 @@ public function handle(HttpCache $cache, $uri, $alt, $ignoreErrors) try { $response = $cache->handle($subRequest, HttpKernelInterface::SUB_REQUEST, true); - if (!$response->isSuccessful()) { + if (!$response->isSuccessful() && Response::HTTP_NOT_MODIFIED !== $response->getStatusCode()) { throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %d).', $subRequest->getUri(), $response->getStatusCode())); } diff --git a/vendor/symfony/http-kernel/HttpCache/Esi.php b/vendor/symfony/http-kernel/HttpCache/Esi.php index 3d461a7f..829f4ac6 100644 --- a/vendor/symfony/http-kernel/HttpCache/Esi.php +++ b/vendor/symfony/http-kernel/HttpCache/Esi.php @@ -37,7 +37,7 @@ public function getName() */ public function addSurrogateControl(Response $response) { - if (false !== strpos($response->getContent(), 'getContent(), 'headers->set('Surrogate-Control', 'content="ESI/1.0"'); } } @@ -97,7 +97,7 @@ public function process(Request $request, Response $response) $chunks[$i] = sprintf('surrogate->handle($this, %s, %s, %s) ?>'."\n", var_export($options['src'], true), - var_export(isset($options['alt']) ? $options['alt'] : '', true), + var_export($options['alt'] ?? '', true), isset($options['onerror']) && 'continue' === $options['onerror'] ? 'true' : 'false' ); ++$i; diff --git a/vendor/symfony/http-kernel/HttpCache/HttpCache.php b/vendor/symfony/http-kernel/HttpCache/HttpCache.php index 34717585..84b77c51 100644 --- a/vendor/symfony/http-kernel/HttpCache/HttpCache.php +++ b/vendor/symfony/http-kernel/HttpCache/HttpCache.php @@ -5,12 +5,14 @@ * * (c) Fabien Potencier * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* * This code is partially based on the Rack-Cache library by Ryan Tomayko, * which is released under the MIT license. * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. */ namespace Symfony\Component\HttpKernel\HttpCache; @@ -40,7 +42,14 @@ class HttpCache implements HttpKernelInterface, TerminableInterface * * The available options are: * - * * debug: If true, the traces are added as a HTTP header to ease debugging + * * debug If true, exceptions are thrown when things go wrong. Otherwise, the cache + * will try to carry on and deliver a meaningful response. + * + * * trace_level May be one of 'none', 'short' and 'full'. For 'short', a concise trace of the + * master request will be added as an HTTP header. 'full' will add traces for all + * requests (including ESI subrequests). (default: 'full' if in debug; 'none' otherwise) + * + * * trace_header Header name to use for traces. (default: X-Symfony-Cache) * * * default_ttl The number of seconds that a cache entry should be considered * fresh when no explicit freshness information is provided in @@ -87,7 +96,13 @@ public function __construct(HttpKernelInterface $kernel, StoreInterface $store, 'allow_revalidate' => false, 'stale_while_revalidate' => 2, 'stale_if_error' => 60, + 'trace_level' => 'none', + 'trace_header' => 'X-Symfony-Cache', ], $options); + + if (!isset($options['trace_level'])) { + $this->options['trace_level'] = $this->options['debug'] ? 'full' : 'none'; + } } /** @@ -110,6 +125,23 @@ public function getTraces() return $this->traces; } + private function addTraces(Response $response) + { + $traceString = null; + + if ('full' === $this->options['trace_level']) { + $traceString = $this->getLog(); + } + + if ('short' === $this->options['trace_level'] && $masterId = array_key_first($this->traces)) { + $traceString = implode('/', $this->traces[$masterId]); + } + + if (null !== $traceString) { + $response->headers->add([$this->options['trace_header'] => $traceString]); + } + } + /** * Returns a log message for the events of the last request processing. * @@ -177,7 +209,7 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ $this->traces[$this->getTraceKey($request)] = []; - if (!$request->isMethodSafe(false)) { + if (!$request->isMethodSafe()) { $response = $this->invalidate($request, $catch); } elseif ($request->headers->has('expect') || !$request->isMethodCacheable()) { $response = $this->pass($request, $catch); @@ -194,8 +226,8 @@ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQ $this->restoreResponseBody($request, $response); - if (HttpKernelInterface::MASTER_REQUEST === $type && $this->options['debug']) { - $response->headers->set('X-Symfony-Cache', $this->getLog()); + if (HttpKernelInterface::MASTER_REQUEST === $type) { + $this->addTraces($response); } if (null !== $this->surrogate) { @@ -226,8 +258,7 @@ public function terminate(Request $request, Response $response) /** * Forwards the Request to the backend without storing the Response in the cache. * - * @param Request $request A Request instance - * @param bool $catch Whether to process exceptions + * @param bool $catch Whether to process exceptions * * @return Response A Response instance */ @@ -241,8 +272,7 @@ protected function pass(Request $request, $catch = false) /** * Invalidates non-safe methods (like POST, PUT, and DELETE). * - * @param Request $request A Request instance - * @param bool $catch Whether to process exceptions + * @param bool $catch Whether to process exceptions * * @return Response A Response instance * @@ -290,8 +320,7 @@ protected function invalidate(Request $request, $catch = false) * the backend using conditional GET. When no matching cache entry is found, * it triggers "miss" processing. * - * @param Request $request A Request instance - * @param bool $catch Whether to process exceptions + * @param bool $catch Whether to process exceptions * * @return Response A Response instance * @@ -340,9 +369,7 @@ protected function lookup(Request $request, $catch = false) * The original request is used as a template for a conditional * GET request with the backend. * - * @param Request $request A Request instance - * @param Response $entry A Response instance to validate - * @param bool $catch Whether to process exceptions + * @param bool $catch Whether to process exceptions * * @return Response A Response instance */ @@ -357,7 +384,7 @@ protected function validate(Request $request, Response $entry, $catch = false) // add our cached last-modified validator if ($entry->headers->has('Last-Modified')) { - $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified')); + $subRequest->headers->set('If-Modified-Since', $entry->headers->get('Last-Modified')); } // Add our cached etag validator to the environment. @@ -366,7 +393,7 @@ protected function validate(Request $request, Response $entry, $catch = false) $cachedEtags = $entry->getEtag() ? [$entry->getEtag()] : []; $requestEtags = $request->getETags(); if ($etags = array_unique(array_merge($cachedEtags, $requestEtags))) { - $subRequest->headers->set('if_none_match', implode(', ', $etags)); + $subRequest->headers->set('If-None-Match', implode(', ', $etags)); } $response = $this->forward($subRequest, $catch, $entry); @@ -405,8 +432,7 @@ protected function validate(Request $request, Response $entry, $catch = false) * Unconditionally fetches a fresh response from the backend and * stores it in the cache if is cacheable. * - * @param Request $request A Request instance - * @param bool $catch Whether to process exceptions + * @param bool $catch Whether to process exceptions * * @return Response A Response instance */ @@ -420,8 +446,8 @@ protected function fetch(Request $request, $catch = false) } // avoid that the backend sends no content - $subRequest->headers->remove('if_modified_since'); - $subRequest->headers->remove('if_none_match'); + $subRequest->headers->remove('If-Modified-Since'); + $subRequest->headers->remove('If-None-Match'); $response = $this->forward($subRequest, $catch); @@ -641,10 +667,8 @@ protected function processResponseBody(Request $request, Response $response) /** * Checks if the Request includes authorization or other sensitive information * that should cause the Response to be considered private by default. - * - * @return bool true if the Request is private, false otherwise */ - private function isPrivateRequest(Request $request) + private function isPrivateRequest(Request $request): bool { foreach ($this->options['private_headers'] as $key) { $key = strtolower(str_replace('HTTP_', '', $key)); @@ -663,21 +687,16 @@ private function isPrivateRequest(Request $request) /** * Records that an event took place. - * - * @param Request $request A Request instance - * @param string $event The event name */ - private function record(Request $request, $event) + private function record(Request $request, string $event) { $this->traces[$this->getTraceKey($request)][] = $event; } /** * Calculates the key we use in the "trace" array for a given request. - * - * @return string */ - private function getTraceKey(Request $request) + private function getTraceKey(Request $request): string { $path = $request->getPathInfo(); if ($qs = $request->getQueryString()) { @@ -690,10 +709,8 @@ private function getTraceKey(Request $request) /** * Checks whether the given (cached) response may be served as "stale" when a revalidation * is currently in progress. - * - * @return bool true when the stale response may be served, false otherwise */ - private function mayServeStaleWhileRevalidate(Response $entry) + private function mayServeStaleWhileRevalidate(Response $entry): bool { $timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate'); @@ -701,17 +718,13 @@ private function mayServeStaleWhileRevalidate(Response $entry) $timeout = $this->options['stale_while_revalidate']; } - return abs($entry->getTtl()) < $timeout; + return abs($entry->getTtl() ?? 0) < $timeout; } /** * Waits for the store to release a locked entry. - * - * @param Request $request The request to wait for - * - * @return bool true if the lock was released before the internal timeout was hit; false if the wait timeout was exceeded */ - private function waitForLock(Request $request) + private function waitForLock(Request $request): bool { $wait = 0; while ($this->store->isLocked($request) && $wait < 100) { diff --git a/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php b/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php index aee689e1..17a7e87f 100644 --- a/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php +++ b/vendor/symfony/http-kernel/HttpCache/ResponseCacheStrategy.php @@ -27,12 +27,12 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface /** * Cache-Control headers that are sent to the final response if they appear in ANY of the responses. */ - private static $overrideDirectives = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate']; + private const OVERRIDE_DIRECTIVES = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate']; /** * Cache-Control headers that are sent to the final response if they appear in ALL of the responses. */ - private static $inheritDirectives = ['public', 'immutable']; + private const INHERIT_DIRECTIVES = ['public', 'immutable']; private $embeddedResponses = 0; private $isNotCacheableResponseEmbedded = false; @@ -60,13 +60,13 @@ public function add(Response $response) { ++$this->embeddedResponses; - foreach (self::$overrideDirectives as $directive) { + foreach (self::OVERRIDE_DIRECTIVES as $directive) { if ($response->headers->hasCacheControlDirective($directive)) { $this->flagDirectives[$directive] = true; } } - foreach (self::$inheritDirectives as $directive) { + foreach (self::INHERIT_DIRECTIVES as $directive) { if (false !== $this->flagDirectives[$directive]) { $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive); } @@ -81,12 +81,15 @@ public function add(Response $response) return; } - $this->storeRelativeAgeDirective('max-age', $response->headers->getCacheControlDirective('max-age'), $age); - $this->storeRelativeAgeDirective('s-maxage', $response->headers->getCacheControlDirective('s-maxage') ?: $response->headers->getCacheControlDirective('max-age'), $age); + $isHeuristicallyCacheable = $response->headers->hasCacheControlDirective('public'); + $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age') : null; + $this->storeRelativeAgeDirective('max-age', $maxAge, $age, $isHeuristicallyCacheable); + $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int) $response->headers->getCacheControlDirective('s-maxage') : $maxAge; + $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $age, $isHeuristicallyCacheable); $expires = $response->getExpires(); $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null; - $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0); + $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0, $isHeuristicallyCacheable); } /** @@ -153,10 +156,8 @@ public function update(Response $response) * RFC2616, Section 13.4. * * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 - * - * @return bool */ - private function willMakeFinalResponseUncacheable(Response $response) + private function willMakeFinalResponseUncacheable(Response $response): bool { // RFC2616: A response received with a status code of 200, 203, 300, 301 or 410 // MAY be stored by a cache […] unless a cache-control directive prohibits caching. @@ -199,15 +200,29 @@ private function willMakeFinalResponseUncacheable(Response $response) * we have to subtract the age so that the value is normalized for an age of 0. * * If the value is lower than the currently stored value, we update the value, to keep a rolling - * minimal value of each instruction. If the value is NULL, the directive will not be set on the final response. + * minimal value of each instruction. + * + * If the value is NULL and the isHeuristicallyCacheable parameter is false, the directive will + * not be set on the final response. In this case, not all responses had the directive set and no + * value can be found that satisfies the requirements of all responses. The directive will be dropped + * from the final response. * - * @param string $directive - * @param int|null $value - * @param int $age + * If the isHeuristicallyCacheable parameter is true, however, the current response has been marked + * as cacheable in a public (shared) cache, but did not provide an explicit lifetime that would serve + * as an upper bound. In this case, we can proceed and possibly keep the directive on the final response. */ - private function storeRelativeAgeDirective($directive, $value, $age) + private function storeRelativeAgeDirective(string $directive, ?int $value, int $age, bool $isHeuristicallyCacheable) { if (null === $value) { + if ($isHeuristicallyCacheable) { + /* + * See https://datatracker.ietf.org/doc/html/rfc7234#section-4.2.2 + * This particular response does not require maximum lifetime; heuristics might be applied. + * Other responses, however, might have more stringent requirements on maximum lifetime. + * So, return early here so that the final response can have the more limiting value set. + */ + return; + } $this->ageDirectives[$directive] = false; } diff --git a/vendor/symfony/http-kernel/HttpCache/Ssi.php b/vendor/symfony/http-kernel/HttpCache/Ssi.php index 6dba4e11..a2856f27 100644 --- a/vendor/symfony/http-kernel/HttpCache/Ssi.php +++ b/vendor/symfony/http-kernel/HttpCache/Ssi.php @@ -34,7 +34,7 @@ public function getName() */ public function addSurrogateControl(Response $response) { - if (false !== strpos($response->getContent(), '', $strategy->render('/', $request)->getContent()); - $this->assertEquals('', $strategy->render('/', $request, ['comment' => 'This is a comment'])->getContent(), 'Strategy options should not impact the ssi include tag'); - } - - public function testRenderControllerReference() - { - $signer = new UriSigner('foo'); - $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy(), $signer); - - $request = Request::create('/'); - $request->setLocale('fr'); - $request->headers->set('Surrogate-Capability', 'SSI/1.0'); - - $reference = new ControllerReference('main_controller', [], []); - $altReference = new ControllerReference('alt_controller', [], []); - - $this->assertEquals( - '', - $strategy->render($reference, $request, ['alt' => $altReference])->getContent() - ); - } - - public function testRenderControllerReferenceWithoutSignerThrowsException() - { - $this->expectException('LogicException'); - $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy()); - - $request = Request::create('/'); - $request->setLocale('fr'); - $request->headers->set('Surrogate-Capability', 'SSI/1.0'); - - $strategy->render(new ControllerReference('main_controller'), $request); - } - - public function testRenderAltControllerReferenceWithoutSignerThrowsException() - { - $this->expectException('LogicException'); - $strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy()); - - $request = Request::create('/'); - $request->setLocale('fr'); - $request->headers->set('Surrogate-Capability', 'SSI/1.0'); - - $strategy->render('/', $request, ['alt' => new ControllerReference('alt_controller')]); - } - - private function getInlineStrategy($called = false) - { - $inline = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer')->disableOriginalConstructor()->getMock(); - - if ($called) { - $inline->expects($this->once())->method('render'); - } - - return $inline; - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php deleted file mode 100644 index 2aca5459..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php +++ /dev/null @@ -1,244 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpCache\Esi; - -class EsiTest extends TestCase -{ - public function testHasSurrogateEsiCapability() - { - $esi = new Esi(); - - $request = Request::create('/'); - $request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"'); - $this->assertTrue($esi->hasSurrogateCapability($request)); - - $request = Request::create('/'); - $request->headers->set('Surrogate-Capability', 'foobar'); - $this->assertFalse($esi->hasSurrogateCapability($request)); - - $request = Request::create('/'); - $this->assertFalse($esi->hasSurrogateCapability($request)); - } - - public function testAddSurrogateEsiCapability() - { - $esi = new Esi(); - - $request = Request::create('/'); - $esi->addSurrogateCapability($request); - $this->assertEquals('symfony="ESI/1.0"', $request->headers->get('Surrogate-Capability')); - - $esi->addSurrogateCapability($request); - $this->assertEquals('symfony="ESI/1.0", symfony="ESI/1.0"', $request->headers->get('Surrogate-Capability')); - } - - public function testAddSurrogateControl() - { - $esi = new Esi(); - - $response = new Response('foo '); - $esi->addSurrogateControl($response); - $this->assertEquals('content="ESI/1.0"', $response->headers->get('Surrogate-Control')); - - $response = new Response('foo'); - $esi->addSurrogateControl($response); - $this->assertEquals('', $response->headers->get('Surrogate-Control')); - } - - public function testNeedsEsiParsing() - { - $esi = new Esi(); - - $response = new Response(); - $response->headers->set('Surrogate-Control', 'content="ESI/1.0"'); - $this->assertTrue($esi->needsParsing($response)); - - $response = new Response(); - $this->assertFalse($esi->needsParsing($response)); - } - - public function testRenderIncludeTag() - { - $esi = new Esi(); - - $this->assertEquals('', $esi->renderIncludeTag('/', '/alt', true)); - $this->assertEquals('', $esi->renderIncludeTag('/', '/alt', false)); - $this->assertEquals('', $esi->renderIncludeTag('/')); - $this->assertEquals(''."\n".'', $esi->renderIncludeTag('/', '/alt', true, 'some comment')); - } - - public function testProcessDoesNothingIfContentTypeIsNotHtml() - { - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response(); - $response->headers->set('Content-Type', 'text/plain'); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertFalse($response->headers->has('x-body-eval')); - } - - public function testMultilineEsiRemoveTagsAreRemoved() - { - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response(' www.example.com Keep this'."\n www.example.com And this"); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals(' Keep this And this', $response->getContent()); - } - - public function testCommentTagsAreRemoved() - { - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response(' Keep this'); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals(' Keep this', $response->getContent()); - } - - public function testProcess() - { - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response('foo '); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals('foo surrogate->handle($this, \'...\', \'alt\', true) ?>'."\n", $response->getContent()); - $this->assertEquals('ESI', $response->headers->get('x-body-eval')); - - $response = new Response('foo '); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals('foo surrogate->handle($this, \'foo\\\'\', \'bar\\\'\', true) ?>'."\n", $response->getContent()); - - $response = new Response('foo '); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals('foo surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent()); - - $response = new Response('foo '); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals('foo surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent()); - } - - public function testProcessEscapesPhpTags() - { - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response(''); - $this->assertSame($response, $esi->process($request, $response)); - - $this->assertEquals('php cript language=php>', $response->getContent()); - } - - public function testProcessWhenNoSrcInAnEsi() - { - $this->expectException('RuntimeException'); - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response('foo '); - $this->assertSame($response, $esi->process($request, $response)); - } - - public function testProcessRemoveSurrogateControlHeader() - { - $esi = new Esi(); - - $request = Request::create('/'); - $response = new Response('foo '); - $response->headers->set('Surrogate-Control', 'content="ESI/1.0"'); - $this->assertSame($response, $esi->process($request, $response)); - $this->assertEquals('ESI', $response->headers->get('x-body-eval')); - - $response->headers->set('Surrogate-Control', 'no-store, content="ESI/1.0"'); - $this->assertSame($response, $esi->process($request, $response)); - $this->assertEquals('ESI', $response->headers->get('x-body-eval')); - $this->assertEquals('no-store', $response->headers->get('surrogate-control')); - - $response->headers->set('Surrogate-Control', 'content="ESI/1.0", no-store'); - $this->assertSame($response, $esi->process($request, $response)); - $this->assertEquals('ESI', $response->headers->get('x-body-eval')); - $this->assertEquals('no-store', $response->headers->get('surrogate-control')); - } - - public function testHandle() - { - $esi = new Esi(); - $cache = $this->getCache(Request::create('/'), new Response('foo')); - $this->assertEquals('foo', $esi->handle($cache, '/', '/alt', true)); - } - - public function testHandleWhenResponseIsNot200() - { - $this->expectException('RuntimeException'); - $esi = new Esi(); - $response = new Response('foo'); - $response->setStatusCode(404); - $cache = $this->getCache(Request::create('/'), $response); - $esi->handle($cache, '/', '/alt', false); - } - - public function testHandleWhenResponseIsNot200AndErrorsAreIgnored() - { - $esi = new Esi(); - $response = new Response('foo'); - $response->setStatusCode(404); - $cache = $this->getCache(Request::create('/'), $response); - $this->assertEquals('', $esi->handle($cache, '/', '/alt', true)); - } - - public function testHandleWhenResponseIsNot200AndAltIsPresent() - { - $esi = new Esi(); - $response1 = new Response('foo'); - $response1->setStatusCode(404); - $response2 = new Response('bar'); - $cache = $this->getCache(Request::create('/'), [$response1, $response2]); - $this->assertEquals('bar', $esi->handle($cache, '/', '/alt', false)); - } - - protected function getCache($request, $response) - { - $cache = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpCache\HttpCache')->setMethods(['getRequest', 'handle'])->disableOriginalConstructor()->getMock(); - $cache->expects($this->any()) - ->method('getRequest') - ->willReturn($request) - ; - if (\is_array($response)) { - $cache->expects($this->any()) - ->method('handle') - ->will(\call_user_func_array([$this, 'onConsecutiveCalls'], $response)) - ; - } else { - $cache->expects($this->any()) - ->method('handle') - ->willReturn($response) - ; - } - - return $cache; - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php deleted file mode 100644 index d080598f..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php +++ /dev/null @@ -1,1702 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpCache\Esi; -use Symfony\Component\HttpKernel\HttpCache\HttpCache; -use Symfony\Component\HttpKernel\HttpCache\Store; -use Symfony\Component\HttpKernel\HttpKernelInterface; - -/** - * @group time-sensitive - */ -class HttpCacheTest extends HttpCacheTestCase -{ - public function testTerminateDelegatesTerminationOnlyForTerminableInterface() - { - $storeMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\HttpCache\\StoreInterface') - ->disableOriginalConstructor() - ->getMock(); - - // does not implement TerminableInterface - $kernel = new TestKernel(); - $httpCache = new HttpCache($kernel, $storeMock); - $httpCache->terminate(Request::create('/'), new Response()); - - $this->assertFalse($kernel->terminateCalled, 'terminate() is never called if the kernel class does not implement TerminableInterface'); - - // implements TerminableInterface - $kernelMock = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Kernel') - ->disableOriginalConstructor() - ->setMethods(['terminate', 'registerBundles', 'registerContainerConfiguration']) - ->getMock(); - - $kernelMock->expects($this->once()) - ->method('terminate'); - - $kernel = new HttpCache($kernelMock, $storeMock); - $kernel->terminate(Request::create('/'), new Response()); - } - - public function testPassesOnNonGetHeadRequests() - { - $this->setNextResponse(200); - $this->request('POST', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertResponseOk(); - $this->assertTraceContains('pass'); - $this->assertFalse($this->response->headers->has('Age')); - } - - public function testInvalidatesOnPostPutDeleteRequests() - { - foreach (['post', 'put', 'delete'] as $method) { - $this->setNextResponse(200); - $this->request($method, '/'); - - $this->assertHttpKernelIsCalled(); - $this->assertResponseOk(); - $this->assertTraceContains('invalidate'); - $this->assertTraceContains('pass'); - } - } - - public function testDoesNotCacheWithAuthorizationRequestHeaderAndNonPublicResponse() - { - $this->setNextResponse(200, ['ETag' => '"Foo"']); - $this->request('GET', '/', ['HTTP_AUTHORIZATION' => 'basic foobarbaz']); - - $this->assertHttpKernelIsCalled(); - $this->assertResponseOk(); - $this->assertEquals('private', $this->response->headers->get('Cache-Control')); - - $this->assertTraceContains('miss'); - $this->assertTraceNotContains('store'); - $this->assertFalse($this->response->headers->has('Age')); - } - - public function testDoesCacheWithAuthorizationRequestHeaderAndPublicResponse() - { - $this->setNextResponse(200, ['Cache-Control' => 'public', 'ETag' => '"Foo"']); - $this->request('GET', '/', ['HTTP_AUTHORIZATION' => 'basic foobarbaz']); - - $this->assertHttpKernelIsCalled(); - $this->assertResponseOk(); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertTrue($this->response->headers->has('Age')); - $this->assertEquals('public', $this->response->headers->get('Cache-Control')); - } - - public function testDoesNotCacheWithCookieHeaderAndNonPublicResponse() - { - $this->setNextResponse(200, ['ETag' => '"Foo"']); - $this->request('GET', '/', [], ['foo' => 'bar']); - - $this->assertHttpKernelIsCalled(); - $this->assertResponseOk(); - $this->assertEquals('private', $this->response->headers->get('Cache-Control')); - $this->assertTraceContains('miss'); - $this->assertTraceNotContains('store'); - $this->assertFalse($this->response->headers->has('Age')); - } - - public function testDoesNotCacheRequestsWithACookieHeader() - { - $this->setNextResponse(200); - $this->request('GET', '/', [], ['foo' => 'bar']); - - $this->assertHttpKernelIsCalled(); - $this->assertResponseOk(); - $this->assertEquals('private', $this->response->headers->get('Cache-Control')); - $this->assertTraceContains('miss'); - $this->assertTraceNotContains('store'); - $this->assertFalse($this->response->headers->has('Age')); - } - - public function testRespondsWith304WhenIfModifiedSinceMatchesLastModified() - { - $time = \DateTime::createFromFormat('U', time()); - - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Last-Modified' => $time->format(\DATE_RFC2822), 'Content-Type' => 'text/plain'], 'Hello World'); - $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => $time->format(\DATE_RFC2822)]); - - $this->assertHttpKernelIsCalled(); - $this->assertEquals(304, $this->response->getStatusCode()); - $this->assertEquals('', $this->response->headers->get('Content-Type')); - $this->assertEmpty($this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - } - - public function testRespondsWith304WhenIfNoneMatchMatchesETag() - { - $this->setNextResponse(200, ['Cache-Control' => 'public', 'ETag' => '12345', 'Content-Type' => 'text/plain'], 'Hello World'); - $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345']); - - $this->assertHttpKernelIsCalled(); - $this->assertEquals(304, $this->response->getStatusCode()); - $this->assertEquals('', $this->response->headers->get('Content-Type')); - $this->assertTrue($this->response->headers->has('ETag')); - $this->assertEmpty($this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - } - - public function testRespondsWith304OnlyIfIfNoneMatchAndIfModifiedSinceBothMatch() - { - $time = \DateTime::createFromFormat('U', time()); - - $this->setNextResponse(200, [], '', function ($request, $response) use ($time) { - $response->setStatusCode(200); - $response->headers->set('ETag', '12345'); - $response->headers->set('Last-Modified', $time->format(\DATE_RFC2822)); - $response->headers->set('Content-Type', 'text/plain'); - $response->setContent('Hello World'); - }); - - // only ETag matches - $t = \DateTime::createFromFormat('U', time() - 3600); - $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $t->format(\DATE_RFC2822)]); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - - // only Last-Modified matches - $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '1234', 'HTTP_IF_MODIFIED_SINCE' => $time->format(\DATE_RFC2822)]); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - - // Both matches - $this->request('GET', '/', ['HTTP_IF_NONE_MATCH' => '12345', 'HTTP_IF_MODIFIED_SINCE' => $time->format(\DATE_RFC2822)]); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(304, $this->response->getStatusCode()); - } - - public function testIncrementsMaxAgeWhenNoDateIsSpecifiedEventWhenUsingETag() - { - $this->setNextResponse( - 200, - [ - 'ETag' => '1234', - 'Cache-Control' => 'public, s-maxage=60', - ] - ); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - sleep(2); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('fresh'); - $this->assertEquals(2, $this->response->headers->get('Age')); - } - - public function testValidatesPrivateResponsesCachedOnTheClient() - { - $this->setNextResponse(200, [], '', function ($request, $response) { - $etags = preg_split('/\s*,\s*/', $request->headers->get('IF_NONE_MATCH')); - if ($request->cookies->has('authenticated')) { - $response->headers->set('Cache-Control', 'private, no-store'); - $response->setETag('"private tag"'); - if (\in_array('"private tag"', $etags)) { - $response->setStatusCode(304); - } else { - $response->setStatusCode(200); - $response->headers->set('Content-Type', 'text/plain'); - $response->setContent('private data'); - } - } else { - $response->headers->set('Cache-Control', 'public'); - $response->setETag('"public tag"'); - if (\in_array('"public tag"', $etags)) { - $response->setStatusCode(304); - } else { - $response->setStatusCode(200); - $response->headers->set('Content-Type', 'text/plain'); - $response->setContent('public data'); - } - } - }); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('"public tag"', $this->response->headers->get('ETag')); - $this->assertEquals('public data', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - $this->request('GET', '/', [], ['authenticated' => '']); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('"private tag"', $this->response->headers->get('ETag')); - $this->assertEquals('private data', $this->response->getContent()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('invalid'); - $this->assertTraceNotContains('store'); - } - - public function testStoresResponsesWhenNoCacheRequestDirectivePresent() - { - $time = \DateTime::createFromFormat('U', time() + 5); - - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\DATE_RFC2822)]); - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']); - - $this->assertHttpKernelIsCalled(); - $this->assertTraceContains('store'); - $this->assertTrue($this->response->headers->has('Age')); - } - - public function testReloadsResponsesWhenCacheHitsButNoCacheRequestDirectivePresentWhenAllowReloadIsSetTrue() - { - $count = 0; - - $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=10000'], '', function ($request, $response) use (&$count) { - ++$count; - $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World'); - }); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('store'); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('fresh'); - - $this->cacheConfig['allow_reload'] = true; - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Goodbye World', $this->response->getContent()); - $this->assertTraceContains('reload'); - $this->assertTraceContains('store'); - } - - public function testDoesNotReloadResponsesWhenAllowReloadIsSetFalseDefault() - { - $count = 0; - - $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=10000'], '', function ($request, $response) use (&$count) { - ++$count; - $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World'); - }); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('store'); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('fresh'); - - $this->cacheConfig['allow_reload'] = false; - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceNotContains('reload'); - - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'no-cache']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceNotContains('reload'); - } - - public function testRevalidatesFreshCacheEntryWhenMaxAgeRequestDirectiveIsExceededWhenAllowRevalidateOptionIsSetTrue() - { - $count = 0; - - $this->setNextResponse(200, [], '', function ($request, $response) use (&$count) { - ++$count; - $response->headers->set('Cache-Control', 'public, max-age=10000'); - $response->setETag($count); - $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World'); - }); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('store'); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('fresh'); - - $this->cacheConfig['allow_revalidate'] = true; - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'max-age=0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Goodbye World', $this->response->getContent()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('invalid'); - $this->assertTraceContains('store'); - } - - public function testDoesNotRevalidateFreshCacheEntryWhenEnableRevalidateOptionIsSetFalseDefault() - { - $count = 0; - - $this->setNextResponse(200, [], '', function ($request, $response) use (&$count) { - ++$count; - $response->headers->set('Cache-Control', 'public, max-age=10000'); - $response->setETag($count); - $response->setContent(1 == $count ? 'Hello World' : 'Goodbye World'); - }); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('store'); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('fresh'); - - $this->cacheConfig['allow_revalidate'] = false; - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'max-age=0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceNotContains('stale'); - $this->assertTraceNotContains('invalid'); - $this->assertTraceContains('fresh'); - - $this->request('GET', '/', ['HTTP_CACHE_CONTROL' => 'max-age=0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceNotContains('stale'); - $this->assertTraceNotContains('invalid'); - $this->assertTraceContains('fresh'); - } - - public function testFetchesResponseFromBackendWhenCacheMisses() - { - $time = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\DATE_RFC2822)]); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('miss'); - $this->assertTrue($this->response->headers->has('Age')); - } - - public function testDoesNotCacheSomeStatusCodeResponses() - { - foreach (array_merge(range(201, 202), range(204, 206), range(303, 305), range(400, 403), range(405, 409), range(411, 417), range(500, 505)) as $code) { - $time = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse($code, ['Expires' => $time->format(\DATE_RFC2822)]); - - $this->request('GET', '/'); - $this->assertEquals($code, $this->response->getStatusCode()); - $this->assertTraceNotContains('store'); - $this->assertFalse($this->response->headers->has('Age')); - } - } - - public function testDoesNotCacheResponsesWithExplicitNoStoreDirective() - { - $time = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse(200, ['Expires' => $time->format(\DATE_RFC2822), 'Cache-Control' => 'no-store']); - - $this->request('GET', '/'); - $this->assertTraceNotContains('store'); - $this->assertFalse($this->response->headers->has('Age')); - } - - public function testDoesNotCacheResponsesWithoutFreshnessInformationOrAValidator() - { - $this->setNextResponse(); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceNotContains('store'); - } - - public function testCachesResponsesWithExplicitNoCacheDirective() - { - $time = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse(200, ['Expires' => $time->format(\DATE_RFC2822), 'Cache-Control' => 'public, no-cache']); - - $this->request('GET', '/'); - $this->assertTraceContains('store'); - $this->assertTrue($this->response->headers->has('Age')); - } - - public function testRevalidatesResponsesWithNoCacheDirectiveEvenIfFresh() - { - $this->setNextResponse(200, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag'], 'OK'); - $this->request('GET', '/'); // warm the cache - - sleep(5); - - $this->setNextResponse(304, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag']); - $this->request('GET', '/'); - - $this->assertHttpKernelIsCalled(); // no-cache -> MUST have revalidated at origin - $this->assertTraceContains('valid'); - $this->assertEquals('OK', $this->response->getContent()); - $this->assertEquals(0, $this->response->getAge()); - } - - public function testCachesResponsesWithAnExpirationHeader() - { - $time = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\DATE_RFC2822)]); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - $values = $this->getMetaStorageValues(); - $this->assertCount(1, $values); - } - - public function testCachesResponsesWithAMaxAgeDirective() - { - $this->setNextResponse(200, ['Cache-Control' => 'public, max-age=5']); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - $values = $this->getMetaStorageValues(); - $this->assertCount(1, $values); - } - - public function testCachesResponsesWithASMaxAgeDirective() - { - $this->setNextResponse(200, ['Cache-Control' => 's-maxage=5']); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - $values = $this->getMetaStorageValues(); - $this->assertCount(1, $values); - } - - public function testCachesResponsesWithALastModifiedValidatorButNoFreshnessInformation() - { - $time = \DateTime::createFromFormat('U', time()); - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Last-Modified' => $time->format(\DATE_RFC2822)]); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - } - - public function testCachesResponsesWithAnETagValidatorButNoFreshnessInformation() - { - $this->setNextResponse(200, ['Cache-Control' => 'public', 'ETag' => '"123456"']); - - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - } - - public function testHitsCachedResponsesWithExpiresHeader() - { - $time1 = \DateTime::createFromFormat('U', time() - 5); - $time2 = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Date' => $time1->format(\DATE_RFC2822), 'Expires' => $time2->format(\DATE_RFC2822)]); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertLessThan(2, strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date'))); - $this->assertGreaterThan(0, $this->response->headers->get('Age')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - } - - public function testHitsCachedResponseWithMaxAgeDirective() - { - $time = \DateTime::createFromFormat('U', time() - 5); - $this->setNextResponse(200, ['Date' => $time->format(\DATE_RFC2822), 'Cache-Control' => 'public, max-age=10']); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertLessThan(2, strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date'))); - $this->assertGreaterThan(0, $this->response->headers->get('Age')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - } - - public function testDegradationWhenCacheLocked() - { - if ('\\' === \DIRECTORY_SEPARATOR) { - $this->markTestSkipped('Skips on windows to avoid permissions issues.'); - } - - $this->cacheConfig['stale_while_revalidate'] = 10; - - // The prescence of Last-Modified makes this cacheable (because Response::isValidateable() then). - $this->setNextResponse(200, ['Cache-Control' => 'public, s-maxage=5', 'Last-Modified' => 'some while ago'], 'Old response'); - $this->request('GET', '/'); // warm the cache - - // Now, lock the cache - $concurrentRequest = Request::create('/', 'GET'); - $this->store->lock($concurrentRequest); - - /* - * After 10s, the cached response has become stale. Yet, we're still within the "stale_while_revalidate" - * timeout so we may serve the stale response. - */ - sleep(10); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('stale-while-revalidate'); - $this->assertEquals('Old response', $this->response->getContent()); - - /* - * Another 10s later, stale_while_revalidate is over. Resort to serving the old response, but - * do so with a "server unavailable" message. - */ - sleep(10); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(503, $this->response->getStatusCode()); - $this->assertEquals('Old response', $this->response->getContent()); - } - - public function testHitsCachedResponseWithSMaxAgeDirective() - { - $time = \DateTime::createFromFormat('U', time() - 5); - $this->setNextResponse(200, ['Date' => $time->format(\DATE_RFC2822), 'Cache-Control' => 's-maxage=10, max-age=0']); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertLessThan(2, strtotime($this->responses[0]->headers->get('Date')) - strtotime($this->response->headers->get('Date'))); - $this->assertGreaterThan(0, $this->response->headers->get('Age')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - } - - public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformation() - { - $this->setNextResponse(); - - $this->cacheConfig['default_ttl'] = 10; - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=10/', $this->response->headers->get('Cache-Control')); - - $this->cacheConfig['default_ttl'] = 10; - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=10/', $this->response->headers->get('Cache-Control')); - } - - public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpired() - { - $this->setNextResponse(); - - $this->cacheConfig['default_ttl'] = 2; - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - - // expires the cache - $values = $this->getMetaStorageValues(); - $this->assertCount(1, $values); - $tmp = unserialize($values[0]); - $time = \DateTime::createFromFormat('U', time() - 5); - $tmp[0][1]['date'] = $time->format(\DATE_RFC2822); - $r = new \ReflectionObject($this->store); - $m = $r->getMethod('save'); - $m->setAccessible(true); - $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp)); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('invalid'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - - $this->setNextResponse(); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - } - - public function testAssignsDefaultTtlWhenResponseHasNoFreshnessInformationAndAfterTtlWasExpiredWithStatus304() - { - $this->setNextResponse(); - - $this->cacheConfig['default_ttl'] = 2; - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - - // expires the cache - $values = $this->getMetaStorageValues(); - $this->assertCount(1, $values); - $tmp = unserialize($values[0]); - $time = \DateTime::createFromFormat('U', time() - 5); - $tmp[0][1]['date'] = $time->format(\DATE_RFC2822); - $r = new \ReflectionObject($this->store); - $m = $r->getMethod('save'); - $m->setAccessible(true); - $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp)); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('valid'); - $this->assertTraceContains('store'); - $this->assertTraceNotContains('miss'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertMatchesRegularExpression('/s-maxage=(2|3)/', $this->response->headers->get('Cache-Control')); - } - - public function testDoesNotAssignDefaultTtlWhenResponseHasMustRevalidateDirective() - { - $this->setNextResponse(200, ['Cache-Control' => 'must-revalidate']); - - $this->cacheConfig['default_ttl'] = 10; - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('miss'); - $this->assertTraceNotContains('store'); - $this->assertDoesNotMatchRegularExpression('/s-maxage/', $this->response->headers->get('Cache-Control')); - $this->assertEquals('Hello World', $this->response->getContent()); - } - - public function testFetchesFullResponseWhenCacheStaleAndNoValidatorsPresent() - { - $time = \DateTime::createFromFormat('U', time() + 5); - $this->setNextResponse(200, ['Cache-Control' => 'public', 'Expires' => $time->format(\DATE_RFC2822)]); - - // build initial request - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('Date')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertNotNull($this->response->headers->get('Age')); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - - // go in and play around with the cached metadata directly ... - $values = $this->getMetaStorageValues(); - $this->assertCount(1, $values); - $tmp = unserialize($values[0]); - $time = \DateTime::createFromFormat('U', time()); - $tmp[0][1]['expires'] = $time->format(\DATE_RFC2822); - $r = new \ReflectionObject($this->store); - $m = $r->getMethod('save'); - $m->setAccessible(true); - $m->invoke($this->store, 'md'.hash('sha256', 'http://localhost/'), serialize($tmp)); - - // build subsequent request; should be found but miss due to freshness - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertLessThanOrEqual(1, $this->response->headers->get('Age')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertTraceContains('stale'); - $this->assertTraceNotContains('fresh'); - $this->assertTraceNotContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Hello World', $this->response->getContent()); - } - - public function testValidatesCachedResponsesWithLastModifiedAndNoFreshnessInformation() - { - $time = \DateTime::createFromFormat('U', time()); - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) use ($time) { - $response->headers->set('Cache-Control', 'public'); - $response->headers->set('Last-Modified', $time->format(\DATE_RFC2822)); - if ($time->format(\DATE_RFC2822) == $request->headers->get('IF_MODIFIED_SINCE')) { - $response->setStatusCode(304); - $response->setContent(''); - } - }); - - // build initial request - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('Last-Modified')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertTraceNotContains('stale'); - - // build subsequent request; should be found but miss due to freshness - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('Last-Modified')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertLessThanOrEqual(1, $this->response->headers->get('Age')); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('valid'); - $this->assertTraceContains('store'); - $this->assertTraceNotContains('miss'); - } - - public function testValidatesCachedResponsesUseSameHttpMethod() - { - $test = $this; - - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) use ($test) { - $test->assertSame('OPTIONS', $request->getMethod()); - }); - - // build initial request - $this->request('OPTIONS', '/'); - - // build subsequent request - $this->request('OPTIONS', '/'); - } - - public function testValidatesCachedResponsesWithETagAndNoFreshnessInformation() - { - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) { - $this->assertFalse($request->headers->has('If-Modified-Since')); - $response->headers->set('Cache-Control', 'public'); - $response->headers->set('ETag', '"12345"'); - if ($response->getETag() == $request->headers->get('IF_NONE_MATCH')) { - $response->setStatusCode(304); - $response->setContent(''); - } - }); - - // build initial request - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('ETag')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - // build subsequent request; should be found but miss due to freshness - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertNotNull($this->response->headers->get('ETag')); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $this->assertLessThanOrEqual(1, $this->response->headers->get('Age')); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('valid'); - $this->assertTraceContains('store'); - $this->assertTraceNotContains('miss'); - } - - public function testServesResponseWhileFreshAndRevalidatesWithLastModifiedInformation() - { - $time = \DateTime::createFromFormat('U', time()); - - $this->setNextResponse(200, [], 'Hello World', function (Request $request, Response $response) use ($time) { - $response->setSharedMaxAge(10); - $response->headers->set('Last-Modified', $time->format(\DATE_RFC2822)); - }); - - // prime the cache - $this->request('GET', '/'); - - // next request before s-maxage has expired: Serve from cache - // without hitting the backend - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('fresh'); - - sleep(15); // expire the cache - - $this->setNextResponse(304, [], '', function (Request $request, Response $response) use ($time) { - $this->assertEquals($time->format(\DATE_RFC2822), $request->headers->get('IF_MODIFIED_SINCE')); - }); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('valid'); - } - - public function testReplacesCachedResponsesWhenValidationResultsInNon304Response() - { - $time = \DateTime::createFromFormat('U', time()); - $count = 0; - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) use ($time, &$count) { - $response->headers->set('Last-Modified', $time->format(\DATE_RFC2822)); - $response->headers->set('Cache-Control', 'public'); - switch (++$count) { - case 1: - $response->setContent('first response'); - break; - case 2: - $response->setContent('second response'); - break; - case 3: - $response->setContent(''); - $response->setStatusCode(304); - break; - } - }); - - // first request should fetch from backend and store in cache - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('first response', $this->response->getContent()); - - // second request is validated, is invalid, and replaces cached entry - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('second response', $this->response->getContent()); - - // third response is validated, valid, and returns cached entry - $this->request('GET', '/'); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('second response', $this->response->getContent()); - - $this->assertEquals(3, $count); - } - - public function testPassesHeadRequestsThroughDirectlyOnPass() - { - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) { - $response->setContent(''); - $response->setStatusCode(200); - $this->assertEquals('HEAD', $request->getMethod()); - }); - - $this->request('HEAD', '/', ['HTTP_EXPECT' => 'something ...']); - $this->assertHttpKernelIsCalled(); - $this->assertEquals('', $this->response->getContent()); - } - - public function testUsesCacheToRespondToHeadRequestsWhenFresh() - { - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) { - $response->headers->set('Cache-Control', 'public, max-age=10'); - $response->setContent('Hello World'); - $response->setStatusCode(200); - $this->assertNotEquals('HEAD', $request->getMethod()); - }); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals('Hello World', $this->response->getContent()); - - $this->request('HEAD', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('', $this->response->getContent()); - $this->assertEquals(\strlen('Hello World'), $this->response->headers->get('Content-Length')); - } - - public function testSendsNoContentWhenFresh() - { - $time = \DateTime::createFromFormat('U', time()); - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) use ($time) { - $response->headers->set('Cache-Control', 'public, max-age=10'); - $response->headers->set('Last-Modified', $time->format(\DATE_RFC2822)); - }); - - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals('Hello World', $this->response->getContent()); - - $this->request('GET', '/', ['HTTP_IF_MODIFIED_SINCE' => $time->format(\DATE_RFC2822)]); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(304, $this->response->getStatusCode()); - $this->assertEquals('', $this->response->getContent()); - } - - public function testInvalidatesCachedResponsesOnPost() - { - $this->setNextResponse(200, [], 'Hello World', function ($request, $response) { - if ('GET' == $request->getMethod()) { - $response->setStatusCode(200); - $response->headers->set('Cache-Control', 'public, max-age=500'); - $response->setContent('Hello World'); - } elseif ('POST' == $request->getMethod()) { - $response->setStatusCode(303); - $response->headers->set('Location', '/'); - $response->headers->remove('Cache-Control'); - $response->setContent(''); - } - }); - - // build initial request to enter into the cache - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - // make sure it is valid - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('fresh'); - - // now POST to same URL - $this->request('POST', '/helloworld'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals('/', $this->response->headers->get('Location')); - $this->assertTraceContains('invalidate'); - $this->assertTraceContains('pass'); - $this->assertEquals('', $this->response->getContent()); - - // now make sure it was actually invalidated - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Hello World', $this->response->getContent()); - $this->assertTraceContains('stale'); - $this->assertTraceContains('invalid'); - $this->assertTraceContains('store'); - } - - public function testServesFromCacheWhenHeadersMatch() - { - $count = 0; - $this->setNextResponse(200, ['Cache-Control' => 'max-age=10000'], '', function ($request, $response) use (&$count) { - $response->headers->set('Vary', 'Accept User-Agent Foo'); - $response->headers->set('Cache-Control', 'public, max-age=10'); - $response->headers->set('X-Response-Count', ++$count); - $response->setContent($request->headers->get('USER_AGENT')); - }); - - $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Bob/1.0', $this->response->getContent()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - - $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Bob/1.0', $this->response->getContent()); - $this->assertTraceContains('fresh'); - $this->assertTraceNotContains('store'); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - } - - public function testStoresMultipleResponsesWhenHeadersDiffer() - { - $count = 0; - $this->setNextResponse(200, ['Cache-Control' => 'max-age=10000'], '', function ($request, $response) use (&$count) { - $response->headers->set('Vary', 'Accept User-Agent Foo'); - $response->headers->set('Cache-Control', 'public, max-age=10'); - $response->headers->set('X-Response-Count', ++$count); - $response->setContent($request->headers->get('USER_AGENT')); - }); - - $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('Bob/1.0', $this->response->getContent()); - $this->assertEquals(1, $this->response->headers->get('X-Response-Count')); - - $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/2.0']); - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertTraceContains('miss'); - $this->assertTraceContains('store'); - $this->assertEquals('Bob/2.0', $this->response->getContent()); - $this->assertEquals(2, $this->response->headers->get('X-Response-Count')); - - $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/1.0']); - $this->assertTraceContains('fresh'); - $this->assertEquals('Bob/1.0', $this->response->getContent()); - $this->assertEquals(1, $this->response->headers->get('X-Response-Count')); - - $this->request('GET', '/', ['HTTP_ACCEPT' => 'text/html', 'HTTP_USER_AGENT' => 'Bob/2.0']); - $this->assertTraceContains('fresh'); - $this->assertEquals('Bob/2.0', $this->response->getContent()); - $this->assertEquals(2, $this->response->headers->get('X-Response-Count')); - - $this->request('GET', '/', ['HTTP_USER_AGENT' => 'Bob/2.0']); - $this->assertTraceContains('miss'); - $this->assertEquals('Bob/2.0', $this->response->getContent()); - $this->assertEquals(3, $this->response->headers->get('X-Response-Count')); - } - - public function testShouldCatchExceptions() - { - $this->catchExceptions(); - - $this->setNextResponse(); - $this->request('GET', '/'); - - $this->assertExceptionsAreCaught(); - } - - public function testShouldCatchExceptionsWhenReloadingAndNoCacheRequest() - { - $this->catchExceptions(); - - $this->setNextResponse(); - $this->cacheConfig['allow_reload'] = true; - $this->request('GET', '/', [], [], false, ['Pragma' => 'no-cache']); - - $this->assertExceptionsAreCaught(); - } - - public function testShouldNotCatchExceptions() - { - $this->catchExceptions(false); - - $this->setNextResponse(); - $this->request('GET', '/'); - - $this->assertExceptionsAreNotCaught(); - } - - public function testEsiCacheSendsTheLowestTtl() - { - $responses = [ - [ - 'status' => 200, - 'body' => ' ', - 'headers' => [ - 'Cache-Control' => 's-maxage=300', - 'Surrogate-Control' => 'content="ESI/1.0"', - ], - ], - [ - 'status' => 200, - 'body' => 'Hello World!', - 'headers' => ['Cache-Control' => 's-maxage=200'], - ], - [ - 'status' => 200, - 'body' => 'My name is Bobby.', - 'headers' => ['Cache-Control' => 's-maxage=100'], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('GET', '/', [], [], true); - $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent()); - - $this->assertEquals(100, $this->response->getTtl()); - } - - public function testEsiCacheSendsTheLowestTtlForHeadRequests() - { - $responses = [ - [ - 'status' => 200, - 'body' => 'I am a long-lived master response, but I embed a short-lived resource: ', - 'headers' => [ - 'Cache-Control' => 's-maxage=300', - 'Surrogate-Control' => 'content="ESI/1.0"', - ], - ], - [ - 'status' => 200, - 'body' => 'I am a short-lived resource', - 'headers' => ['Cache-Control' => 's-maxage=100'], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('HEAD', '/', [], [], true); - - $this->assertEmpty($this->response->getContent()); - $this->assertEquals(100, $this->response->getTtl()); - } - - public function testEsiCacheForceValidation() - { - $responses = [ - [ - 'status' => 200, - 'body' => ' ', - 'headers' => [ - 'Cache-Control' => 's-maxage=300', - 'Surrogate-Control' => 'content="ESI/1.0"', - ], - ], - [ - 'status' => 200, - 'body' => 'Hello World!', - 'headers' => ['ETag' => 'foobar'], - ], - [ - 'status' => 200, - 'body' => 'My name is Bobby.', - 'headers' => ['Cache-Control' => 's-maxage=100'], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('GET', '/', [], [], true); - $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent()); - $this->assertNull($this->response->getTtl()); - $this->assertTrue($this->response->headers->hasCacheControlDirective('private')); - $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache')); - } - - public function testEsiCacheForceValidationForHeadRequests() - { - $responses = [ - [ - 'status' => 200, - 'body' => 'I am the master response and use expiration caching, but I embed another resource: ', - 'headers' => [ - 'Cache-Control' => 's-maxage=300', - 'Surrogate-Control' => 'content="ESI/1.0"', - ], - ], - [ - 'status' => 200, - 'body' => 'I am the embedded resource and use validation caching', - 'headers' => ['ETag' => 'foobar'], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('HEAD', '/', [], [], true); - - // The response has been assembled from expiration and validation based resources - // This can neither be cached nor revalidated, so it should be private/no cache - $this->assertEmpty($this->response->getContent()); - $this->assertNull($this->response->getTtl()); - $this->assertTrue($this->response->headers->hasCacheControlDirective('private')); - $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache')); - } - - public function testEsiRecalculateContentLengthHeader() - { - $responses = [ - [ - 'status' => 200, - 'body' => '', - 'headers' => [ - 'Content-Length' => 26, - 'Surrogate-Control' => 'content="ESI/1.0"', - ], - ], - [ - 'status' => 200, - 'body' => 'Hello World!', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('GET', '/', [], [], true); - $this->assertEquals('Hello World!', $this->response->getContent()); - $this->assertEquals(12, $this->response->headers->get('Content-Length')); - } - - public function testEsiRecalculateContentLengthHeaderForHeadRequest() - { - $responses = [ - [ - 'status' => 200, - 'body' => '', - 'headers' => [ - 'Content-Length' => 26, - 'Surrogate-Control' => 'content="ESI/1.0"', - ], - ], - [ - 'status' => 200, - 'body' => 'Hello World!', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('HEAD', '/', [], [], true); - - // https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.13 - // "The Content-Length entity-header field indicates the size of the entity-body, - // in decimal number of OCTETs, sent to the recipient or, in the case of the HEAD - // method, the size of the entity-body that would have been sent had the request - // been a GET." - $this->assertEmpty($this->response->getContent()); - $this->assertEquals(12, $this->response->headers->get('Content-Length')); - } - - public function testClientIpIsAlwaysLocalhostForForwardedRequests() - { - $this->setNextResponse(); - $this->request('GET', '/', ['REMOTE_ADDR' => '10.0.0.1']); - - $this->kernel->assert(function ($backendRequest) { - $this->assertSame('127.0.0.1', $backendRequest->server->get('REMOTE_ADDR')); - }); - } - - /** - * @dataProvider getTrustedProxyData - */ - public function testHttpCacheIsSetAsATrustedProxy(array $existing) - { - Request::setTrustedProxies($existing, Request::HEADER_X_FORWARDED_ALL); - - $this->setNextResponse(); - $this->request('GET', '/', ['REMOTE_ADDR' => '10.0.0.1']); - $this->assertSame($existing, Request::getTrustedProxies()); - - $existing = array_unique(array_merge($existing, ['127.0.0.1'])); - $this->kernel->assert(function ($backendRequest) use ($existing) { - $this->assertSame($existing, Request::getTrustedProxies()); - $this->assertsame('10.0.0.1', $backendRequest->getClientIp()); - }); - - Request::setTrustedProxies([], -1); - } - - public function getTrustedProxyData() - { - return [ - [[]], - [['10.0.0.2']], - [['10.0.0.2', '127.0.0.1']], - ]; - } - - /** - * @dataProvider getForwardedData - */ - public function testForwarderHeaderForForwardedRequests($forwarded, $expected) - { - $this->setNextResponse(); - $server = ['REMOTE_ADDR' => '10.0.0.1']; - if (null !== $forwarded) { - Request::setTrustedProxies($server, -1); - $server['HTTP_FORWARDED'] = $forwarded; - } - $this->request('GET', '/', $server); - - $this->kernel->assert(function ($backendRequest) use ($expected) { - $this->assertSame($expected, $backendRequest->headers->get('Forwarded')); - }); - - Request::setTrustedProxies([], -1); - } - - public function getForwardedData() - { - return [ - [null, 'for="10.0.0.1";host="localhost";proto=http'], - ['for=10.0.0.2', 'for="10.0.0.2";host="localhost";proto=http, for="10.0.0.1"'], - ['for=10.0.0.2, for=10.0.0.3', 'for="10.0.0.2";host="localhost";proto=http, for="10.0.0.3", for="10.0.0.1"'], - ]; - } - - public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponses() - { - $time = \DateTime::createFromFormat('U', time()); - - $responses = [ - [ - 'status' => 200, - 'body' => '', - 'headers' => [ - 'Surrogate-Control' => 'content="ESI/1.0"', - 'ETag' => 'hey', - 'Last-Modified' => $time->format(\DATE_RFC2822), - ], - ], - [ - 'status' => 200, - 'body' => 'Hey!', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('GET', '/', [], [], true); - $this->assertNull($this->response->getETag()); - $this->assertNull($this->response->getLastModified()); - } - - public function testEsiCacheRemoveValidationHeadersIfEmbeddedResponsesAndHeadRequest() - { - $time = \DateTime::createFromFormat('U', time()); - - $responses = [ - [ - 'status' => 200, - 'body' => '', - 'headers' => [ - 'Surrogate-Control' => 'content="ESI/1.0"', - 'ETag' => 'hey', - 'Last-Modified' => $time->format(\DATE_RFC2822), - ], - ], - [ - 'status' => 200, - 'body' => 'Hey!', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - - $this->request('HEAD', '/', [], [], true); - $this->assertEmpty($this->response->getContent()); - $this->assertNull($this->response->getETag()); - $this->assertNull($this->response->getLastModified()); - } - - public function testDoesNotCacheOptionsRequest() - { - $this->setNextResponse(200, ['Cache-Control' => 'public, s-maxage=60'], 'get'); - $this->request('GET', '/'); - $this->assertHttpKernelIsCalled(); - - $this->setNextResponse(200, ['Cache-Control' => 'public, s-maxage=60'], 'options'); - $this->request('OPTIONS', '/'); - $this->assertHttpKernelIsCalled(); - - $this->request('GET', '/'); - $this->assertHttpKernelIsNotCalled(); - $this->assertSame('get', $this->response->getContent()); - } - - public function testUsesOriginalRequestForSurrogate() - { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); - $store = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpCache\StoreInterface')->getMock(); - - $kernel - ->expects($this->exactly(2)) - ->method('handle') - ->willReturnCallback(function (Request $request) { - $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); - - return new Response(); - }); - - $cache = new HttpCache($kernel, - $store, - new Esi() - ); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '10.0.0.1'); - - // Main request - $cache->handle($request, HttpKernelInterface::MASTER_REQUEST); - - // Main request was now modified by HttpCache - // The surrogate will ask for the request using $this->cache->getRequest() - // which MUST return the original request so the surrogate - // can actually behave like a reverse proxy like e.g. Varnish would. - $this->assertSame('10.0.0.1', $cache->getRequest()->getClientIp()); - $this->assertSame('10.0.0.1', $cache->getRequest()->server->get('REMOTE_ADDR')); - - // Surrogate request - $cache->handle($request, HttpKernelInterface::SUB_REQUEST); - } - - public function testStaleIfErrorMustNotResetLifetime() - { - // Make sure we don't accidentally treat the response as fresh (revalidated) again - // when stale-if-error handling kicks in. - - $responses = [ - [ - 'status' => 200, - 'body' => 'OK', - // This is cacheable and can be used in stale-if-error cases: - 'headers' => ['Cache-Control' => 'public, max-age=10', 'ETag' => 'some-etag'], - ], - [ - 'status' => 500, - 'body' => 'FAIL', - 'headers' => [], - ], - [ - 'status' => 500, - 'body' => 'FAIL', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - $this->cacheConfig['stale_if_error'] = 10; - - $this->request('GET', '/'); // warm cache - - sleep(15); // now the entry is stale, but still within the grace period (10s max-age + 10s stale-if-error) - - $this->request('GET', '/'); // hit backend error - $this->assertEquals(200, $this->response->getStatusCode()); // stale-if-error saved the day - $this->assertEquals(15, $this->response->getAge()); - - sleep(10); // now we're outside the grace period - - $this->request('GET', '/'); // hit backend error - $this->assertEquals(500, $this->response->getStatusCode()); // fail - } - - /** - * @dataProvider getResponseDataThatMayBeServedStaleIfError - */ - public function testResponsesThatMayBeUsedStaleIfError($responseHeaders, $sleepBetweenRequests = null) - { - $responses = [ - [ - 'status' => 200, - 'body' => 'OK', - 'headers' => $responseHeaders, - ], - [ - 'status' => 500, - 'body' => 'FAIL', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - $this->cacheConfig['stale_if_error'] = 10; // after stale, may be served for 10s - - $this->request('GET', '/'); // warm cache - - if ($sleepBetweenRequests) { - sleep($sleepBetweenRequests); - } - - $this->request('GET', '/'); // hit backend error - - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('OK', $this->response->getContent()); - $this->assertTraceContains('stale-if-error'); - } - - public function getResponseDataThatMayBeServedStaleIfError() - { - // All data sets assume that a 10s stale-if-error grace period has been configured - yield 'public, max-age expired' => [['Cache-Control' => 'public, max-age=60'], 65]; - yield 'public, validateable with ETag, no TTL' => [['Cache-Control' => 'public', 'ETag' => 'some-etag'], 5]; - yield 'public, validateable with Last-Modified, no TTL' => [['Cache-Control' => 'public', 'Last-Modified' => 'yesterday'], 5]; - yield 'public, s-maxage will be served stale-if-error, even if the RFC mandates otherwise' => [['Cache-Control' => 'public, s-maxage=20'], 25]; - } - - /** - * @dataProvider getResponseDataThatMustNotBeServedStaleIfError - */ - public function testResponsesThatMustNotBeUsedStaleIfError($responseHeaders, $sleepBetweenRequests = null) - { - $responses = [ - [ - 'status' => 200, - 'body' => 'OK', - 'headers' => $responseHeaders, - ], - [ - 'status' => 500, - 'body' => 'FAIL', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - $this->cacheConfig['stale_if_error'] = 10; // after stale, may be served for 10s - $this->cacheConfig['strict_smaxage'] = true; // full RFC compliance for this feature - - $this->request('GET', '/'); // warm cache - - if ($sleepBetweenRequests) { - sleep($sleepBetweenRequests); - } - - $this->request('GET', '/'); // hit backend error - - $this->assertEquals(500, $this->response->getStatusCode()); - } - - public function getResponseDataThatMustNotBeServedStaleIfError() - { - // All data sets assume that a 10s stale-if-error grace period has been configured - yield 'public, no TTL but beyond grace period' => [['Cache-Control' => 'public'], 15]; - yield 'public, validateable with ETag, no TTL but beyond grace period' => [['Cache-Control' => 'public', 'ETag' => 'some-etag'], 15]; - yield 'public, validateable with Last-Modified, no TTL but beyond grace period' => [['Cache-Control' => 'public', 'Last-Modified' => 'yesterday'], 15]; - yield 'public, stale beyond grace period' => [['Cache-Control' => 'public, max-age=10'], 30]; - - // Cache-control values that prohibit serving stale responses or responses without positive validation - - // see https://tools.ietf.org/html/rfc7234#section-4.2.4 and - // https://tools.ietf.org/html/rfc7234#section-5.2.2 - yield 'no-cache requires positive validation' => [['Cache-Control' => 'public, no-cache', 'ETag' => 'some-etag']]; - yield 'no-cache requires positive validation, even if fresh' => [['Cache-Control' => 'public, no-cache, max-age=10']]; - yield 'must-revalidate requires positive validation once stale' => [['Cache-Control' => 'public, max-age=10, must-revalidate'], 15]; - yield 'proxy-revalidate requires positive validation once stale' => [['Cache-Control' => 'public, max-age=10, proxy-revalidate'], 15]; - } - - public function testStaleIfErrorWhenStrictSmaxageDisabled() - { - $responses = [ - [ - 'status' => 200, - 'body' => 'OK', - 'headers' => ['Cache-Control' => 'public, s-maxage=20'], - ], - [ - 'status' => 500, - 'body' => 'FAIL', - 'headers' => [], - ], - ]; - - $this->setNextResponses($responses); - $this->cacheConfig['stale_if_error'] = 10; - $this->cacheConfig['strict_smaxage'] = false; - - $this->request('GET', '/'); // warm cache - sleep(25); - $this->request('GET', '/'); // hit backend error - - $this->assertEquals(200, $this->response->getStatusCode()); - $this->assertEquals('OK', $this->response->getContent()); - $this->assertTraceContains('stale-if-error'); - } -} - -class TestKernel implements HttpKernelInterface -{ - public $terminateCalled = false; - - public function terminate(Request $request, Response $response) - { - $this->terminateCalled = true; - } - - public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) - { - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php deleted file mode 100644 index 3cbea5e4..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php +++ /dev/null @@ -1,185 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\HttpCache\Esi; -use Symfony\Component\HttpKernel\HttpCache\HttpCache; -use Symfony\Component\HttpKernel\HttpCache\Store; -use Symfony\Component\HttpKernel\HttpKernelInterface; - -class HttpCacheTestCase extends TestCase -{ - protected $kernel; - protected $cache; - protected $caches; - protected $cacheConfig; - protected $request; - protected $response; - protected $responses; - protected $catch; - protected $esi; - - /** - * @var Store - */ - protected $store; - - protected function setUp() - { - $this->kernel = null; - - $this->cache = null; - $this->esi = null; - $this->caches = []; - $this->cacheConfig = []; - - $this->request = null; - $this->response = null; - $this->responses = []; - - $this->catch = false; - - $this->clearDirectory(sys_get_temp_dir().'/http_cache'); - } - - protected function tearDown() - { - if ($this->cache) { - $this->cache->getStore()->cleanup(); - } - $this->kernel = null; - $this->cache = null; - $this->caches = null; - $this->request = null; - $this->response = null; - $this->responses = null; - $this->cacheConfig = null; - $this->catch = null; - $this->esi = null; - - $this->clearDirectory(sys_get_temp_dir().'/http_cache'); - } - - public function assertHttpKernelIsCalled() - { - $this->assertTrue($this->kernel->hasBeenCalled()); - } - - public function assertHttpKernelIsNotCalled() - { - $this->assertFalse($this->kernel->hasBeenCalled()); - } - - public function assertResponseOk() - { - $this->assertEquals(200, $this->response->getStatusCode()); - } - - public function assertTraceContains($trace) - { - $traces = $this->cache->getTraces(); - $traces = current($traces); - - $this->assertMatchesRegularExpression('/'.$trace.'/', implode(', ', $traces)); - } - - public function assertTraceNotContains($trace) - { - $traces = $this->cache->getTraces(); - $traces = current($traces); - - $this->assertDoesNotMatchRegularExpression('/'.$trace.'/', implode(', ', $traces)); - } - - public function assertExceptionsAreCaught() - { - $this->assertTrue($this->kernel->isCatchingExceptions()); - } - - public function assertExceptionsAreNotCaught() - { - $this->assertFalse($this->kernel->isCatchingExceptions()); - } - - public function request($method, $uri = '/', $server = [], $cookies = [], $esi = false, $headers = []) - { - if (null === $this->kernel) { - throw new \LogicException('You must call setNextResponse() before calling request().'); - } - - $this->kernel->reset(); - - $this->store = new Store(sys_get_temp_dir().'/http_cache'); - - $this->cacheConfig['debug'] = true; - - $this->esi = $esi ? new Esi() : null; - $this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig); - $this->request = Request::create($uri, $method, [], $cookies, [], $server); - $this->request->headers->add($headers); - - $this->response = $this->cache->handle($this->request, HttpKernelInterface::MASTER_REQUEST, $this->catch); - - $this->responses[] = $this->response; - } - - public function getMetaStorageValues() - { - $values = []; - foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(sys_get_temp_dir().'/http_cache/md', \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) { - $values[] = file_get_contents($file); - } - - return $values; - } - - // A basic response with 200 status code and a tiny body. - public function setNextResponse($statusCode = 200, array $headers = [], $body = 'Hello World', \Closure $customizer = null) - { - $this->kernel = new TestHttpKernel($body, $statusCode, $headers, $customizer); - } - - public function setNextResponses($responses) - { - $this->kernel = new TestMultipleHttpKernel($responses); - } - - public function catchExceptions($catch = true) - { - $this->catch = $catch; - } - - public static function clearDirectory($directory) - { - if (!is_dir($directory)) { - return; - } - - $fp = opendir($directory); - while (false !== $file = readdir($fp)) { - if (!\in_array($file, ['.', '..'])) { - if (is_link($directory.'/'.$file)) { - unlink($directory.'/'.$file); - } elseif (is_dir($directory.'/'.$file)) { - self::clearDirectory($directory.'/'.$file); - rmdir($directory.'/'.$file); - } else { - unlink($directory.'/'.$file); - } - } - } - - closedir($fp); - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php deleted file mode 100644 index fd67af36..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ /dev/null @@ -1,469 +0,0 @@ - - * - * This code is partially based on the Rack-Cache library by Ryan Tomayko, - * which is released under the MIT license. - * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategy; - -class ResponseCacheStrategyTest extends TestCase -{ - public function testMinimumSharedMaxAgeWins() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $response1 = new Response(); - $response1->setSharedMaxAge(60); - $cacheStrategy->add($response1); - - $response2 = new Response(); - $response2->setSharedMaxAge(3600); - $cacheStrategy->add($response2); - - $response = new Response(); - $response->setSharedMaxAge(86400); - $cacheStrategy->update($response); - - $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage')); - } - - public function testSharedMaxAgeNotSetIfNotSetInAnyEmbeddedRequest() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $response1 = new Response(); - $response1->setSharedMaxAge(60); - $cacheStrategy->add($response1); - - $response2 = new Response(); - $cacheStrategy->add($response2); - - $response = new Response(); - $response->setSharedMaxAge(86400); - $cacheStrategy->update($response); - - $this->assertFalse($response->headers->hasCacheControlDirective('s-maxage')); - } - - public function testSharedMaxAgeNotSetIfNotSetInMasterRequest() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $response1 = new Response(); - $response1->setSharedMaxAge(60); - $cacheStrategy->add($response1); - - $response2 = new Response(); - $response2->setSharedMaxAge(3600); - $cacheStrategy->add($response2); - - $response = new Response(); - $cacheStrategy->update($response); - - $this->assertFalse($response->headers->hasCacheControlDirective('s-maxage')); - } - - public function testMasterResponseNotCacheableWhenEmbeddedResponseRequiresValidation() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $embeddedResponse = new Response(); - $embeddedResponse->setLastModified(new \DateTime()); - $cacheStrategy->add($embeddedResponse); - - $masterResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); - $cacheStrategy->update($masterResponse); - - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache')); - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate')); - $this->assertFalse($masterResponse->isFresh()); - } - - public function testValidationOnMasterResponseIsNotPossibleWhenItContainsEmbeddedResponses() - { - $cacheStrategy = new ResponseCacheStrategy(); - - // This master response uses the "validation" model - $masterResponse = new Response(); - $masterResponse->setLastModified(new \DateTime()); - $masterResponse->setEtag('foo'); - - // Embedded response uses "expiry" model - $embeddedResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); - $cacheStrategy->add($embeddedResponse); - - $cacheStrategy->update($masterResponse); - - $this->assertFalse($masterResponse->isValidateable()); - $this->assertFalse($masterResponse->headers->has('Last-Modified')); - $this->assertFalse($masterResponse->headers->has('ETag')); - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache')); - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate')); - } - - public function testMasterResponseWithValidationIsUnchangedWhenThereIsNoEmbeddedResponse() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setLastModified(new \DateTime()); - $cacheStrategy->update($masterResponse); - - $this->assertTrue($masterResponse->isValidateable()); - } - - public function testMasterResponseWithExpirationIsUnchangedWhenThereIsNoEmbeddedResponse() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); - $cacheStrategy->update($masterResponse); - - $this->assertTrue($masterResponse->isFresh()); - } - - public function testMasterResponseIsNotCacheableWhenEmbeddedResponseIsNotCacheable() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); // Public, cacheable - - /* This response has no validation or expiration information. - That makes it uncacheable, it is always stale. - (It does *not* make this private, though.) */ - $embeddedResponse = new Response(); - $this->assertFalse($embeddedResponse->isFresh()); // not fresh, as no lifetime is provided - - $cacheStrategy->add($embeddedResponse); - $cacheStrategy->update($masterResponse); - - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache')); - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate')); - $this->assertFalse($masterResponse->isFresh()); - } - - public function testEmbeddingPrivateResponseMakesMainResponsePrivate() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); // public, cacheable - - // The embedded response might for example contain per-user data that remains valid for 60 seconds - $embeddedResponse = new Response(); - $embeddedResponse->setPrivate(); - $embeddedResponse->setMaxAge(60); // this would implicitly set "private" as well, but let's be explicit - - $cacheStrategy->add($embeddedResponse); - $cacheStrategy->update($masterResponse); - - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('private')); - $this->assertFalse($masterResponse->headers->hasCacheControlDirective('public')); - } - - public function testEmbeddingPublicResponseDoesNotMakeMainResponsePublic() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setPrivate(); // this is the default, but let's be explicit - $masterResponse->setMaxAge(100); - - $embeddedResponse = new Response(); - $embeddedResponse->setPublic(); - $embeddedResponse->setSharedMaxAge(100); - - $cacheStrategy->add($embeddedResponse); - $cacheStrategy->update($masterResponse); - - $this->assertTrue($masterResponse->headers->hasCacheControlDirective('private')); - $this->assertFalse($masterResponse->headers->hasCacheControlDirective('public')); - } - - public function testResponseIsExiprableWhenEmbeddedResponseCombinesExpiryAndValidation() - { - /* When "expiration wins over validation" (https://symfony.com/doc/current/http_cache/validation.html) - * and both the main and embedded response provide s-maxage, then the more restricting value of both - * should be fine, regardless of whether the embedded response can be validated later on or must be - * completely regenerated. - */ - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); - - $embeddedResponse = new Response(); - $embeddedResponse->setSharedMaxAge(60); - $embeddedResponse->setEtag('foo'); - - $cacheStrategy->add($embeddedResponse); - $cacheStrategy->update($masterResponse); - - $this->assertEqualsWithDelta(60, (int) $masterResponse->headers->getCacheControlDirective('s-maxage'), 1); - } - - public function testResponseIsExpirableButNotValidateableWhenMasterResponseCombinesExpirationAndValidation() - { - $cacheStrategy = new ResponseCacheStrategy(); - - $masterResponse = new Response(); - $masterResponse->setSharedMaxAge(3600); - $masterResponse->setEtag('foo'); - $masterResponse->setLastModified(new \DateTime()); - - $embeddedResponse = new Response(); - $embeddedResponse->setSharedMaxAge(60); - - $cacheStrategy->add($embeddedResponse); - $cacheStrategy->update($masterResponse); - - $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage')); - $this->assertFalse($masterResponse->isValidateable()); - } - - /** - * @dataProvider cacheControlMergingProvider - */ - public function testCacheControlMerging(array $expects, array $master, array $surrogates) - { - $cacheStrategy = new ResponseCacheStrategy(); - $buildResponse = function ($config) { - $response = new Response(); - - foreach ($config as $key => $value) { - switch ($key) { - case 'age': - $response->headers->set('Age', $value); - break; - - case 'expires': - $expires = clone $response->getDate(); - $expires->modify('+'.$value.' seconds'); - $response->setExpires($expires); - break; - - case 'max-age': - $response->setMaxAge($value); - break; - - case 's-maxage': - $response->setSharedMaxAge($value); - break; - - case 'private': - $response->setPrivate(); - break; - - case 'public': - $response->setPublic(); - break; - - default: - $response->headers->addCacheControlDirective($key, $value); - } - } - - return $response; - }; - - foreach ($surrogates as $config) { - $cacheStrategy->add($buildResponse($config)); - } - - $response = $buildResponse($master); - $cacheStrategy->update($response); - - foreach ($expects as $key => $value) { - if ('expires' === $key) { - $this->assertSame($value, $response->getExpires()->format('U') - $response->getDate()->format('U')); - } elseif ('age' === $key) { - $this->assertSame($value, $response->getAge()); - } elseif (true === $value) { - $this->assertTrue($response->headers->hasCacheControlDirective($key), sprintf('Cache-Control header must have "%s" flag', $key)); - } elseif (false === $value) { - $this->assertFalse( - $response->headers->hasCacheControlDirective($key), - sprintf('Cache-Control header must NOT have "%s" flag', $key) - ); - } else { - $this->assertSame($value, $response->headers->getCacheControlDirective($key), sprintf('Cache-Control flag "%s" should be "%s"', $key, $value)); - } - } - } - - public function cacheControlMergingProvider() - { - yield 'result is public if all responses are public' => [ - ['private' => false, 'public' => true], - ['public' => true], - [ - ['public' => true], - ], - ]; - - yield 'result is private by default' => [ - ['private' => true, 'public' => false], - ['public' => true], - [ - [], - ], - ]; - - yield 'combines public and private responses' => [ - ['must-revalidate' => false, 'private' => true, 'public' => false], - ['public' => true], - [ - ['private' => true], - ], - ]; - - yield 'inherits no-cache from surrogates' => [ - ['no-cache' => true, 'public' => false], - ['public' => true], - [ - ['no-cache' => true], - ], - ]; - - yield 'inherits no-store from surrogate' => [ - ['no-store' => true, 'public' => false], - ['public' => true], - [ - ['no-store' => true], - ], - ]; - - yield 'resolve to lowest possible max-age' => [ - ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'], - ['public' => true, 'max-age' => 3600], - [ - ['private' => true, 'max-age' => 60], - ], - ]; - - yield 'resolves multiple max-age' => [ - ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'], - ['private' => true, 'max-age' => 100], - [ - ['private' => true, 'max-age' => 3600], - ['public' => true, 'max-age' => 60, 's-maxage' => 60], - ['private' => true, 'max-age' => 60], - ], - ]; - - yield 'merge max-age and s-maxage' => [ - ['public' => true, 's-maxage' => '60', 'max-age' => null], - ['public' => true, 's-maxage' => 3600], - [ - ['public' => true, 'max-age' => 60], - ], - ]; - - yield 'result is private when combining private responses' => [ - ['no-cache' => false, 'must-revalidate' => false, 'private' => true], - ['s-maxage' => 60, 'private' => true], - [ - ['s-maxage' => 60, 'private' => true], - ], - ]; - - yield 'result can have s-maxage and max-age' => [ - ['public' => true, 'private' => false, 's-maxage' => '60', 'max-age' => '30'], - ['s-maxage' => 100, 'max-age' => 2000], - [ - ['s-maxage' => 1000, 'max-age' => 30], - ['s-maxage' => 500, 'max-age' => 500], - ['s-maxage' => 60, 'max-age' => 1000], - ], - ]; - - yield 'does not set headers without value' => [ - ['max-age' => null, 's-maxage' => null, 'public' => null], - ['private' => true], - [ - ['private' => true], - ], - ]; - - yield 'max-age 0 is sent to the client' => [ - ['private' => true, 'max-age' => '0'], - ['max-age' => 0, 'private' => true], - [ - ['max-age' => 60, 'private' => true], - ], - ]; - - yield 'max-age is relative to age' => [ - ['max-age' => '240', 'age' => 60], - ['max-age' => 180], - [ - ['max-age' => 600, 'age' => 60], - ], - ]; - - yield 'retains lowest age of all responses' => [ - ['max-age' => '160', 'age' => 60], - ['max-age' => 600, 'age' => 60], - [ - ['max-age' => 120, 'age' => 20], - ], - ]; - - yield 'max-age can be less than age, essentially expiring the response' => [ - ['age' => 120, 'max-age' => '90'], - ['max-age' => 90, 'age' => 120], - [ - ['max-age' => 120, 'age' => 60], - ], - ]; - - yield 'max-age is 0 regardless of age' => [ - ['max-age' => '0'], - ['max-age' => 60], - [ - ['max-age' => 0, 'age' => 60], - ], - ]; - - yield 'max-age is not negative' => [ - ['max-age' => '0'], - ['max-age' => 0], - [ - ['max-age' => 0, 'age' => 60], - ], - ]; - - yield 'calculates lowest Expires header' => [ - ['expires' => 60], - ['expires' => 60], - [ - ['expires' => 120], - ], - ]; - - yield 'calculates Expires header relative to age' => [ - ['expires' => 210, 'age' => 120], - ['expires' => 90], - [ - ['expires' => 600, 'age' => '120'], - ], - ]; - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php deleted file mode 100644 index f5000554..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php +++ /dev/null @@ -1,211 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpCache\Ssi; - -class SsiTest extends TestCase -{ - public function testHasSurrogateSsiCapability() - { - $ssi = new Ssi(); - - $request = Request::create('/'); - $request->headers->set('Surrogate-Capability', 'abc="SSI/1.0"'); - $this->assertTrue($ssi->hasSurrogateCapability($request)); - - $request = Request::create('/'); - $request->headers->set('Surrogate-Capability', 'foobar'); - $this->assertFalse($ssi->hasSurrogateCapability($request)); - - $request = Request::create('/'); - $this->assertFalse($ssi->hasSurrogateCapability($request)); - } - - public function testAddSurrogateSsiCapability() - { - $ssi = new Ssi(); - - $request = Request::create('/'); - $ssi->addSurrogateCapability($request); - $this->assertEquals('symfony="SSI/1.0"', $request->headers->get('Surrogate-Capability')); - - $ssi->addSurrogateCapability($request); - $this->assertEquals('symfony="SSI/1.0", symfony="SSI/1.0"', $request->headers->get('Surrogate-Capability')); - } - - public function testAddSurrogateControl() - { - $ssi = new Ssi(); - - $response = new Response('foo '); - $ssi->addSurrogateControl($response); - $this->assertEquals('content="SSI/1.0"', $response->headers->get('Surrogate-Control')); - - $response = new Response('foo'); - $ssi->addSurrogateControl($response); - $this->assertEquals('', $response->headers->get('Surrogate-Control')); - } - - public function testNeedsSsiParsing() - { - $ssi = new Ssi(); - - $response = new Response(); - $response->headers->set('Surrogate-Control', 'content="SSI/1.0"'); - $this->assertTrue($ssi->needsParsing($response)); - - $response = new Response(); - $this->assertFalse($ssi->needsParsing($response)); - } - - public function testRenderIncludeTag() - { - $ssi = new Ssi(); - - $this->assertEquals('', $ssi->renderIncludeTag('/', '/alt', true)); - $this->assertEquals('', $ssi->renderIncludeTag('/', '/alt', false)); - $this->assertEquals('', $ssi->renderIncludeTag('/')); - } - - public function testProcessDoesNothingIfContentTypeIsNotHtml() - { - $ssi = new Ssi(); - - $request = Request::create('/'); - $response = new Response(); - $response->headers->set('Content-Type', 'text/plain'); - $ssi->process($request, $response); - - $this->assertFalse($response->headers->has('x-body-eval')); - } - - public function testProcess() - { - $ssi = new Ssi(); - - $request = Request::create('/'); - $response = new Response('foo '); - $ssi->process($request, $response); - - $this->assertEquals('foo surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent()); - $this->assertEquals('SSI', $response->headers->get('x-body-eval')); - - $response = new Response('foo '); - $ssi->process($request, $response); - - $this->assertEquals("foo surrogate->handle(\$this, 'foo\\'', '', false) ?>"."\n", $response->getContent()); - } - - public function testProcessEscapesPhpTags() - { - $ssi = new Ssi(); - - $request = Request::create('/'); - $response = new Response(''); - $ssi->process($request, $response); - - $this->assertEquals('php cript language=php>', $response->getContent()); - } - - public function testProcessWhenNoSrcInAnSsi() - { - $this->expectException('RuntimeException'); - $ssi = new Ssi(); - - $request = Request::create('/'); - $response = new Response('foo '); - $ssi->process($request, $response); - } - - public function testProcessRemoveSurrogateControlHeader() - { - $ssi = new Ssi(); - - $request = Request::create('/'); - $response = new Response('foo '); - $response->headers->set('Surrogate-Control', 'content="SSI/1.0"'); - $ssi->process($request, $response); - $this->assertEquals('SSI', $response->headers->get('x-body-eval')); - - $response->headers->set('Surrogate-Control', 'no-store, content="SSI/1.0"'); - $ssi->process($request, $response); - $this->assertEquals('SSI', $response->headers->get('x-body-eval')); - $this->assertEquals('no-store', $response->headers->get('surrogate-control')); - - $response->headers->set('Surrogate-Control', 'content="SSI/1.0", no-store'); - $ssi->process($request, $response); - $this->assertEquals('SSI', $response->headers->get('x-body-eval')); - $this->assertEquals('no-store', $response->headers->get('surrogate-control')); - } - - public function testHandle() - { - $ssi = new Ssi(); - $cache = $this->getCache(Request::create('/'), new Response('foo')); - $this->assertEquals('foo', $ssi->handle($cache, '/', '/alt', true)); - } - - public function testHandleWhenResponseIsNot200() - { - $this->expectException('RuntimeException'); - $ssi = new Ssi(); - $response = new Response('foo'); - $response->setStatusCode(404); - $cache = $this->getCache(Request::create('/'), $response); - $ssi->handle($cache, '/', '/alt', false); - } - - public function testHandleWhenResponseIsNot200AndErrorsAreIgnored() - { - $ssi = new Ssi(); - $response = new Response('foo'); - $response->setStatusCode(404); - $cache = $this->getCache(Request::create('/'), $response); - $this->assertEquals('', $ssi->handle($cache, '/', '/alt', true)); - } - - public function testHandleWhenResponseIsNot200AndAltIsPresent() - { - $ssi = new Ssi(); - $response1 = new Response('foo'); - $response1->setStatusCode(404); - $response2 = new Response('bar'); - $cache = $this->getCache(Request::create('/'), [$response1, $response2]); - $this->assertEquals('bar', $ssi->handle($cache, '/', '/alt', false)); - } - - protected function getCache($request, $response) - { - $cache = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpCache\HttpCache')->setMethods(['getRequest', 'handle'])->disableOriginalConstructor()->getMock(); - $cache->expects($this->any()) - ->method('getRequest') - ->willReturn($request) - ; - if (\is_array($response)) { - $cache->expects($this->any()) - ->method('handle') - ->will(\call_user_func_array([$this, 'onConsecutiveCalls'], $response)) - ; - } else { - $cache->expects($this->any()) - ->method('handle') - ->willReturn($response) - ; - } - - return $cache; - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php deleted file mode 100644 index eee8970b..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/StoreTest.php +++ /dev/null @@ -1,355 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpCache\Store; - -class StoreTest extends TestCase -{ - protected $request; - protected $response; - - /** - * @var Store - */ - protected $store; - - protected function setUp() - { - $this->request = Request::create('/'); - $this->response = new Response('hello world', 200, []); - - HttpCacheTestCase::clearDirectory(sys_get_temp_dir().'/http_cache'); - - $this->store = new Store(sys_get_temp_dir().'/http_cache'); - } - - protected function tearDown() - { - $this->store = null; - $this->request = null; - $this->response = null; - - HttpCacheTestCase::clearDirectory(sys_get_temp_dir().'/http_cache'); - } - - public function testReadsAnEmptyArrayWithReadWhenNothingCachedAtKey() - { - $this->assertEmpty($this->getStoreMetadata('/nothing')); - } - - public function testUnlockFileThatDoesExist() - { - $this->storeSimpleEntry(); - $this->store->lock($this->request); - - $this->assertTrue($this->store->unlock($this->request)); - } - - public function testUnlockFileThatDoesNotExist() - { - $this->assertFalse($this->store->unlock($this->request)); - } - - public function testRemovesEntriesForKeyWithPurge() - { - $request = Request::create('/foo'); - $this->store->write($request, new Response('foo')); - - $metadata = $this->getStoreMetadata($request); - $this->assertNotEmpty($metadata); - - $this->assertTrue($this->store->purge('/foo')); - $this->assertEmpty($this->getStoreMetadata($request)); - - // cached content should be kept after purging - $path = $this->store->getPath($metadata[0][1]['x-content-digest'][0]); - $this->assertTrue(is_file($path)); - - $this->assertFalse($this->store->purge('/bar')); - } - - public function testStoresACacheEntry() - { - $cacheKey = $this->storeSimpleEntry(); - - $this->assertNotEmpty($this->getStoreMetadata($cacheKey)); - } - - public function testSetsTheXContentDigestResponseHeaderBeforeStoring() - { - $cacheKey = $this->storeSimpleEntry(); - $entries = $this->getStoreMetadata($cacheKey); - list(, $res) = $entries[0]; - - $this->assertEquals('en9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', $res['x-content-digest'][0]); - } - - public function testDoesNotTrustXContentDigestFromUpstream() - { - $response = new Response('test', 200, ['X-Content-Digest' => 'untrusted-from-elsewhere']); - - $cacheKey = $this->store->write($this->request, $response); - $entries = $this->getStoreMetadata($cacheKey); - list(, $res) = $entries[0]; - - $this->assertEquals('en9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', $res['x-content-digest'][0]); - $this->assertEquals('en9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', $response->headers->get('X-Content-Digest')); - } - - public function testWritesResponseEvenIfXContentDigestIsPresent() - { - // Prime the store - $this->store->write($this->request, new Response('test', 200, ['X-Content-Digest' => 'untrusted-from-elsewhere'])); - - $response = $this->store->lookup($this->request); - $this->assertNotNull($response); - } - - public function testWritingARestoredResponseDoesNotCorruptCache() - { - /* - * This covers the regression reported in https://github.com/symfony/symfony/issues/37174. - * - * A restored response does *not* load the body, but only keep the file path in a special X-Body-File - * header. For reasons (?), the file path was also used as the restored response body. - * It would be up to others (HttpCache...?) to honor this header and actually load the response content - * from there. - * - * When a restored response was stored again, the Store itself would ignore the header. In the first - * step, this would compute a new Content Digest based on the file path in the restored response body; - * this is covered by "Checkpoint 1" below. But, since the X-Body-File header was left untouched (Checkpoint 2), downstream - * code (HttpCache...) would not immediately notice. - * - * Only upon performing the lookup for a second time, we'd get a Response where the (wrong) Content Digest - * is also reflected in the X-Body-File header, this time also producing wrong content when the downstream - * evaluates it. - */ - $this->store->write($this->request, $this->response); - $digest = $this->response->headers->get('X-Content-Digest'); - $path = $this->getStorePath($digest); - - $response = $this->store->lookup($this->request); - $this->store->write($this->request, $response); - $this->assertEquals($digest, $response->headers->get('X-Content-Digest')); // Checkpoint 1 - $this->assertEquals($path, $response->headers->get('X-Body-File')); // Checkpoint 2 - - $response = $this->store->lookup($this->request); - $this->assertEquals($digest, $response->headers->get('X-Content-Digest')); - $this->assertEquals($path, $response->headers->get('X-Body-File')); - } - - public function testFindsAStoredEntryWithLookup() - { - $this->storeSimpleEntry(); - $response = $this->store->lookup($this->request); - - $this->assertNotNull($response); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); - } - - public function testDoesNotFindAnEntryWithLookupWhenNoneExists() - { - $request = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - - $this->assertNull($this->store->lookup($request)); - } - - public function testCanonizesUrlsForCacheKeys() - { - $this->storeSimpleEntry($path = '/test?x=y&p=q'); - $hitsReq = Request::create($path); - $missReq = Request::create('/test?p=x'); - - $this->assertNotNull($this->store->lookup($hitsReq)); - $this->assertNull($this->store->lookup($missReq)); - } - - public function testDoesNotFindAnEntryWithLookupWhenTheBodyDoesNotExist() - { - $this->storeSimpleEntry(); - $this->assertNotNull($this->response->headers->get('X-Content-Digest')); - $path = $this->getStorePath($this->response->headers->get('X-Content-Digest')); - @unlink($path); - $this->assertNull($this->store->lookup($this->request)); - } - - public function testRestoresResponseHeadersProperlyWithLookup() - { - $this->storeSimpleEntry(); - $response = $this->store->lookup($this->request); - - $this->assertEquals($response->headers->all(), array_merge(['content-length' => 4, 'x-body-file' => [$this->getStorePath($response->headers->get('X-Content-Digest'))]], $this->response->headers->all())); - } - - public function testRestoresResponseContentFromEntityStoreWithLookup() - { - $this->storeSimpleEntry(); - $response = $this->store->lookup($this->request); - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test')), $response->getContent()); - } - - public function testInvalidatesMetaAndEntityStoreEntriesWithInvalidate() - { - $this->storeSimpleEntry(); - $this->store->invalidate($this->request); - $response = $this->store->lookup($this->request); - $this->assertInstanceOf('Symfony\Component\HttpFoundation\Response', $response); - $this->assertFalse($response->isFresh()); - } - - public function testSucceedsQuietlyWhenInvalidateCalledWithNoMatchingEntries() - { - $req = Request::create('/test'); - $this->store->invalidate($req); - $this->assertNull($this->store->lookup($this->request)); - } - - public function testDoesNotReturnEntriesThatVaryWithLookup() - { - $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']); - $res = new Response('test', 200, ['Vary' => 'Foo Bar']); - $this->store->write($req1, $res); - - $this->assertNull($this->store->lookup($req2)); - } - - public function testDoesNotReturnEntriesThatSlightlyVaryWithLookup() - { - $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bam']); - $res = new Response('test', 200, ['Vary' => ['Foo', 'Bar']]); - $this->store->write($req1, $res); - - $this->assertNull($this->store->lookup($req2)); - } - - public function testStoresMultipleResponsesForEachVaryCombination() - { - $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - $res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']); - $key = $this->store->write($req1, $res1); - - $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']); - $res2 = new Response('test 2', 200, ['Vary' => 'Foo Bar']); - $this->store->write($req2, $res2); - - $req3 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Baz', 'HTTP_BAR' => 'Boom']); - $res3 = new Response('test 3', 200, ['Vary' => 'Foo Bar']); - $this->store->write($req3, $res3); - - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 3')), $this->store->lookup($req3)->getContent()); - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 2')), $this->store->lookup($req2)->getContent()); - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 1')), $this->store->lookup($req1)->getContent()); - - $this->assertCount(3, $this->getStoreMetadata($key)); - } - - public function testOverwritesNonVaryingResponseWithStore() - { - $req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - $res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']); - $this->store->write($req1, $res1); - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 1')), $this->store->lookup($req1)->getContent()); - - $req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']); - $res2 = new Response('test 2', 200, ['Vary' => 'Foo Bar']); - $this->store->write($req2, $res2); - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 2')), $this->store->lookup($req2)->getContent()); - - $req3 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - $res3 = new Response('test 3', 200, ['Vary' => 'Foo Bar']); - $key = $this->store->write($req3, $res3); - $this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 3')), $this->store->lookup($req3)->getContent()); - - $this->assertCount(2, $this->getStoreMetadata($key)); - } - - public function testLocking() - { - $req = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']); - $this->assertTrue($this->store->lock($req)); - - $this->store->lock($req); - $this->assertTrue($this->store->isLocked($req)); - - $this->store->unlock($req); - $this->assertFalse($this->store->isLocked($req)); - } - - public function testPurgeHttps() - { - $request = Request::create('https://example.com/foo'); - $this->store->write($request, new Response('foo')); - - $this->assertNotEmpty($this->getStoreMetadata($request)); - - $this->assertTrue($this->store->purge('https://example.com/foo')); - $this->assertEmpty($this->getStoreMetadata($request)); - } - - public function testPurgeHttpAndHttps() - { - $requestHttp = Request::create('https://example.com/foo'); - $this->store->write($requestHttp, new Response('foo')); - - $requestHttps = Request::create('http://example.com/foo'); - $this->store->write($requestHttps, new Response('foo')); - - $this->assertNotEmpty($this->getStoreMetadata($requestHttp)); - $this->assertNotEmpty($this->getStoreMetadata($requestHttps)); - - $this->assertTrue($this->store->purge('http://example.com/foo')); - $this->assertEmpty($this->getStoreMetadata($requestHttp)); - $this->assertEmpty($this->getStoreMetadata($requestHttps)); - } - - protected function storeSimpleEntry($path = null, $headers = []) - { - if (null === $path) { - $path = '/test'; - } - - $this->request = Request::create($path, 'get', [], [], [], $headers); - $this->response = new Response('test', 200, ['Cache-Control' => 'max-age=420']); - - return $this->store->write($this->request, $this->response); - } - - protected function getStoreMetadata($key) - { - $r = new \ReflectionObject($this->store); - $m = $r->getMethod('getMetadata'); - $m->setAccessible(true); - - if ($key instanceof Request) { - $m1 = $r->getMethod('getCacheKey'); - $m1->setAccessible(true); - $key = $m1->invoke($this->store, $key); - } - - return $m->invoke($this->store, $key); - } - - protected function getStorePath($key) - { - $r = new \ReflectionObject($this->store); - $m = $r->getMethod('getPath'); - $m->setAccessible(true); - - return $m->invoke($this->store, $key); - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/SubRequestHandlerTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/SubRequestHandlerTest.php deleted file mode 100644 index 67b637bf..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/SubRequestHandlerTest.php +++ /dev/null @@ -1,153 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\HttpCache\SubRequestHandler; -use Symfony\Component\HttpKernel\HttpKernelInterface; - -class SubRequestHandlerTest extends TestCase -{ - private static $globalState; - - protected function setUp() - { - self::$globalState = $this->getGlobalState(); - } - - protected function tearDown() - { - Request::setTrustedProxies(self::$globalState[0], self::$globalState[1]); - } - - public function testTrustedHeadersAreKept() - { - Request::setTrustedProxies(['10.0.0.1'], -1); - $globalState = $this->getGlobalState(); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '10.0.0.1'); - $request->headers->set('X-Forwarded-For', '10.0.0.2'); - $request->headers->set('X-Forwarded-Host', 'Good'); - $request->headers->set('X-Forwarded-Port', '1234'); - $request->headers->set('X-Forwarded-Proto', 'https'); - - $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { - $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); - $this->assertSame('10.0.0.2', $request->getClientIp()); - $this->assertSame('Good', $request->headers->get('X-Forwarded-Host')); - $this->assertSame('1234', $request->headers->get('X-Forwarded-Port')); - $this->assertSame('https', $request->headers->get('X-Forwarded-Proto')); - }); - - SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true); - - $this->assertSame($globalState, $this->getGlobalState()); - } - - public function testUntrustedHeadersAreRemoved() - { - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '10.0.0.1'); - $request->headers->set('X-Forwarded-For', '10.0.0.2'); - $request->headers->set('X-Forwarded-Host', 'Evil'); - $request->headers->set('X-Forwarded-Port', '1234'); - $request->headers->set('X-Forwarded-Proto', 'http'); - $request->headers->set('Forwarded', 'Evil2'); - - $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { - $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); - $this->assertSame('10.0.0.1', $request->getClientIp()); - $this->assertFalse($request->headers->has('X-Forwarded-Host')); - $this->assertFalse($request->headers->has('X-Forwarded-Port')); - $this->assertFalse($request->headers->has('X-Forwarded-Proto')); - $this->assertSame('for="10.0.0.1";host="localhost";proto=http', $request->headers->get('Forwarded')); - }); - - SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true); - - $this->assertSame(self::$globalState, $this->getGlobalState()); - } - - public function testTrustedForwardedHeader() - { - Request::setTrustedProxies(['10.0.0.1'], -1); - $globalState = $this->getGlobalState(); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '10.0.0.1'); - $request->headers->set('Forwarded', 'for="10.0.0.2";host="foo.bar:1234";proto=https'); - - $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { - $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); - $this->assertSame('10.0.0.2', $request->getClientIp()); - $this->assertSame('foo.bar:1234', $request->getHttpHost()); - $this->assertSame('https', $request->getScheme()); - $this->assertSame(1234, $request->getPort()); - }); - - SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true); - - $this->assertSame($globalState, $this->getGlobalState()); - } - - public function testTrustedXForwardedForHeader() - { - Request::setTrustedProxies(['10.0.0.1'], -1); - $globalState = $this->getGlobalState(); - - $request = Request::create('/'); - $request->server->set('REMOTE_ADDR', '10.0.0.1'); - $request->headers->set('X-Forwarded-For', '10.0.0.2'); - $request->headers->set('X-Forwarded-Host', 'foo.bar'); - $request->headers->set('X-Forwarded-Proto', 'https'); - - $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { - $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); - $this->assertSame('10.0.0.2', $request->getClientIp()); - $this->assertSame('foo.bar', $request->getHttpHost()); - $this->assertSame('https', $request->getScheme()); - }); - - SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MASTER_REQUEST, true); - - $this->assertSame($globalState, $this->getGlobalState()); - } - - private function getGlobalState() - { - return [ - Request::getTrustedProxies(), - Request::getTrustedHeaderSet(), - ]; - } -} - -class TestSubRequestHandlerKernel implements HttpKernelInterface -{ - private $assertCallback; - - public function __construct(\Closure $assertCallback) - { - $this->assertCallback = $assertCallback; - } - - public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) - { - $assertCallback = $this->assertCallback; - $assertCallback($request, $type, $catch); - - return new Response(); - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/TestHttpKernel.php b/vendor/symfony/http-kernel/Tests/HttpCache/TestHttpKernel.php deleted file mode 100644 index 304ff9d9..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/TestHttpKernel.php +++ /dev/null @@ -1,102 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\HttpKernel\HttpKernel; -use Symfony\Component\HttpKernel\HttpKernelInterface; - -class TestHttpKernel extends HttpKernel implements ControllerResolverInterface, ArgumentResolverInterface -{ - protected $body; - protected $status; - protected $headers; - protected $called = false; - protected $customizer; - protected $catch = false; - protected $backendRequest; - - public function __construct($body, $status, $headers, \Closure $customizer = null) - { - $this->body = $body; - $this->status = $status; - $this->headers = $headers; - $this->customizer = $customizer; - - parent::__construct(new EventDispatcher(), $this, null, $this); - } - - public function assert(\Closure $callback) - { - $trustedConfig = [Request::getTrustedProxies(), Request::getTrustedHeaderSet()]; - - list($trustedProxies, $trustedHeaderSet, $backendRequest) = $this->backendRequest; - Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); - - try { - $callback($backendRequest); - } finally { - list($trustedProxies, $trustedHeaderSet) = $trustedConfig; - Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); - } - } - - public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false) - { - $this->catch = $catch; - $this->backendRequest = [Request::getTrustedProxies(), Request::getTrustedHeaderSet(), $request]; - - return parent::handle($request, $type, $catch); - } - - public function isCatchingExceptions() - { - return $this->catch; - } - - public function getController(Request $request) - { - return [$this, 'callController']; - } - - public function getArguments(Request $request, $controller) - { - return [$request]; - } - - public function callController(Request $request) - { - $this->called = true; - - $response = new Response($this->body, $this->status, $this->headers); - - if (null !== $customizer = $this->customizer) { - $customizer($request, $response); - } - - return $response; - } - - public function hasBeenCalled() - { - return $this->called; - } - - public function reset() - { - $this->called = false; - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/TestMultipleHttpKernel.php b/vendor/symfony/http-kernel/Tests/HttpCache/TestMultipleHttpKernel.php deleted file mode 100644 index 010bee86..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpCache/TestMultipleHttpKernel.php +++ /dev/null @@ -1,81 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\HttpCache; - -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\HttpKernel\HttpKernel; -use Symfony\Component\HttpKernel\HttpKernelInterface; - -class TestMultipleHttpKernel extends HttpKernel implements ControllerResolverInterface, ArgumentResolverInterface -{ - protected $bodies = []; - protected $statuses = []; - protected $headers = []; - protected $called = false; - protected $backendRequest; - - public function __construct($responses) - { - foreach ($responses as $response) { - $this->bodies[] = $response['body']; - $this->statuses[] = $response['status']; - $this->headers[] = $response['headers']; - } - - parent::__construct(new EventDispatcher(), $this, null, $this); - } - - public function getBackendRequest() - { - return $this->backendRequest; - } - - public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = false) - { - $this->backendRequest = $request; - - return parent::handle($request, $type, $catch); - } - - public function getController(Request $request) - { - return [$this, 'callController']; - } - - public function getArguments(Request $request, $controller) - { - return [$request]; - } - - public function callController(Request $request) - { - $this->called = true; - - $response = new Response(array_shift($this->bodies), array_shift($this->statuses), array_shift($this->headers)); - - return $response; - } - - public function hasBeenCalled() - { - return $this->called; - } - - public function reset() - { - $this->called = false; - } -} diff --git a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php deleted file mode 100644 index 97c58305..00000000 --- a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php +++ /dev/null @@ -1,395 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent; -use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; -use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; -use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; -use Symfony\Component\HttpKernel\HttpKernel; -use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\KernelEvents; - -class HttpKernelTest extends TestCase -{ - public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrue() - { - $this->expectException('RuntimeException'); - $kernel = $this->getHttpKernel(new EventDispatcher(), function () { throw new \RuntimeException(); }); - - $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, true); - } - - public function testHandleWhenControllerThrowsAnExceptionAndCatchIsFalseAndNoListenerIsRegistered() - { - $this->expectException('RuntimeException'); - $kernel = $this->getHttpKernel(new EventDispatcher(), function () { throw new \RuntimeException(); }); - - $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, false); - } - - public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithAHandlingListener() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) { - $event->setResponse(new Response($event->getException()->getMessage())); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { throw new \RuntimeException('foo'); }); - $response = $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, true); - - $this->assertEquals('500', $response->getStatusCode()); - $this->assertEquals('foo', $response->getContent()); - } - - public function testHandleWhenControllerThrowsAnExceptionAndCatchIsTrueWithANonHandlingListener() - { - $exception = new \RuntimeException(); - - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) { - // should set a response, but does not - }); - - $kernel = $this->getHttpKernel($dispatcher, function () use ($exception) { throw $exception; }); - - try { - $kernel->handle(new Request(), HttpKernelInterface::MASTER_REQUEST, true); - $this->fail('LogicException expected'); - } catch (\RuntimeException $e) { - $this->assertSame($exception, $e); - } - } - - public function testHandleExceptionWithARedirectionResponse() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) { - $event->setResponse(new RedirectResponse('/login', 301)); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { throw new AccessDeniedHttpException(); }); - $response = $kernel->handle(new Request()); - - $this->assertEquals('301', $response->getStatusCode()); - $this->assertEquals('/login', $response->headers->get('Location')); - } - - public function testHandleHttpException() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) { - $event->setResponse(new Response($event->getException()->getMessage())); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { throw new MethodNotAllowedHttpException(['POST']); }); - $response = $kernel->handle(new Request()); - - $this->assertEquals('405', $response->getStatusCode()); - $this->assertEquals('POST', $response->headers->get('Allow')); - } - - /** - * @group legacy - * @dataProvider getStatusCodes - */ - public function testLegacyHandleWhenAnExceptionIsHandledWithASpecificStatusCode($responseStatusCode, $expectedStatusCode) - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) use ($responseStatusCode, $expectedStatusCode) { - $event->setResponse(new Response('', $responseStatusCode, ['X-Status-Code' => $expectedStatusCode])); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { throw new \RuntimeException(); }); - $response = $kernel->handle(new Request()); - - $this->assertEquals($expectedStatusCode, $response->getStatusCode()); - $this->assertFalse($response->headers->has('X-Status-Code')); - } - - public function getStatusCodes() - { - return [ - [200, 404], - [404, 200], - [301, 200], - [500, 200], - ]; - } - - /** - * @dataProvider getSpecificStatusCodes - */ - public function testHandleWhenAnExceptionIsHandledWithASpecificStatusCode($expectedStatusCode) - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function (GetResponseForExceptionEvent $event) use ($expectedStatusCode) { - $event->allowCustomResponseCode(); - $event->setResponse(new Response('', $expectedStatusCode)); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { throw new \RuntimeException(); }); - $response = $kernel->handle(new Request()); - - $this->assertEquals($expectedStatusCode, $response->getStatusCode()); - } - - public function getSpecificStatusCodes() - { - return [ - [200], - [302], - [403], - ]; - } - - public function testHandleWhenAListenerReturnsAResponse() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::REQUEST, function ($event) { - $event->setResponse(new Response('hello')); - }); - - $kernel = $this->getHttpKernel($dispatcher); - - $this->assertEquals('hello', $kernel->handle(new Request())->getContent()); - } - - public function testHandleWhenNoControllerIsFound() - { - $this->expectException('Symfony\Component\HttpKernel\Exception\NotFoundHttpException'); - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, false); - - $kernel->handle(new Request()); - } - - public function testHandleWhenTheControllerIsAClosure() - { - $response = new Response('foo'); - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, function () use ($response) { return $response; }); - - $this->assertSame($response, $kernel->handle(new Request())); - } - - public function testHandleWhenTheControllerIsAnObjectWithInvoke() - { - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, new TestController()); - - $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request())); - } - - public function testHandleWhenTheControllerIsAFunction() - { - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, 'Symfony\Component\HttpKernel\Tests\controller_func'); - - $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request())); - } - - public function testHandleWhenTheControllerIsAnArray() - { - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, [new TestController(), 'controller']); - - $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request())); - } - - public function testHandleWhenTheControllerIsAStaticArray() - { - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, ['Symfony\Component\HttpKernel\Tests\TestController', 'staticcontroller']); - - $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request())); - } - - public function testHandleWhenTheControllerDoesNotReturnAResponse() - { - $this->expectException('LogicException'); - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, function () { return 'foo'; }); - - $kernel->handle(new Request()); - } - - public function testHandleWhenTheControllerDoesNotReturnAResponseButAViewIsRegistered() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::VIEW, function ($event) { - $event->setResponse(new Response($event->getControllerResult())); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { return 'foo'; }); - - $this->assertEquals('foo', $kernel->handle(new Request())->getContent()); - } - - public function testHandleWithAResponseListener() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::RESPONSE, function ($event) { - $event->setResponse(new Response('foo')); - }); - $kernel = $this->getHttpKernel($dispatcher); - - $this->assertEquals('foo', $kernel->handle(new Request())->getContent()); - } - - public function testHandleAllowChangingControllerArguments() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function (FilterControllerArgumentsEvent $event) { - $event->setArguments(['foo']); - }); - - $kernel = $this->getHttpKernel($dispatcher, function ($content) { return new Response($content); }); - - $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request())); - } - - public function testHandleAllowChangingControllerAndArguments() - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function (FilterControllerArgumentsEvent $event) { - $oldController = $event->getController(); - $oldArguments = $event->getArguments(); - - $newController = function ($id) use ($oldController, $oldArguments) { - $response = \call_user_func_array($oldController, $oldArguments); - - $response->headers->set('X-Id', $id); - - return $response; - }; - - $event->setController($newController); - $event->setArguments(['bar']); - }); - - $kernel = $this->getHttpKernel($dispatcher, function ($content) { return new Response($content); }, null, ['foo']); - - $this->assertResponseEquals(new Response('foo', 200, ['X-Id' => 'bar']), $kernel->handle(new Request())); - } - - public function testTerminate() - { - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher); - $dispatcher->addListener(KernelEvents::TERMINATE, function ($event) use (&$called, &$capturedKernel, &$capturedRequest, &$capturedResponse) { - $called = true; - $capturedKernel = $event->getKernel(); - $capturedRequest = $event->getRequest(); - $capturedResponse = $event->getResponse(); - }); - - $kernel->terminate($request = Request::create('/'), $response = new Response()); - $this->assertTrue($called); - $this->assertEquals($kernel, $capturedKernel); - $this->assertEquals($request, $capturedRequest); - $this->assertEquals($response, $capturedResponse); - } - - public function testVerifyRequestStackPushPopDuringHandle() - { - $request = new Request(); - - $stack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->setMethods(['push', 'pop'])->getMock(); - $stack->expects($this->once())->method('push')->with($this->equalTo($request)); - $stack->expects($this->once())->method('pop'); - - $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, null, $stack); - - $kernel->handle($request, HttpKernelInterface::MASTER_REQUEST); - } - - public function testInconsistentClientIpsOnMasterRequests() - { - $this->expectException('Symfony\Component\HttpKernel\Exception\BadRequestHttpException'); - $request = new Request(); - $request->setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_FORWARDED); - $request->server->set('REMOTE_ADDR', '1.1.1.1'); - $request->headers->set('FORWARDED', 'for=2.2.2.2'); - $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); - - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::REQUEST, function ($event) { - $event->getRequest()->getClientIp(); - }); - - $kernel = $this->getHttpKernel($dispatcher); - $kernel->handle($request, $kernel::MASTER_REQUEST, false); - - Request::setTrustedProxies([], -1); - } - - private function getHttpKernel(EventDispatcherInterface $eventDispatcher, $controller = null, RequestStack $requestStack = null, array $arguments = []) - { - if (null === $controller) { - $controller = function () { return new Response('Hello'); }; - } - - $controllerResolver = $this->getMockBuilder(ControllerResolverInterface::class)->getMock(); - $controllerResolver - ->expects($this->any()) - ->method('getController') - ->willReturn($controller); - - $argumentResolver = $this->getMockBuilder(ArgumentResolverInterface::class)->getMock(); - $argumentResolver - ->expects($this->any()) - ->method('getArguments') - ->willReturn($arguments); - - return new HttpKernel($eventDispatcher, $controllerResolver, $requestStack, $argumentResolver); - } - - private function assertResponseEquals(Response $expected, Response $actual) - { - $expected->setDate($actual->getDate()); - $this->assertEquals($expected, $actual); - } -} - -class TestController -{ - public function __invoke() - { - return new Response('foo'); - } - - public function controller() - { - return new Response('foo'); - } - - public static function staticController() - { - return new Response('foo'); - } -} - -function controller_func() -{ - return new Response('foo'); -} diff --git a/vendor/symfony/http-kernel/Tests/KernelTest.php b/vendor/symfony/http-kernel/Tests/KernelTest.php deleted file mode 100644 index fd840bbb..00000000 --- a/vendor/symfony/http-kernel/Tests/KernelTest.php +++ /dev/null @@ -1,1077 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Config\Loader\LoaderInterface; -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\ContainerInterface; -use Symfony\Component\Filesystem\Filesystem; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Bundle\BundleInterface; -use Symfony\Component\HttpKernel\Config\EnvParametersResource; -use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; -use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; -use Symfony\Component\HttpKernel\HttpKernelInterface; -use Symfony\Component\HttpKernel\Kernel; -use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForOverrideName; -use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest; -use Symfony\Component\HttpKernel\Tests\Fixtures\KernelWithoutBundles; -use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService; - -class KernelTest extends TestCase -{ - public static function tearDownAfterClass() - { - $fs = new Filesystem(); - $fs->remove(__DIR__.'/Fixtures/cache'); - } - - public function testConstructor() - { - $env = 'test_env'; - $debug = true; - $kernel = new KernelForTest($env, $debug); - - $this->assertEquals($env, $kernel->getEnvironment()); - $this->assertEquals($debug, $kernel->isDebug()); - $this->assertFalse($kernel->isBooted()); - $this->assertLessThanOrEqual(microtime(true), $kernel->getStartTime()); - $this->assertNull($kernel->getContainer()); - } - - public function testClone() - { - $env = 'test_env'; - $debug = true; - $kernel = new KernelForTest($env, $debug); - - $clone = clone $kernel; - - $this->assertEquals($env, $clone->getEnvironment()); - $this->assertEquals($debug, $clone->isDebug()); - $this->assertFalse($clone->isBooted()); - $this->assertLessThanOrEqual(microtime(true), $clone->getStartTime()); - $this->assertNull($clone->getContainer()); - } - - public function testInitializeContainerClearsOldContainers() - { - $fs = new Filesystem(); - $legacyContainerDir = __DIR__.'/Fixtures/cache/custom/ContainerA123456'; - $fs->mkdir($legacyContainerDir); - touch($legacyContainerDir.'.legacy'); - - $kernel = new CustomProjectDirKernel(); - $kernel->boot(); - - $containerDir = __DIR__.'/Fixtures/cache/custom/'.substr(\get_class($kernel->getContainer()), 0, 16); - $this->assertTrue(unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta')); - $this->assertFileExists($containerDir); - $this->assertFileDoesNotExist($containerDir.'.legacy'); - - $kernel = new CustomProjectDirKernel(function ($container) { $container->register('foo', 'stdClass')->setPublic(true); }); - $kernel->boot(); - - $this->assertFileExists($containerDir); - $this->assertFileExists($containerDir.'.legacy'); - - $this->assertFileDoesNotExist($legacyContainerDir); - $this->assertFileDoesNotExist($legacyContainerDir.'.legacy'); - } - - public function testBootInitializesBundlesAndContainer() - { - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer']); - $kernel->expects($this->once()) - ->method('initializeBundles'); - $kernel->expects($this->once()) - ->method('initializeContainer'); - - $kernel->boot(); - } - - public function testBootSetsTheContainerToTheBundles() - { - $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')->getMock(); - $bundle->expects($this->once()) - ->method('setContainer'); - - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer', 'getBundles']); - $kernel->expects($this->once()) - ->method('getBundles') - ->willReturn([$bundle]); - - $kernel->boot(); - } - - public function testBootSetsTheBootedFlagToTrue() - { - // use test kernel to access isBooted() - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer']); - $kernel->boot(); - - $this->assertTrue($kernel->isBooted()); - } - - /** - * @group legacy - */ - public function testClassCacheIsLoaded() - { - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer', 'doLoadClassCache']); - $kernel->loadClassCache('name', '.extension'); - $kernel->expects($this->once()) - ->method('doLoadClassCache') - ->with('name', '.extension'); - - $kernel->boot(); - } - - public function testClassCacheIsNotLoadedByDefault() - { - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer', 'doLoadClassCache']); - $kernel->expects($this->never()) - ->method('doLoadClassCache'); - - $kernel->boot(); - } - - /** - * @group legacy - */ - public function testClassCacheIsNotLoadedWhenKernelIsNotBooted() - { - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer', 'doLoadClassCache']); - $kernel->loadClassCache(); - $kernel->expects($this->never()) - ->method('doLoadClassCache'); - } - - public function testEnvParametersResourceIsAdded() - { - $container = new ContainerBuilder(); - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest') - ->disableOriginalConstructor() - ->setMethods(['getContainerBuilder', 'prepareContainer', 'getCacheDir', 'getLogDir']) - ->getMock(); - $kernel->expects($this->any()) - ->method('getContainerBuilder') - ->willReturn($container); - $kernel->expects($this->any()) - ->method('prepareContainer') - ->willReturn(null); - $kernel->expects($this->any()) - ->method('getCacheDir') - ->willReturn(sys_get_temp_dir()); - $kernel->expects($this->any()) - ->method('getLogDir') - ->willReturn(sys_get_temp_dir()); - - $reflection = new \ReflectionClass(\get_class($kernel)); - $method = $reflection->getMethod('buildContainer'); - $method->setAccessible(true); - $method->invoke($kernel); - - $found = false; - foreach ($container->getResources() as $resource) { - if ($resource instanceof EnvParametersResource) { - $found = true; - break; - } - } - - $this->assertTrue($found); - } - - public function testBootKernelSeveralTimesOnlyInitializesBundlesOnce() - { - $kernel = $this->getKernel(['initializeBundles', 'initializeContainer']); - $kernel->expects($this->once()) - ->method('initializeBundles'); - - $kernel->boot(); - $kernel->boot(); - } - - public function testShutdownCallsShutdownOnAllBundles() - { - $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')->getMock(); - $bundle->expects($this->once()) - ->method('shutdown'); - - $kernel = $this->getKernel([], [$bundle]); - - $kernel->boot(); - $kernel->shutdown(); - } - - public function testShutdownGivesNullContainerToAllBundles() - { - $bundle = $this->getMockBuilder('Symfony\Component\HttpKernel\Bundle\Bundle')->getMock(); - $bundle->expects($this->exactly(2)) - ->method('setContainer') - ->withConsecutive( - [$this->isInstanceOf(ContainerInterface::class)], - [null] - ); - - $kernel = $this->getKernel(['getBundles']); - $kernel->expects($this->any()) - ->method('getBundles') - ->willReturn([$bundle]); - - $kernel->boot(); - $kernel->shutdown(); - } - - public function testHandleCallsHandleOnHttpKernel() - { - $type = HttpKernelInterface::MASTER_REQUEST; - $catch = true; - $request = new Request(); - - $httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernel') - ->disableOriginalConstructor() - ->getMock(); - $httpKernelMock - ->expects($this->once()) - ->method('handle') - ->with($request, $type, $catch); - - $kernel = $this->getKernel(['getHttpKernel']); - $kernel->expects($this->once()) - ->method('getHttpKernel') - ->willReturn($httpKernelMock); - - $kernel->handle($request, $type, $catch); - } - - public function testHandleBootsTheKernel() - { - $type = HttpKernelInterface::MASTER_REQUEST; - $catch = true; - $request = new Request(); - - $httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernel') - ->disableOriginalConstructor() - ->getMock(); - - $kernel = $this->getKernel(['getHttpKernel', 'boot']); - $kernel->expects($this->once()) - ->method('getHttpKernel') - ->willReturn($httpKernelMock); - - $kernel->expects($this->once()) - ->method('boot'); - - $kernel->handle($request, $type, $catch); - } - - public function testStripComments() - { - $source = <<<'EOF' -assertEquals($expected, $output); - } - - public function testGetRootDir() - { - $kernel = new KernelForTest('test', true); - - $this->assertEquals(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures', realpath($kernel->getRootDir())); - } - - public function testGetName() - { - $kernel = new KernelForTest('test', true); - - $this->assertEquals('Fixtures', $kernel->getName()); - } - - public function testOverrideGetName() - { - $kernel = new KernelForOverrideName('test', true); - - $this->assertEquals('overridden', $kernel->getName()); - } - - public function testSerialize() - { - $env = 'test_env'; - $debug = true; - $kernel = new KernelForTest($env, $debug); - - $expected = serialize([$env, $debug]); - $this->assertEquals($expected, $kernel->serialize()); - } - - public function testLocateResourceThrowsExceptionWhenNameIsNotValid() - { - $this->expectException('InvalidArgumentException'); - $this->getKernel()->locateResource('Foo'); - } - - public function testLocateResourceThrowsExceptionWhenNameIsUnsafe() - { - $this->expectException('RuntimeException'); - $this->getKernel()->locateResource('@FooBundle/../bar'); - } - - public function testLocateResourceThrowsExceptionWhenBundleDoesNotExist() - { - $this->expectException('InvalidArgumentException'); - $this->getKernel()->locateResource('@FooBundle/config/routing.xml'); - } - - public function testLocateResourceThrowsExceptionWhenResourceDoesNotExist() - { - $this->expectException('InvalidArgumentException'); - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle')]) - ; - - $kernel->locateResource('@Bundle1Bundle/config/routing.xml'); - } - - public function testLocateResourceReturnsTheFirstThatMatches() - { - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle')]) - ; - - $this->assertEquals(__DIR__.'/Fixtures/Bundle1Bundle/foo.txt', $kernel->locateResource('@Bundle1Bundle/foo.txt')); - } - - /** - * @group legacy - */ - public function testLocateResourceReturnsTheFirstThatMatchesWithParent() - { - $parent = $this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'); - $child = $this->getBundle(__DIR__.'/Fixtures/Bundle2Bundle'); - - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->exactly(2)) - ->method('getBundle') - ->willReturn([$child, $parent]) - ; - - $this->assertEquals(__DIR__.'/Fixtures/Bundle2Bundle/foo.txt', $kernel->locateResource('@ParentAABundle/foo.txt')); - $this->assertEquals(__DIR__.'/Fixtures/Bundle1Bundle/bar.txt', $kernel->locateResource('@ParentAABundle/bar.txt')); - } - - /** - * @group legacy - */ - public function testLocateResourceReturnsAllMatches() - { - $parent = $this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'); - $child = $this->getBundle(__DIR__.'/Fixtures/Bundle2Bundle'); - - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([$child, $parent]) - ; - - $this->assertEquals([ - __DIR__.'/Fixtures/Bundle2Bundle/foo.txt', - __DIR__.'/Fixtures/Bundle1Bundle/foo.txt', ], - $kernel->locateResource('@Bundle1Bundle/foo.txt', null, false)); - } - - /** - * @group legacy - */ - public function testLocateResourceReturnsAllMatchesBis() - { - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([ - $this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'), - $this->getBundle(__DIR__.'/Foobar'), - ]) - ; - - $this->assertEquals( - [__DIR__.'/Fixtures/Bundle1Bundle/foo.txt'], - $kernel->locateResource('@Bundle1Bundle/foo.txt', null, false) - ); - } - - public function testLocateResourceIgnoresDirOnNonResource() - { - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle')]) - ; - - $this->assertEquals( - __DIR__.'/Fixtures/Bundle1Bundle/foo.txt', - $kernel->locateResource('@Bundle1Bundle/foo.txt', __DIR__.'/Fixtures') - ); - } - - public function testLocateResourceReturnsTheDirOneForResources() - { - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/FooBundle', null, null, 'FooBundle')]) - ; - - $this->assertEquals( - __DIR__.'/Fixtures/Resources/FooBundle/foo.txt', - $kernel->locateResource('@FooBundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources') - ); - } - - /** - * @group legacy - */ - public function testLocateResourceReturnsTheDirOneForResourcesAndBundleOnes() - { - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle', null, null, 'Bundle1Bundle')]) - ; - - $this->assertEquals([ - __DIR__.'/Fixtures/Resources/Bundle1Bundle/foo.txt', - __DIR__.'/Fixtures/Bundle1Bundle/Resources/foo.txt', ], - $kernel->locateResource('@Bundle1Bundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources', false) - ); - } - - /** - * @group legacy - */ - public function testLocateResourceOverrideBundleAndResourcesFolders() - { - $parent = $this->getBundle(__DIR__.'/Fixtures/BaseBundle', null, 'BaseBundle', 'BaseBundle'); - $child = $this->getBundle(__DIR__.'/Fixtures/ChildBundle', 'ParentBundle', 'ChildBundle', 'ChildBundle'); - - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->exactly(4)) - ->method('getBundle') - ->willReturn([$child, $parent]) - ; - - $this->assertEquals([ - __DIR__.'/Fixtures/Resources/ChildBundle/foo.txt', - __DIR__.'/Fixtures/ChildBundle/Resources/foo.txt', - __DIR__.'/Fixtures/BaseBundle/Resources/foo.txt', - ], - $kernel->locateResource('@BaseBundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources', false) - ); - - $this->assertEquals( - __DIR__.'/Fixtures/Resources/ChildBundle/foo.txt', - $kernel->locateResource('@BaseBundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources') - ); - - try { - $kernel->locateResource('@BaseBundle/Resources/hide.txt', __DIR__.'/Fixtures/Resources', false); - $this->fail('Hidden resources should raise an exception when returning an array of matching paths'); - } catch (\RuntimeException $e) { - } - - try { - $kernel->locateResource('@BaseBundle/Resources/hide.txt', __DIR__.'/Fixtures/Resources', true); - $this->fail('Hidden resources should raise an exception when returning the first matching path'); - } catch (\RuntimeException $e) { - } - } - - public function testLocateResourceOnDirectories() - { - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->exactly(2)) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/FooBundle', null, null, 'FooBundle')]) - ; - - $this->assertEquals( - __DIR__.'/Fixtures/Resources/FooBundle/', - $kernel->locateResource('@FooBundle/Resources/', __DIR__.'/Fixtures/Resources') - ); - $this->assertEquals( - __DIR__.'/Fixtures/Resources/FooBundle', - $kernel->locateResource('@FooBundle/Resources', __DIR__.'/Fixtures/Resources') - ); - - $kernel = $this->getKernel(['getBundle']); - $kernel - ->expects($this->exactly(2)) - ->method('getBundle') - ->willReturn([$this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle', null, null, 'Bundle1Bundle')]) - ; - - $this->assertEquals( - __DIR__.'/Fixtures/Bundle1Bundle/Resources/', - $kernel->locateResource('@Bundle1Bundle/Resources/') - ); - $this->assertEquals( - __DIR__.'/Fixtures/Bundle1Bundle/Resources', - $kernel->locateResource('@Bundle1Bundle/Resources') - ); - } - - /** - * @group legacy - */ - public function testInitializeBundles() - { - $parent = $this->getBundle(null, null, 'ParentABundle'); - $child = $this->getBundle(null, 'ParentABundle', 'ChildABundle'); - - // use test kernel so we can access getBundleMap() - $kernel = $this->getKernelForTest(['registerBundles']); - $kernel - ->expects($this->once()) - ->method('registerBundles') - ->willReturn([$parent, $child]) - ; - $kernel->boot(); - - $map = $kernel->getBundleMap(); - $this->assertEquals([$child, $parent], $map['ParentABundle']); - } - - /** - * @group legacy - */ - public function testInitializeBundlesSupportInheritanceCascade() - { - $grandparent = $this->getBundle(null, null, 'GrandParentBBundle'); - $parent = $this->getBundle(null, 'GrandParentBBundle', 'ParentBBundle'); - $child = $this->getBundle(null, 'ParentBBundle', 'ChildBBundle'); - - // use test kernel so we can access getBundleMap() - $kernel = $this->getKernelForTest(['registerBundles']); - $kernel - ->expects($this->once()) - ->method('registerBundles') - ->willReturn([$grandparent, $parent, $child]) - ; - $kernel->boot(); - - $map = $kernel->getBundleMap(); - $this->assertEquals([$child, $parent, $grandparent], $map['GrandParentBBundle']); - $this->assertEquals([$child, $parent], $map['ParentBBundle']); - $this->assertEquals([$child], $map['ChildBBundle']); - } - - /** - * @group legacy - */ - public function testInitializeBundlesThrowsExceptionWhenAParentDoesNotExists() - { - $this->expectException('LogicException'); - $this->expectExceptionMessage('Bundle "ChildCBundle" extends bundle "FooBar", which is not registered.'); - $child = $this->getBundle(null, 'FooBar', 'ChildCBundle'); - $kernel = $this->getKernel([], [$child]); - $kernel->boot(); - } - - /** - * @group legacy - */ - public function testInitializeBundlesSupportsArbitraryBundleRegistrationOrder() - { - $grandparent = $this->getBundle(null, null, 'GrandParentCBundle'); - $parent = $this->getBundle(null, 'GrandParentCBundle', 'ParentCBundle'); - $child = $this->getBundle(null, 'ParentCBundle', 'ChildCBundle'); - - // use test kernel so we can access getBundleMap() - $kernel = $this->getKernelForTest(['registerBundles']); - $kernel - ->expects($this->once()) - ->method('registerBundles') - ->willReturn([$parent, $grandparent, $child]) - ; - $kernel->boot(); - - $map = $kernel->getBundleMap(); - $this->assertEquals([$child, $parent, $grandparent], $map['GrandParentCBundle']); - $this->assertEquals([$child, $parent], $map['ParentCBundle']); - $this->assertEquals([$child], $map['ChildCBundle']); - } - - /** - * @group legacy - */ - public function testInitializeBundlesThrowsExceptionWhenABundleIsDirectlyExtendedByTwoBundles() - { - $this->expectException('LogicException'); - $this->expectExceptionMessage('Bundle "ParentCBundle" is directly extended by two bundles "ChildC2Bundle" and "ChildC1Bundle".'); - $parent = $this->getBundle(null, null, 'ParentCBundle'); - $child1 = $this->getBundle(null, 'ParentCBundle', 'ChildC1Bundle'); - $child2 = $this->getBundle(null, 'ParentCBundle', 'ChildC2Bundle'); - - $kernel = $this->getKernel([], [$parent, $child1, $child2]); - $kernel->boot(); - } - - /** - * @group legacy - */ - public function testInitializeBundleThrowsExceptionWhenRegisteringTwoBundlesWithTheSameName() - { - $this->expectException('LogicException'); - $this->expectExceptionMessage('Trying to register two bundles with the same name "DuplicateName"'); - $fooBundle = $this->getBundle(__DIR__.'/Fixtures/FooBundle', null, 'FooBundle', 'DuplicateName'); - $barBundle = $this->getBundle(__DIR__.'/Fixtures/BarBundle', null, 'BarBundle', 'DuplicateName'); - - $kernel = $this->getKernel([], [$fooBundle, $barBundle]); - $kernel->boot(); - } - - /** - * @group legacy - */ - public function testInitializeBundleThrowsExceptionWhenABundleExtendsItself() - { - $this->expectException('LogicException'); - $this->expectExceptionMessage('Bundle "CircularRefBundle" can not extend itself.'); - $circularRef = $this->getBundle(null, 'CircularRefBundle', 'CircularRefBundle'); - - $kernel = $this->getKernel([], [$circularRef]); - $kernel->boot(); - } - - public function testTerminateReturnsSilentlyIfKernelIsNotBooted() - { - $kernel = $this->getKernel(['getHttpKernel']); - $kernel->expects($this->never()) - ->method('getHttpKernel'); - - $kernel->terminate(Request::create('/'), new Response()); - } - - public function testTerminateDelegatesTerminationOnlyForTerminableInterface() - { - // does not implement TerminableInterface - $httpKernel = new TestKernel(); - - $kernel = $this->getKernel(['getHttpKernel']); - $kernel->expects($this->once()) - ->method('getHttpKernel') - ->willReturn($httpKernel); - - $kernel->boot(); - $kernel->terminate(Request::create('/'), new Response()); - - $this->assertFalse($httpKernel->terminateCalled, 'terminate() is never called if the kernel class does not implement TerminableInterface'); - - // implements TerminableInterface - $httpKernelMock = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernel') - ->disableOriginalConstructor() - ->setMethods(['terminate']) - ->getMock(); - - $httpKernelMock - ->expects($this->once()) - ->method('terminate'); - - $kernel = $this->getKernel(['getHttpKernel']); - $kernel->expects($this->exactly(2)) - ->method('getHttpKernel') - ->willReturn($httpKernelMock); - - $kernel->boot(); - $kernel->terminate(Request::create('/'), new Response()); - } - - public function testKernelWithoutBundles() - { - $kernel = new KernelWithoutBundles('test', true); - $kernel->boot(); - - $this->assertTrue($kernel->getContainer()->getParameter('test_executed')); - } - - public function testKernelRootDirNameStartingWithANumber() - { - $dir = __DIR__.'/Fixtures/123'; - require_once $dir.'/Kernel123.php'; - $kernel = new \Symfony\Component\HttpKernel\Tests\Fixtures\_123\Kernel123('dev', true); - $this->assertEquals('_123', $kernel->getName()); - } - - /** - * @group legacy - * @expectedDeprecation The "Symfony\Component\HttpKernel\Kernel::getEnvParameters()" method is deprecated as of 3.3 and will be removed in 4.0. Use the %cenv()%c syntax to get the value of any environment variable from configuration files instead. - * @expectedDeprecation The support of special environment variables that start with SYMFONY__ (such as "SYMFONY__FOO__BAR") is deprecated as of 3.3 and will be removed in 4.0. Use the %cenv()%c syntax instead to get the value of environment variables in configuration files. - */ - public function testSymfonyEnvironmentVariables() - { - $_SERVER['SYMFONY__FOO__BAR'] = 'baz'; - - $kernel = $this->getKernel(); - $method = new \ReflectionMethod($kernel, 'getEnvParameters'); - $method->setAccessible(true); - - $envParameters = $method->invoke($kernel); - $this->assertSame('baz', $envParameters['foo.bar']); - - unset($_SERVER['SYMFONY__FOO__BAR']); - } - - public function testProjectDirExtension() - { - $kernel = new CustomProjectDirKernel(); - $kernel->boot(); - - $this->assertSame('foo', $kernel->getProjectDir()); - $this->assertSame('foo', $kernel->getContainer()->getParameter('kernel.project_dir')); - } - - public function testKernelReset() - { - (new Filesystem())->remove(__DIR__.'/Fixtures/cache'); - - $kernel = new CustomProjectDirKernel(); - $kernel->boot(); - - $containerClass = \get_class($kernel->getContainer()); - $containerFile = (new \ReflectionClass($kernel->getContainer()))->getFileName(); - unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta'); - - $kernel = new CustomProjectDirKernel(); - $kernel->boot(); - - $this->assertInstanceOf($containerClass, $kernel->getContainer()); - $this->assertFileExists($containerFile); - unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta'); - - $kernel = new CustomProjectDirKernel(function ($container) { $container->register('foo', 'stdClass')->setPublic(true); }); - $kernel->boot(); - - $this->assertNotInstanceOf($containerClass, $kernel->getContainer()); - $this->assertFileExists($containerFile); - $this->assertFileExists(\dirname($containerFile).'.legacy'); - } - - public function testKernelPass() - { - $kernel = new PassKernel(); - $kernel->boot(); - - $this->assertTrue($kernel->getContainer()->getParameter('test.processed')); - } - - public function testServicesResetter() - { - $httpKernelMock = $this->getMockBuilder(HttpKernelInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $httpKernelMock - ->expects($this->exactly(2)) - ->method('handle'); - - $kernel = new CustomProjectDirKernel(function ($container) { - $container->addCompilerPass(new ResettableServicePass()); - $container->register('one', ResettableService::class) - ->setPublic(true) - ->addTag('kernel.reset', ['method' => 'reset']); - $container->register('services_resetter', ServicesResetter::class)->setPublic(true); - }, $httpKernelMock, 'resetting'); - - ResettableService::$counter = 0; - - $request = new Request(); - - $kernel->handle($request); - $kernel->getContainer()->get('one'); - - $this->assertEquals(0, ResettableService::$counter); - $this->assertFalse($kernel->getContainer()->initialized('services_resetter')); - - $kernel->handle($request); - - $this->assertEquals(1, ResettableService::$counter); - } - - /** - * @group time-sensitive - */ - public function testKernelStartTimeIsResetWhileBootingAlreadyBootedKernel() - { - $kernel = $this->getKernel(['initializeBundles'], [], true); - $kernel->boot(); - $preReBoot = $kernel->getStartTime(); - - sleep(3600); //Intentionally large value to detect if ClockMock ever breaks - $kernel->reboot(null); - - $this->assertGreaterThan($preReBoot, $kernel->getStartTime()); - } - - /** - * Returns a mock for the BundleInterface. - * - * @return BundleInterface - */ - protected function getBundle($dir = null, $parent = null, $className = null, $bundleName = null) - { - $bundle = $this - ->getMockBuilder('Symfony\Component\HttpKernel\Bundle\BundleInterface') - ->setMethods(['getPath', 'getParent', 'getName']) - ->disableOriginalConstructor() - ; - - if ($className) { - $bundle->setMockClassName($className); - } - - $bundle = $bundle->getMockForAbstractClass(); - - $bundle - ->expects($this->any()) - ->method('getName') - ->willReturn(null === $bundleName ? \get_class($bundle) : $bundleName) - ; - - $bundle - ->expects($this->any()) - ->method('getPath') - ->willReturn($dir) - ; - - $bundle - ->expects($this->any()) - ->method('getParent') - ->willReturn($parent) - ; - - return $bundle; - } - - /** - * Returns a mock for the abstract kernel. - * - * @param array $methods Additional methods to mock (besides the abstract ones) - * @param array $bundles Bundles to register - * - * @return Kernel - */ - protected function getKernel(array $methods = [], array $bundles = [], $debug = false) - { - $methods[] = 'registerBundles'; - - $kernel = $this - ->getMockBuilder(KernelForTest::class) - ->setMethods($methods) - ->setConstructorArgs(['test', $debug]) - ->getMock() - ; - $kernel->expects($this->any()) - ->method('registerBundles') - ->willReturn($bundles) - ; - $p = new \ReflectionProperty($kernel, 'rootDir'); - $p->setAccessible(true); - $p->setValue($kernel, __DIR__.'/Fixtures'); - - return $kernel; - } - - protected function getKernelForTest(array $methods = [], $debug = false) - { - $kernel = $this->getMockBuilder(KernelForTest::class) - ->setConstructorArgs(['test', $debug]) - ->setMethods($methods) - ->getMock() - ; - $p = new \ReflectionProperty($kernel, 'rootDir'); - $p->setAccessible(true); - $p->setValue($kernel, __DIR__.'/Fixtures'); - - return $kernel; - } -} - -class TestKernel implements HttpKernelInterface -{ - public $terminateCalled = false; - - public function terminate() - { - $this->terminateCalled = true; - } - - public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true) - { - } - - public function getProjectDir() - { - return __DIR__.'/Fixtures'; - } -} - -class CustomProjectDirKernel extends Kernel -{ - private $baseDir; - private $buildContainer; - private $httpKernel; - - public function __construct(\Closure $buildContainer = null, HttpKernelInterface $httpKernel = null, $name = 'custom') - { - parent::__construct($name, true); - - $this->baseDir = 'foo'; - $this->buildContainer = $buildContainer; - $this->httpKernel = $httpKernel; - } - - public function registerBundles() - { - return []; - } - - public function registerContainerConfiguration(LoaderInterface $loader) - { - } - - public function getProjectDir() - { - return $this->baseDir; - } - - public function getRootDir() - { - return __DIR__.'/Fixtures'; - } - - protected function build(ContainerBuilder $container) - { - if ($build = $this->buildContainer) { - $build($container); - } - } - - protected function getHttpKernel() - { - return $this->httpKernel; - } -} - -class PassKernel extends CustomProjectDirKernel implements CompilerPassInterface -{ - public function __construct() - { - parent::__construct(); - Kernel::__construct('pass', true); - } - - public function process(ContainerBuilder $container) - { - $container->setParameter('test.processed', true); - } -} diff --git a/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php b/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php deleted file mode 100644 index fd304579..00000000 --- a/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php +++ /dev/null @@ -1,206 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\Log; - -use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; -use Psr\Log\LogLevel; -use Symfony\Component\HttpKernel\Log\Logger; - -/** - * @author Kévin Dunglas - * @author Jordi Boggiano - */ -class LoggerTest extends TestCase -{ - /** - * @var LoggerInterface - */ - private $logger; - - /** - * @var string - */ - private $tmpFile; - - protected function setUp() - { - $this->tmpFile = tempnam(sys_get_temp_dir(), 'log'); - $this->logger = new Logger(LogLevel::DEBUG, $this->tmpFile); - } - - protected function tearDown() - { - if (!@unlink($this->tmpFile)) { - file_put_contents($this->tmpFile, ''); - } - } - - public static function assertLogsMatch(array $expected, array $given) - { - foreach ($given as $k => $line) { - self::assertThat(1 === preg_match('/[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}[\+-][0-9]{2}:[0-9]{2} '.preg_quote($expected[$k]).'/', $line), self::isTrue(), "\"$line\" do not match expected pattern \"$expected[$k]\""); - } - } - - /** - * Return the log messages in order. - * - * @return string[] - */ - public function getLogs() - { - return file($this->tmpFile, \FILE_IGNORE_NEW_LINES); - } - - public function testImplements() - { - $this->assertInstanceOf(LoggerInterface::class, $this->logger); - } - - /** - * @dataProvider provideLevelsAndMessages - */ - public function testLogsAtAllLevels($level, $message) - { - $this->logger->{$level}($message, ['user' => 'Bob']); - $this->logger->log($level, $message, ['user' => 'Bob']); - - $expected = [ - "[$level] message of level $level with context: Bob", - "[$level] message of level $level with context: Bob", - ]; - $this->assertLogsMatch($expected, $this->getLogs()); - } - - public function provideLevelsAndMessages() - { - return [ - LogLevel::EMERGENCY => [LogLevel::EMERGENCY, 'message of level emergency with context: {user}'], - LogLevel::ALERT => [LogLevel::ALERT, 'message of level alert with context: {user}'], - LogLevel::CRITICAL => [LogLevel::CRITICAL, 'message of level critical with context: {user}'], - LogLevel::ERROR => [LogLevel::ERROR, 'message of level error with context: {user}'], - LogLevel::WARNING => [LogLevel::WARNING, 'message of level warning with context: {user}'], - LogLevel::NOTICE => [LogLevel::NOTICE, 'message of level notice with context: {user}'], - LogLevel::INFO => [LogLevel::INFO, 'message of level info with context: {user}'], - LogLevel::DEBUG => [LogLevel::DEBUG, 'message of level debug with context: {user}'], - ]; - } - - public function testLogLevelDisabled() - { - $this->logger = new Logger(LogLevel::INFO, $this->tmpFile); - - $this->logger->debug('test', ['user' => 'Bob']); - $this->logger->log(LogLevel::DEBUG, 'test', ['user' => 'Bob']); - - // Will always be true, but asserts than an exception isn't thrown - $this->assertSame([], $this->getLogs()); - } - - public function testThrowsOnInvalidLevel() - { - $this->expectException('Psr\Log\InvalidArgumentException'); - $this->logger->log('invalid level', 'Foo'); - } - - public function testThrowsOnInvalidMinLevel() - { - $this->expectException('Psr\Log\InvalidArgumentException'); - new Logger('invalid'); - } - - public function testInvalidOutput() - { - $this->expectException('Psr\Log\InvalidArgumentException'); - new Logger(LogLevel::DEBUG, '/'); - } - - public function testContextReplacement() - { - $logger = $this->logger; - $logger->info('{Message {nothing} {user} {foo.bar} a}', ['user' => 'Bob', 'foo.bar' => 'Bar']); - - $expected = ['[info] {Message {nothing} Bob Bar a}']; - $this->assertLogsMatch($expected, $this->getLogs()); - } - - public function testObjectCastToString() - { - if (method_exists($this, 'createPartialMock')) { - $dummy = $this->createPartialMock(DummyTest::class, ['__toString']); - } else { - $dummy = $this->createPartialMock(DummyTest::class, ['__toString']); - } - $dummy->expects($this->atLeastOnce()) - ->method('__toString') - ->willReturn('DUMMY'); - - $this->logger->warning($dummy); - - $expected = ['[warning] DUMMY']; - $this->assertLogsMatch($expected, $this->getLogs()); - } - - public function testContextCanContainAnything() - { - $context = [ - 'bool' => true, - 'null' => null, - 'string' => 'Foo', - 'int' => 0, - 'float' => 0.5, - 'nested' => ['with object' => new DummyTest()], - 'object' => new \DateTime(), - 'resource' => fopen('php://memory', 'r'), - ]; - - $this->logger->warning('Crazy context data', $context); - - $expected = ['[warning] Crazy context data']; - $this->assertLogsMatch($expected, $this->getLogs()); - } - - public function testContextExceptionKeyCanBeExceptionOrOtherValues() - { - $logger = $this->logger; - $logger->warning('Random message', ['exception' => 'oops']); - $logger->critical('Uncaught Exception!', ['exception' => new \LogicException('Fail')]); - - $expected = [ - '[warning] Random message', - '[critical] Uncaught Exception!', - ]; - $this->assertLogsMatch($expected, $this->getLogs()); - } - - public function testFormatter() - { - $this->logger = new Logger(LogLevel::DEBUG, $this->tmpFile, function ($level, $message, $context) { - return json_encode(['level' => $level, 'message' => $message, 'context' => $context]).\PHP_EOL; - }); - - $this->logger->error('An error', ['foo' => 'bar']); - $this->logger->warning('A warning', ['baz' => 'bar']); - $this->assertSame([ - '{"level":"error","message":"An error","context":{"foo":"bar"}}', - '{"level":"warning","message":"A warning","context":{"baz":"bar"}}', - ], $this->getLogs()); - } -} - -class DummyTest -{ - public function __toString() - { - } -} diff --git a/vendor/symfony/http-kernel/Tests/Logger.php b/vendor/symfony/http-kernel/Tests/Logger.php deleted file mode 100644 index 47529a2d..00000000 --- a/vendor/symfony/http-kernel/Tests/Logger.php +++ /dev/null @@ -1,91 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests; - -use Psr\Log\LoggerInterface; - -class Logger implements LoggerInterface -{ - protected $logs; - - public function __construct() - { - $this->clear(); - } - - /** - * @return array - */ - public function getLogs($level = false) - { - return false === $level ? $this->logs : $this->logs[$level]; - } - - public function clear() - { - $this->logs = [ - 'emergency' => [], - 'alert' => [], - 'critical' => [], - 'error' => [], - 'warning' => [], - 'notice' => [], - 'info' => [], - 'debug' => [], - ]; - } - - public function log($level, $message, array $context = []) - { - $this->logs[$level][] = $message; - } - - public function emergency($message, array $context = []) - { - $this->log('emergency', $message, $context); - } - - public function alert($message, array $context = []) - { - $this->log('alert', $message, $context); - } - - public function critical($message, array $context = []) - { - $this->log('critical', $message, $context); - } - - public function error($message, array $context = []) - { - $this->log('error', $message, $context); - } - - public function warning($message, array $context = []) - { - $this->log('warning', $message, $context); - } - - public function notice($message, array $context = []) - { - $this->log('notice', $message, $context); - } - - public function info($message, array $context = []) - { - $this->log('info', $message, $context); - } - - public function debug($message, array $context = []) - { - $this->log('debug', $message, $context); - } -} diff --git a/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php b/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php deleted file mode 100644 index 5d817ace..00000000 --- a/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php +++ /dev/null @@ -1,350 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\Profiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage; -use Symfony\Component\HttpKernel\Profiler\Profile; - -class FileProfilerStorageTest extends TestCase -{ - private $tmpDir; - private $storage; - - protected function setUp() - { - $this->tmpDir = sys_get_temp_dir().'/sf2_profiler_file_storage'; - if (is_dir($this->tmpDir)) { - self::cleanDir(); - } - $this->storage = new FileProfilerStorage('file:'.$this->tmpDir); - $this->storage->purge(); - } - - protected function tearDown() - { - self::cleanDir(); - } - - public function testStore() - { - for ($i = 0; $i < 10; ++$i) { - $profile = new Profile('token_'.$i); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar'); - $profile->setMethod('GET'); - $this->storage->write($profile); - } - $this->assertCount(10, $this->storage->find('127.0.0.1', 'http://foo.bar', 20, 'GET'), '->write() stores data in the storage'); - } - - public function testChildren() - { - $parentProfile = new Profile('token_parent'); - $parentProfile->setIp('127.0.0.1'); - $parentProfile->setUrl('http://foo.bar/parent'); - - $childProfile = new Profile('token_child'); - $childProfile->setIp('127.0.0.1'); - $childProfile->setUrl('http://foo.bar/child'); - - $parentProfile->addChild($childProfile); - - $this->storage->write($parentProfile); - $this->storage->write($childProfile); - - // Load them from storage - $parentProfile = $this->storage->read('token_parent'); - $childProfile = $this->storage->read('token_child'); - - // Check child has link to parent - $this->assertNotNull($childProfile->getParent()); - $this->assertEquals($parentProfile->getToken(), $childProfile->getParentToken()); - - // Check parent has child - $children = $parentProfile->getChildren(); - $this->assertCount(1, $children); - $this->assertEquals($childProfile->getToken(), $children[0]->getToken()); - } - - public function testStoreSpecialCharsInUrl() - { - // The storage accepts special characters in URLs (Even though URLs are not - // supposed to contain them) - $profile = new Profile('simple_quote'); - $profile->setUrl('http://foo.bar/\''); - $this->storage->write($profile); - $this->assertNotFalse($this->storage->read('simple_quote'), '->write() accepts single quotes in URL'); - - $profile = new Profile('double_quote'); - $profile->setUrl('http://foo.bar/"'); - $this->storage->write($profile); - $this->assertNotFalse($this->storage->read('double_quote'), '->write() accepts double quotes in URL'); - - $profile = new Profile('backslash'); - $profile->setUrl('http://foo.bar/\\'); - $this->storage->write($profile); - $this->assertNotFalse($this->storage->read('backslash'), '->write() accepts backslash in URL'); - - $profile = new Profile('comma'); - $profile->setUrl('http://foo.bar/,'); - $this->storage->write($profile); - $this->assertNotFalse($this->storage->read('comma'), '->write() accepts comma in URL'); - } - - public function testStoreDuplicateToken() - { - $profile = new Profile('token'); - $profile->setUrl('http://example.com/'); - - $this->assertTrue($this->storage->write($profile), '->write() returns true when the token is unique'); - - $profile->setUrl('http://example.net/'); - - $this->assertTrue($this->storage->write($profile), '->write() returns true when the token is already present in the storage'); - $this->assertEquals('http://example.net/', $this->storage->read('token')->getUrl(), '->write() overwrites the current profile data'); - - $this->assertCount(1, $this->storage->find('', '', 1000, ''), '->find() does not return the same profile twice'); - } - - public function testRetrieveByIp() - { - $profile = new Profile('token'); - $profile->setIp('127.0.0.1'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $this->assertCount(1, $this->storage->find('127.0.0.1', '', 10, 'GET'), '->find() retrieve a record by IP'); - $this->assertCount(0, $this->storage->find('127.0.%.1', '', 10, 'GET'), '->find() does not interpret a "%" as a wildcard in the IP'); - $this->assertCount(0, $this->storage->find('127.0._.1', '', 10, 'GET'), '->find() does not interpret a "_" as a wildcard in the IP'); - } - - public function testRetrieveByStatusCode() - { - $profile200 = new Profile('statuscode200'); - $profile200->setStatusCode(200); - $this->storage->write($profile200); - - $profile404 = new Profile('statuscode404'); - $profile404->setStatusCode(404); - $this->storage->write($profile404); - - $this->assertCount(1, $this->storage->find(null, null, 10, null, null, null, '200'), '->find() retrieve a record by Status code 200'); - $this->assertCount(1, $this->storage->find(null, null, 10, null, null, null, '404'), '->find() retrieve a record by Status code 404'); - } - - public function testRetrieveByUrl() - { - $profile = new Profile('simple_quote'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar/\''); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $profile = new Profile('double_quote'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar/"'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $profile = new Profile('backslash'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo\\bar/'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $profile = new Profile('percent'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar/%'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $profile = new Profile('underscore'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar/_'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $profile = new Profile('semicolon'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar/;'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/\'', 10, 'GET'), '->find() accepts single quotes in URLs'); - $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/"', 10, 'GET'), '->find() accepts double quotes in URLs'); - $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo\\bar/', 10, 'GET'), '->find() accepts backslash in URLs'); - $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/;', 10, 'GET'), '->find() accepts semicolon in URLs'); - $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/%', 10, 'GET'), '->find() does not interpret a "%" as a wildcard in the URL'); - $this->assertCount(1, $this->storage->find('127.0.0.1', 'http://foo.bar/_', 10, 'GET'), '->find() does not interpret a "_" as a wildcard in the URL'); - } - - public function testStoreTime() - { - $dt = new \DateTime('now'); - $start = $dt->getTimestamp(); - - for ($i = 0; $i < 3; ++$i) { - $dt->modify('+1 minute'); - $profile = new Profile('time_'.$i); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://foo.bar'); - $profile->setTime($dt->getTimestamp()); - $profile->setMethod('GET'); - $this->storage->write($profile); - } - - $records = $this->storage->find('', '', 3, 'GET', $start, time() + 3 * 60); - $this->assertCount(3, $records, '->find() returns all previously added records'); - $this->assertEquals('time_2', $records[0]['token'], '->find() returns records ordered by time in descendant order'); - $this->assertEquals('time_1', $records[1]['token'], '->find() returns records ordered by time in descendant order'); - $this->assertEquals('time_0', $records[2]['token'], '->find() returns records ordered by time in descendant order'); - - $records = $this->storage->find('', '', 3, 'GET', $start, time() + 2 * 60); - $this->assertCount(2, $records, '->find() should return only first two of the previously added records'); - } - - public function testRetrieveByEmptyUrlAndIp() - { - for ($i = 0; $i < 5; ++$i) { - $profile = new Profile('token_'.$i); - $profile->setMethod('GET'); - $this->storage->write($profile); - } - $this->assertCount(5, $this->storage->find('', '', 10, 'GET'), '->find() returns all previously added records'); - $this->storage->purge(); - } - - public function testRetrieveByMethodAndLimit() - { - foreach (['POST', 'GET'] as $method) { - for ($i = 0; $i < 5; ++$i) { - $profile = new Profile('token_'.$i.$method); - $profile->setMethod($method); - $this->storage->write($profile); - } - } - - $this->assertCount(5, $this->storage->find('', '', 5, 'POST')); - - $this->storage->purge(); - } - - public function testPurge() - { - $profile = new Profile('token1'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://example.com/'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $this->assertNotFalse($this->storage->read('token1')); - $this->assertCount(1, $this->storage->find('127.0.0.1', '', 10, 'GET')); - - $profile = new Profile('token2'); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://example.net/'); - $profile->setMethod('GET'); - $this->storage->write($profile); - - $this->assertNotFalse($this->storage->read('token2')); - $this->assertCount(2, $this->storage->find('127.0.0.1', '', 10, 'GET')); - - $this->storage->purge(); - - $this->assertEmpty($this->storage->read('token'), '->purge() removes all data stored by profiler'); - $this->assertCount(0, $this->storage->find('127.0.0.1', '', 10, 'GET'), '->purge() removes all items from index'); - } - - public function testDuplicates() - { - for ($i = 1; $i <= 5; ++$i) { - $profile = new Profile('foo'.$i); - $profile->setIp('127.0.0.1'); - $profile->setUrl('http://example.net/'); - $profile->setMethod('GET'); - - ///three duplicates - $this->storage->write($profile); - $this->storage->write($profile); - $this->storage->write($profile); - } - $this->assertCount(3, $this->storage->find('127.0.0.1', 'http://example.net/', 3, 'GET'), '->find() method returns incorrect number of entries'); - } - - public function testStatusCode() - { - $profile = new Profile('token1'); - $profile->setStatusCode(200); - $this->storage->write($profile); - - $profile = new Profile('token2'); - $profile->setStatusCode(404); - $this->storage->write($profile); - - $tokens = $this->storage->find('', '', 10, ''); - $this->assertCount(2, $tokens); - $this->assertContains((int) $tokens[0]['status_code'], [200, 404]); - $this->assertContains((int) $tokens[1]['status_code'], [200, 404]); - } - - public function testMultiRowIndexFile() - { - $iteration = 3; - for ($i = 0; $i < $iteration; ++$i) { - $profile = new Profile('token'.$i); - $profile->setIp('127.0.0.'.$i); - $profile->setUrl('http://foo.bar/'.$i); - - $this->storage->write($profile); - $this->storage->write($profile); - $this->storage->write($profile); - } - - $handle = fopen($this->tmpDir.'/index.csv', 'r'); - for ($i = 0; $i < $iteration; ++$i) { - $row = fgetcsv($handle); - $this->assertEquals('token'.$i, $row[0]); - $this->assertEquals('127.0.0.'.$i, $row[1]); - $this->assertEquals('http://foo.bar/'.$i, $row[3]); - } - $this->assertFalse(fgetcsv($handle)); - } - - public function testReadLineFromFile() - { - $r = new \ReflectionMethod($this->storage, 'readLineFromFile'); - - $r->setAccessible(true); - - $h = tmpfile(); - - fwrite($h, "line1\n\n\nline2\n"); - fseek($h, 0, \SEEK_END); - - $this->assertEquals('line2', $r->invoke($this->storage, $h)); - $this->assertEquals('line1', $r->invoke($this->storage, $h)); - } - - protected function cleanDir() - { - $flags = \FilesystemIterator::SKIP_DOTS; - $iterator = new \RecursiveDirectoryIterator($this->tmpDir, $flags); - $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); - - foreach ($iterator as $file) { - if (is_file($file)) { - unlink($file); - } - } - } -} diff --git a/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php b/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php deleted file mode 100644 index 8f12e013..00000000 --- a/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php +++ /dev/null @@ -1,105 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests\Profiler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; -use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector; -use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage; -use Symfony\Component\HttpKernel\Profiler\Profiler; - -class ProfilerTest extends TestCase -{ - private $tmp; - private $storage; - - public function testCollect() - { - $request = new Request(); - $request->query->set('foo', 'bar'); - $response = new Response('', 204); - $collector = new RequestDataCollector(); - - $profiler = new Profiler($this->storage); - $profiler->add($collector); - $profile = $profiler->collect($request, $response); - $profiler->saveProfile($profile); - - $this->assertSame(204, $profile->getStatusCode()); - $this->assertSame('GET', $profile->getMethod()); - $this->assertSame('bar', $profile->getCollector('request')->getRequestQuery()->all()['foo']->getValue()); - } - - public function testReset() - { - $collector = $this->getMockBuilder(DataCollectorInterface::class) - ->setMethods(['collect', 'getName', 'reset']) - ->getMock(); - $collector->expects($this->any())->method('getName')->willReturn('mock'); - $collector->expects($this->once())->method('reset'); - - $profiler = new Profiler($this->storage); - $profiler->add($collector); - $profiler->reset(); - } - - public function testFindWorksWithDates() - { - $profiler = new Profiler($this->storage); - - $this->assertCount(0, $profiler->find(null, null, null, null, '7th April 2014', '9th April 2014')); - } - - public function testFindWorksWithTimestamps() - { - $profiler = new Profiler($this->storage); - - $this->assertCount(0, $profiler->find(null, null, null, null, '1396828800', '1397001600')); - } - - public function testFindWorksWithInvalidDates() - { - $profiler = new Profiler($this->storage); - - $this->assertCount(0, $profiler->find(null, null, null, null, 'some string', '')); - } - - public function testFindWorksWithStatusCode() - { - $profiler = new Profiler($this->storage); - - $this->assertCount(0, $profiler->find(null, null, null, null, null, null, '204')); - } - - protected function setUp() - { - $this->tmp = tempnam(sys_get_temp_dir(), 'sf2_profiler'); - if (file_exists($this->tmp)) { - @unlink($this->tmp); - } - - $this->storage = new FileProfilerStorage('file:'.$this->tmp); - $this->storage->purge(); - } - - protected function tearDown() - { - if (null !== $this->storage) { - $this->storage->purge(); - $this->storage = null; - - @unlink($this->tmp); - } - } -} diff --git a/vendor/symfony/http-kernel/Tests/TestHttpKernel.php b/vendor/symfony/http-kernel/Tests/TestHttpKernel.php deleted file mode 100644 index 27ba2d6f..00000000 --- a/vendor/symfony/http-kernel/Tests/TestHttpKernel.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests; - -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\HttpKernel\HttpKernel; - -class TestHttpKernel extends HttpKernel implements ControllerResolverInterface, ArgumentResolverInterface -{ - public function __construct() - { - parent::__construct(new EventDispatcher(), $this, null, $this); - } - - public function getController(Request $request) - { - return [$this, 'callController']; - } - - public function getArguments(Request $request, $controller) - { - return [$request]; - } - - public function callController(Request $request) - { - return new Response('Request: '.$request->getRequestUri()); - } -} diff --git a/vendor/symfony/http-kernel/Tests/UriSignerTest.php b/vendor/symfony/http-kernel/Tests/UriSignerTest.php deleted file mode 100644 index b2eb5920..00000000 --- a/vendor/symfony/http-kernel/Tests/UriSignerTest.php +++ /dev/null @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\HttpKernel\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpKernel\UriSigner; - -class UriSignerTest extends TestCase -{ - public function testSign() - { - $signer = new UriSigner('foobar'); - - $this->assertStringContainsString('?_hash=', $signer->sign('http://example.com/foo')); - $this->assertStringContainsString('?_hash=', $signer->sign('http://example.com/foo?foo=bar')); - $this->assertStringContainsString('&foo=', $signer->sign('http://example.com/foo?foo=bar')); - } - - public function testCheck() - { - $signer = new UriSigner('foobar'); - - $this->assertFalse($signer->check('http://example.com/foo?_hash=foo')); - $this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo')); - $this->assertFalse($signer->check('http://example.com/foo?foo=bar&_hash=foo&bar=foo')); - - $this->assertTrue($signer->check($signer->sign('http://example.com/foo'))); - $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar'))); - $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&0=integer'))); - - $this->assertSame($signer->sign('http://example.com/foo?foo=bar&bar=foo'), $signer->sign('http://example.com/foo?bar=foo&foo=bar')); - } - - public function testCheckWithDifferentArgSeparator() - { - $this->iniSet('arg_separator.output', '&'); - $signer = new UriSigner('foobar'); - - $this->assertSame( - 'http://example.com/foo?_hash=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D&baz=bay&foo=bar', - $signer->sign('http://example.com/foo?foo=bar&baz=bay') - ); - $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay'))); - } - - public function testCheckWithDifferentParameter() - { - $signer = new UriSigner('foobar', 'qux'); - - $this->assertSame( - 'http://example.com/foo?baz=bay&foo=bar&qux=rIOcC%2FF3DoEGo%2FvnESjSp7uU9zA9S%2F%2BOLhxgMexoPUM%3D', - $signer->sign('http://example.com/foo?foo=bar&baz=bay') - ); - $this->assertTrue($signer->check($signer->sign('http://example.com/foo?foo=bar&baz=bay'))); - } - - public function testSignerWorksWithFragments() - { - $signer = new UriSigner('foobar'); - - $this->assertSame( - 'http://example.com/foo?_hash=EhpAUyEobiM3QTrKxoLOtQq5IsWyWedoXDPqIjzNj5o%3D&bar=foo&foo=bar#foobar', - $signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar') - ); - $this->assertTrue($signer->check($signer->sign('http://example.com/foo?bar=foo&foo=bar#foobar'))); - } -} diff --git a/vendor/symfony/http-kernel/UriSigner.php b/vendor/symfony/http-kernel/UriSigner.php index 3927f101..e4f988b2 100644 --- a/vendor/symfony/http-kernel/UriSigner.php +++ b/vendor/symfony/http-kernel/UriSigner.php @@ -25,7 +25,7 @@ class UriSigner * @param string $secret A secret * @param string $parameter Query string parameter to use */ - public function __construct($secret, $parameter = '_hash') + public function __construct(string $secret, string $parameter = '_hash') { $this->secret = $secret; $this->parameter = $parameter; @@ -82,23 +82,23 @@ public function check($uri) return hash_equals($this->computeHash($this->buildUrl($url, $params)), $hash); } - private function computeHash($uri) + private function computeHash(string $uri): string { return base64_encode(hash_hmac('sha256', $uri, $this->secret, true)); } - private function buildUrl(array $url, array $params = []) + private function buildUrl(array $url, array $params = []): string { ksort($params, \SORT_STRING); $url['query'] = http_build_query($params, '', '&'); $scheme = isset($url['scheme']) ? $url['scheme'].'://' : ''; - $host = isset($url['host']) ? $url['host'] : ''; + $host = $url['host'] ?? ''; $port = isset($url['port']) ? ':'.$url['port'] : ''; - $user = isset($url['user']) ? $url['user'] : ''; + $user = $url['user'] ?? ''; $pass = isset($url['pass']) ? ':'.$url['pass'] : ''; $pass = ($user || $pass) ? "$pass@" : ''; - $path = isset($url['path']) ? $url['path'] : ''; + $path = $url['path'] ?? ''; $query = isset($url['query']) && $url['query'] ? '?'.$url['query'] : ''; $fragment = isset($url['fragment']) ? '#'.$url['fragment'] : ''; diff --git a/vendor/symfony/http-kernel/composer.json b/vendor/symfony/http-kernel/composer.json index 06a67607..c2758e45 100644 --- a/vendor/symfony/http-kernel/composer.json +++ b/vendor/symfony/http-kernel/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/http-kernel", "type": "library", - "description": "Symfony HttpKernel Component", + "description": "Provides a structured process for converting a Request into a Response", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,48 +16,50 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/debug": "^3.3.3|~4.0", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-php56": "~1.8", - "psr/log": "~1.0" + "php": ">=7.1.3", + "symfony/error-handler": "^4.4", + "symfony/event-dispatcher": "^4.4", + "symfony/http-client-contracts": "^1.1|^2", + "symfony/http-foundation": "^4.4.30|^5.3.7", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "psr/log": "^1|^2" }, "require-dev": { - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", - "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0", - "psr/cache": "~1.0" + "symfony/browser-kit": "^4.3|^5.0", + "symfony/config": "^3.4|^4.0|^5.0", + "symfony/console": "^3.4|^4.0", + "symfony/css-selector": "^3.4|^4.0|^5.0", + "symfony/dependency-injection": "^4.3|^5.0", + "symfony/dom-crawler": "^3.4|^4.0|^5.0", + "symfony/expression-language": "^3.4|^4.0|^5.0", + "symfony/finder": "^3.4|^4.0|^5.0", + "symfony/process": "^3.4|^4.0|^5.0", + "symfony/routing": "^3.4|^4.0|^5.0", + "symfony/stopwatch": "^3.4|^4.0|^5.0", + "symfony/templating": "^3.4|^4.0|^5.0", + "symfony/translation": "^4.2|^5.0", + "symfony/translation-contracts": "^1.1|^2", + "psr/cache": "^1.0|^2.0|^3.0", + "twig/twig": "^1.43|^2.13|^3.0.4" }, "provide": { - "psr/log-implementation": "1.0" + "psr/log-implementation": "1.0|2.0" }, "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", - "twig/twig": "<1.34|<2.4,>=2" + "symfony/browser-kit": "<4.3", + "symfony/config": "<3.4", + "symfony/console": ">=5", + "symfony/dependency-injection": "<4.3", + "symfony/translation": "<4.2", + "twig/twig": "<1.43|<2.13,>=2" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", - "symfony/dependency-injection": "", - "symfony/finder": "", - "symfony/var-dumper": "" + "symfony/dependency-injection": "" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpKernel\\": "" }, diff --git a/vendor/symfony/http-kernel/phpunit.xml.dist b/vendor/symfony/http-kernel/phpunit.xml.dist deleted file mode 100644 index 3fc07707..00000000 --- a/vendor/symfony/http-kernel/phpunit.xml.dist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Tests - ./vendor - - - - - - - - - Symfony\Component\HttpFoundation - - - - - diff --git a/vendor/symfony/monolog-bridge/.gitignore b/vendor/symfony/monolog-bridge/.gitignore deleted file mode 100644 index c49a5d8d..00000000 --- a/vendor/symfony/monolog-bridge/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff --git a/vendor/symfony/monolog-bridge/CHANGELOG.md b/vendor/symfony/monolog-bridge/CHANGELOG.md index f91d4c5d..1a7e1161 100644 --- a/vendor/symfony/monolog-bridge/CHANGELOG.md +++ b/vendor/symfony/monolog-bridge/CHANGELOG.md @@ -1,6 +1,56 @@ CHANGELOG ========= +5.2.0 +----- + + * The `$actionLevel` constructor argument of `Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy` has been deprecated and replaced by the `$inner` one which expects an ActivationStrategyInterface to decorate instead. `Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy` will become final in 6.0. + * The `$actionLevel` constructor argument of `Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy` has been deprecated and replaced by the `$inner` one which expects an ActivationStrategyInterface to decorate instead. `Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy` will become final in 6.0 + +5.1.0 +----- + + * Added `MailerHandler` + +5.0.0 +----- + + * The methods `DebugProcessor::getLogs()`, `DebugProcessor::countErrors()`, `Logger::getLogs()` and `Logger::countErrors()` have a new `$request` argument. + * Added support for Monolog 2. + +4.4.0 +----- + + * The `RouteProcessor` class has been made final + * Added `ElasticsearchLogstashHandler` + * Added the `ServerLogCommand`. Backport from the deprecated WebServerBundle + +4.3.0 +----- + + * added `ConsoleCommandProcessor`: monolog processor that adds command name and arguments + * added `RouteProcessor`: monolog processor that adds route name, controller::action and route params + +4.2.0 +----- + + * The methods `DebugProcessor::getLogs()`, `DebugProcessor::countErrors()`, `Logger::getLogs()` + and `Logger::countErrors()` will have a new `$request` argument in version 5.0, not defining + it is deprecated + +4.1.0 +----- + + * `WebProcessor` now implements `EventSubscriberInterface` in order to be easily autoconfigured + +4.0.0 +----- + + * the `$format`, `$dateFormat`, `$allowInlineLineBreaks`, and `$ignoreEmptyContextAndExtra` + constructor arguments of the `ConsoleFormatter` class have been removed, use + `$options` instead + * the `DebugHandler` class has been removed + 3.3.0 ----- diff --git a/vendor/symfony/monolog-bridge/Command/ServerLogCommand.php b/vendor/symfony/monolog-bridge/Command/ServerLogCommand.php new file mode 100644 index 00000000..0e5fddc2 --- /dev/null +++ b/vendor/symfony/monolog-bridge/Command/ServerLogCommand.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Command; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Logger; +use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter; +use Symfony\Bridge\Monolog\Handler\ConsoleHandler; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; + +/** + * @author Grégoire Pineau + */ +class ServerLogCommand extends Command +{ + private const BG_COLOR = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'white', 'yellow']; + + private $el; + private $handler; + + protected static $defaultName = 'server:log'; + + public function isEnabled() + { + if (!class_exists(ConsoleFormatter::class)) { + return false; + } + + // based on a symfony/symfony package, it crashes due a missing FormatterInterface from monolog/monolog + if (!interface_exists(FormatterInterface::class)) { + return false; + } + + return parent::isEnabled(); + } + + protected function configure() + { + if (!class_exists(ConsoleFormatter::class)) { + return; + } + + $this + ->addOption('host', null, InputOption::VALUE_REQUIRED, 'The server host', '0.0.0.0:9911') + ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The line format', ConsoleFormatter::SIMPLE_FORMAT) + ->addOption('date-format', null, InputOption::VALUE_REQUIRED, 'The date format', ConsoleFormatter::SIMPLE_DATE) + ->addOption('filter', null, InputOption::VALUE_REQUIRED, 'An expression to filter log. Example: "level > 200 or channel in [\'app\', \'doctrine\']"') + ->setDescription('Start a log server that displays logs in real time') + ->setHelp(<<<'EOF' +%command.name% starts a log server to display in real time the log +messages generated by your application: + + php %command.full_name% + +To filter the log messages using any ExpressionLanguage compatible expression, use the --filter option: + +php %command.full_name% --filter="level > 200 or channel in ['app', 'doctrine']" +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $filter = $input->getOption('filter'); + if ($filter) { + if (!class_exists(ExpressionLanguage::class)) { + throw new LogicException('Package "symfony/expression-language" is required to use the "filter" option.'); + } + $this->el = new ExpressionLanguage(); + } + + $this->handler = new ConsoleHandler($output, true, [ + OutputInterface::VERBOSITY_NORMAL => Logger::DEBUG, + ]); + + $this->handler->setFormatter(new ConsoleFormatter([ + 'format' => str_replace('\n', "\n", $input->getOption('format')), + 'date_format' => $input->getOption('date-format'), + 'colors' => $output->isDecorated(), + 'multiline' => OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity(), + ])); + + if (!str_contains($host = $input->getOption('host'), '://')) { + $host = 'tcp://'.$host; + } + + if (!$socket = stream_socket_server($host, $errno, $errstr)) { + throw new RuntimeException(sprintf('Server start failed on "%s": ', $host).$errstr.' '.$errno); + } + + foreach ($this->getLogs($socket) as $clientId => $message) { + $record = unserialize(base64_decode($message)); + + // Impossible to decode the message, give up. + if (false === $record) { + continue; + } + + if ($filter && !$this->el->evaluate($filter, $record)) { + continue; + } + + $this->displayLog($output, $clientId, $record); + } + + return 0; + } + + private function getLogs($socket): iterable + { + $sockets = [(int) $socket => $socket]; + $write = []; + + while (true) { + $read = $sockets; + stream_select($read, $write, $write, null); + + foreach ($read as $stream) { + if ($socket === $stream) { + $stream = stream_socket_accept($socket); + $sockets[(int) $stream] = $stream; + } elseif (feof($stream)) { + unset($sockets[(int) $stream]); + fclose($stream); + } else { + yield (int) $stream => fgets($stream); + } + } + } + } + + private function displayLog(OutputInterface $output, int $clientId, array $record) + { + if (isset($record['log_id'])) { + $clientId = unpack('H*', $record['log_id'])[1]; + } + $logBlock = sprintf(' ', self::BG_COLOR[$clientId % 8]); + $output->write($logBlock); + + $this->handler->handle($record); + } +} diff --git a/vendor/symfony/monolog-bridge/Formatter/ConsoleFormatter.php b/vendor/symfony/monolog-bridge/Formatter/ConsoleFormatter.php index 35b1c99e..4b87c264 100644 --- a/vendor/symfony/monolog-bridge/Formatter/ConsoleFormatter.php +++ b/vendor/symfony/monolog-bridge/Formatter/ConsoleFormatter.php @@ -27,10 +27,10 @@ */ class ConsoleFormatter implements FormatterInterface { - const SIMPLE_FORMAT = "%datetime% %start_tag%%level_name%%end_tag% [%channel%] %message%%context%%extra%\n"; - const SIMPLE_DATE = 'H:i:s'; + public const SIMPLE_FORMAT = "%datetime% %start_tag%%level_name%%end_tag% [%channel%] %message%%context%%extra%\n"; + public const SIMPLE_DATE = 'H:i:s'; - private static $levelColorMap = [ + private const LEVEL_COLOR_MAP = [ Logger::DEBUG => 'fg=white', Logger::INFO => 'fg=green', Logger::NOTICE => 'fg=blue', @@ -53,32 +53,14 @@ class ConsoleFormatter implements FormatterInterface * * colors: If true, the log string contains ANSI code to add color; * * multiline: If false, "context" and "extra" are dumped on one line. */ - public function __construct($options = []) + public function __construct(array $options = []) { - // BC Layer - if (!\is_array($options)) { - @trigger_error(sprintf('The constructor arguments $format, $dateFormat, $allowInlineLineBreaks, $ignoreEmptyContextAndExtra of "%s" are deprecated since Symfony 3.3 and will be removed in 4.0. Use $options instead.', self::class), \E_USER_DEPRECATED); - $args = \func_get_args(); - $options = []; - if (isset($args[0])) { - $options['format'] = $args[0]; - } - if (isset($args[1])) { - $options['date_format'] = $args[1]; - } - if (isset($args[2])) { - $options['multiline'] = $args[2]; - } - if (isset($args[3])) { - $options['ignore_empty_context_and_extra'] = $args[3]; - } - } - $this->options = array_replace([ 'format' => self::SIMPLE_FORMAT, 'date_format' => self::SIMPLE_DATE, 'colors' => true, 'multiline' => false, + 'level_name_format' => '%-9s', 'ignore_empty_context_and_extra' => true, ], $options); @@ -88,7 +70,7 @@ public function __construct($options = []) '*' => [$this, 'castObject'], ]); - $this->outputBuffer = fopen('php://memory', 'r+b'); + $this->outputBuffer = fopen('php://memory', 'r+'); if ($this->options['multiline']) { $output = $this->outputBuffer; } else { @@ -101,6 +83,8 @@ public function __construct($options = []) /** * {@inheritdoc} + * + * @return mixed */ public function formatBatch(array $records) { @@ -113,13 +97,13 @@ public function formatBatch(array $records) /** * {@inheritdoc} + * + * @return mixed */ public function format(array $record) { $record = $this->replacePlaceHolder($record); - $levelColor = self::$levelColorMap[$record['level']]; - if (!$this->options['ignore_empty_context_and_extra'] || !empty($record['context'])) { $context = ($this->options['multiline'] ? "\n" : ' ').$this->dumpData($record['context']); } else { @@ -136,8 +120,8 @@ public function format(array $record) '%datetime%' => $record['datetime'] instanceof \DateTimeInterface ? $record['datetime']->format($this->options['date_format']) : $record['datetime'], - '%start_tag%' => sprintf('<%s>', $levelColor), - '%level_name%' => sprintf('%-9s', $record['level_name']), + '%start_tag%' => sprintf('<%s>', self::LEVEL_COLOR_MAP[$record['level']]), + '%level_name%' => sprintf($this->options['level_name_format'], $record['level_name']), '%end_tag%' => '', '%channel%' => $record['channel'], '%message%' => $this->replacePlaceHolder($record)['message'], @@ -151,7 +135,7 @@ public function format(array $record) /** * @internal */ - public function echoLine($line, $depth, $indentPad) + public function echoLine(string $line, int $depth, string $indentPad) { if (-1 !== $depth) { fwrite($this->outputBuffer, $line); @@ -161,7 +145,7 @@ public function echoLine($line, $depth, $indentPad) /** * @internal */ - public function castObject($v, array $a, Stub $s, $isNested) + public function castObject($v, array $a, Stub $s, bool $isNested): array { if ($this->options['multiline']) { return $a; @@ -175,11 +159,11 @@ public function castObject($v, array $a, Stub $s, $isNested) return $a; } - private function replacePlaceHolder(array $record) + private function replacePlaceHolder(array $record): array { $message = $record['message']; - if (false === strpos($message, '{')) { + if (!str_contains($message, '{')) { return $record; } @@ -198,7 +182,7 @@ private function replacePlaceHolder(array $record) return $record; } - private function dumpData($data, $colors = null) + private function dumpData($data, bool $colors = null): string { if (null === $this->dumper) { return ''; diff --git a/vendor/symfony/monolog-bridge/Formatter/VarDumperFormatter.php b/vendor/symfony/monolog-bridge/Formatter/VarDumperFormatter.php index e96b510a..54988766 100644 --- a/vendor/symfony/monolog-bridge/Formatter/VarDumperFormatter.php +++ b/vendor/symfony/monolog-bridge/Formatter/VarDumperFormatter.php @@ -23,9 +23,14 @@ class VarDumperFormatter implements FormatterInterface public function __construct(VarCloner $cloner = null) { - $this->cloner = $cloner ?: new VarCloner(); + $this->cloner = $cloner ?? new VarCloner(); } + /** + * {@inheritdoc} + * + * @return mixed + */ public function format(array $record) { $record['context'] = $this->cloner->cloneVar($record['context']); @@ -34,6 +39,11 @@ public function format(array $record) return $record; } + /** + * {@inheritdoc} + * + * @return mixed + */ public function formatBatch(array $records) { foreach ($records as $k => $record) { diff --git a/vendor/symfony/monolog-bridge/Handler/ChromePhpHandler.php b/vendor/symfony/monolog-bridge/Handler/ChromePhpHandler.php index c8e21b2f..e7049c4b 100644 --- a/vendor/symfony/monolog-bridge/Handler/ChromePhpHandler.php +++ b/vendor/symfony/monolog-bridge/Handler/ChromePhpHandler.php @@ -13,12 +13,14 @@ use Monolog\Handler\ChromePHPHandler as BaseChromePhpHandler; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; /** * ChromePhpHandler. * * @author Christophe Coevoet + * + * @final */ class ChromePhpHandler extends BaseChromePhpHandler { @@ -32,7 +34,7 @@ class ChromePhpHandler extends BaseChromePhpHandler /** * Adds the headers to the response once it's created. */ - public function onKernelResponse(FilterResponseEvent $event) + public function onKernelResponse(ResponseEvent $event) { if (!$event->isMasterRequest()) { return; @@ -55,7 +57,7 @@ public function onKernelResponse(FilterResponseEvent $event) /** * {@inheritdoc} */ - protected function sendHeader($header, $content) + protected function sendHeader($header, $content): void { if (!self::$sendHeaders) { return; @@ -71,7 +73,7 @@ protected function sendHeader($header, $content) /** * Override default behavior since we check it in onKernelResponse. */ - protected function headersAccepted() + protected function headersAccepted(): bool { return true; } diff --git a/vendor/symfony/monolog-bridge/Handler/ConsoleHandler.php b/vendor/symfony/monolog-bridge/Handler/ConsoleHandler.php index 5fc3051f..17d3c2f2 100644 --- a/vendor/symfony/monolog-bridge/Handler/ConsoleHandler.php +++ b/vendor/symfony/monolog-bridge/Handler/ConsoleHandler.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Monolog\Handler; +use Monolog\Formatter\FormatterInterface; use Monolog\Formatter\LineFormatter; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Logger; @@ -50,6 +51,7 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe OutputInterface::VERBOSITY_VERY_VERBOSE => Logger::INFO, OutputInterface::VERBOSITY_DEBUG => Logger::DEBUG, ]; + private $consoleFormatterOptions; /** * @param OutputInterface|null $output The console output to use (the handler remains disabled when passing null @@ -58,7 +60,7 @@ class ConsoleHandler extends AbstractProcessingHandler implements EventSubscribe * @param array $verbosityLevelMap Array that maps the OutputInterface verbosity to a minimum logging * level (leave empty to use the default mapping) */ - public function __construct(OutputInterface $output = null, $bubble = true, array $verbosityLevelMap = []) + public function __construct(OutputInterface $output = null, bool $bubble = true, array $verbosityLevelMap = [], array $consoleFormatterOptions = []) { parent::__construct(Logger::DEBUG, $bubble); $this->output = $output; @@ -66,12 +68,14 @@ public function __construct(OutputInterface $output = null, $bubble = true, arra if ($verbosityLevelMap) { $this->verbosityLevelMap = $verbosityLevelMap; } + + $this->consoleFormatterOptions = $consoleFormatterOptions; } /** * {@inheritdoc} */ - public function isHandling(array $record) + public function isHandling(array $record): bool { return $this->updateLevel() && parent::isHandling($record); } @@ -79,7 +83,7 @@ public function isHandling(array $record) /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { // we have to update the logging level each time because the verbosity of the // console output might have changed in the meantime (it is not immutable) @@ -97,7 +101,7 @@ public function setOutput(OutputInterface $output) /** * Disables the output. */ - public function close() + public function close(): void { $this->output = null; @@ -140,7 +144,7 @@ public static function getSubscribedEvents() /** * {@inheritdoc} */ - protected function write(array $record) + protected function write(array $record): void { // at this point we've determined for sure that we want to output the record, so use the output's own verbosity $this->output->write((string) $record['formatted'], false, $this->output->getVerbosity()); @@ -149,19 +153,19 @@ protected function write(array $record) /** * {@inheritdoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { if (!class_exists(CliDumper::class)) { return new LineFormatter(); } if (!$this->output) { - return new ConsoleFormatter(); + return new ConsoleFormatter($this->consoleFormatterOptions); } - return new ConsoleFormatter([ + return new ConsoleFormatter(array_replace([ 'colors' => $this->output->isDecorated(), 'multiline' => OutputInterface::VERBOSITY_DEBUG <= $this->output->getVerbosity(), - ]); + ], $this->consoleFormatterOptions)); } /** @@ -169,7 +173,7 @@ protected function getDefaultFormatter() * * @return bool Whether the handler is enabled and verbosity is not set to quiet */ - private function updateLevel() + private function updateLevel(): bool { if (null === $this->output) { return false; diff --git a/vendor/symfony/monolog-bridge/Handler/DebugHandler.php b/vendor/symfony/monolog-bridge/Handler/DebugHandler.php deleted file mode 100644 index d5f8b367..00000000 --- a/vendor/symfony/monolog-bridge/Handler/DebugHandler.php +++ /dev/null @@ -1,64 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Handler; - -@trigger_error('The '.__NAMESPACE__.'\DebugHandler class is deprecated since Symfony 3.2 and will be removed in 4.0. Use Symfony\Bridge\Monolog\Processor\DebugProcessor instead.', \E_USER_DEPRECATED); - -use Monolog\Handler\TestHandler; -use Monolog\Logger; -use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; - -/** - * DebugLogger. - * - * @author Jordi Boggiano - * - * @deprecated since version 3.2, to be removed in 4.0. Use Symfony\Bridge\Monolog\Processor\DebugProcessor instead. - */ -class DebugHandler extends TestHandler implements DebugLoggerInterface -{ - /** - * {@inheritdoc} - */ - public function getLogs() - { - $records = []; - foreach ($this->records as $record) { - $records[] = [ - 'timestamp' => $record['datetime']->getTimestamp(), - 'message' => $record['message'], - 'priority' => $record['level'], - 'priorityName' => $record['level_name'], - 'context' => $record['context'], - 'channel' => isset($record['channel']) ? $record['channel'] : '', - ]; - } - - return $records; - } - - /** - * {@inheritdoc} - */ - public function countErrors() - { - $cnt = 0; - $levels = [Logger::ERROR, Logger::CRITICAL, Logger::ALERT, Logger::EMERGENCY]; - foreach ($levels as $level) { - if (isset($this->recordsByLevel[$level])) { - $cnt += \count($this->recordsByLevel[$level]); - } - } - - return $cnt; - } -} diff --git a/vendor/symfony/monolog-bridge/Handler/ElasticsearchLogstashHandler.php b/vendor/symfony/monolog-bridge/Handler/ElasticsearchLogstashHandler.php new file mode 100644 index 00000000..a59825f6 --- /dev/null +++ b/vendor/symfony/monolog-bridge/Handler/ElasticsearchLogstashHandler.php @@ -0,0 +1,169 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\LogstashFormatter; +use Monolog\Handler\AbstractHandler; +use Monolog\Handler\FormattableHandlerTrait; +use Monolog\Handler\ProcessableHandlerTrait; +use Monolog\Logger; +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Contracts\HttpClient\Exception\ExceptionInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * Push logs directly to Elasticsearch and format them according to Logstash specification. + * + * This handler dials directly with the HTTP interface of Elasticsearch. This + * means it will slow down your application if Elasticsearch takes times to + * answer. Even if all HTTP calls are done asynchronously. + * + * In a development environment, it's fine to keep the default configuration: + * for each log, an HTTP request will be made to push the log to Elasticsearch. + * + * In a production environment, it's highly recommended to wrap this handler + * in a handler with buffering capabilities (like the FingersCrossedHandler, or + * BufferHandler) in order to call Elasticsearch only once with a bulk push. For + * even better performance and fault tolerance, a proper ELK (https://www.elastic.co/what-is/elk-stack) + * stack is recommended. + * + * @author Grégoire Pineau + */ +class ElasticsearchLogstashHandler extends AbstractHandler +{ + use FormattableHandlerTrait; + use ProcessableHandlerTrait; + + private $endpoint; + private $index; + private $client; + private $responses; + + /** + * @param string|int $level The minimum logging level at which this handler will be triggered + */ + public function __construct(string $endpoint = 'http://127.0.0.1:9200', string $index = 'monolog', HttpClientInterface $client = null, $level = Logger::DEBUG, bool $bubble = true) + { + if (!interface_exists(HttpClientInterface::class)) { + throw new \LogicException(sprintf('The "%s" handler needs an HTTP client. Try running "composer require symfony/http-client".', __CLASS__)); + } + + parent::__construct($level, $bubble); + $this->endpoint = $endpoint; + $this->index = $index; + $this->client = $client ?: HttpClient::create(['timeout' => 1]); + $this->responses = new \SplObjectStorage(); + } + + public function handle(array $record): bool + { + if (!$this->isHandling($record)) { + return false; + } + + $this->sendToElasticsearch([$record]); + + return !$this->bubble; + } + + public function handleBatch(array $records): void + { + $records = array_filter($records, [$this, 'isHandling']); + + if ($records) { + $this->sendToElasticsearch($records); + } + } + + protected function getDefaultFormatter(): FormatterInterface + { + // Monolog 1.X + if (\defined(LogstashFormatter::class.'::V1')) { + return new LogstashFormatter('application', null, null, 'ctxt_', LogstashFormatter::V1); + } + + // Monolog 2.X + return new LogstashFormatter('application'); + } + + private function sendToElasticsearch(array $records) + { + $formatter = $this->getFormatter(); + + $body = ''; + foreach ($records as $record) { + foreach ($this->processors as $processor) { + $record = $processor($record); + } + + $body .= json_encode([ + 'index' => [ + '_index' => $this->index, + '_type' => '_doc', + ], + ]); + $body .= "\n"; + $body .= $formatter->format($record); + $body .= "\n"; + } + + $response = $this->client->request('POST', $this->endpoint.'/_bulk', [ + 'body' => $body, + 'headers' => [ + 'Content-Type' => 'application/json', + ], + ]); + + $this->responses->attach($response); + + $this->wait(false); + } + + /** + * @return array + */ + public function __sleep() + { + throw new \BadMethodCallException('Cannot serialize '.__CLASS__); + } + + public function __wakeup() + { + throw new \BadMethodCallException('Cannot unserialize '.__CLASS__); + } + + public function __destruct() + { + $this->wait(true); + } + + private function wait(bool $blocking) + { + foreach ($this->client->stream($this->responses, $blocking ? null : 0.0) as $response => $chunk) { + try { + if ($chunk->isTimeout() && !$blocking) { + continue; + } + if (!$chunk->isFirst() && !$chunk->isLast()) { + continue; + } + if ($chunk->isLast()) { + $this->responses->detach($response); + } + } catch (ExceptionInterface $e) { + $this->responses->detach($response); + error_log(sprintf("Could not push logs to Elasticsearch:\n%s", (string) $e)); + } + } + } +} diff --git a/vendor/symfony/monolog-bridge/Handler/FingersCrossed/HttpCodeActivationStrategy.php b/vendor/symfony/monolog-bridge/Handler/FingersCrossed/HttpCodeActivationStrategy.php new file mode 100644 index 00000000..e87b8677 --- /dev/null +++ b/vendor/symfony/monolog-bridge/Handler/FingersCrossed/HttpCodeActivationStrategy.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler\FingersCrossed; + +use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; +use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\Exception\HttpException; + +/** + * Activation strategy that ignores certain HTTP codes. + * + * @author Shaun Simmons + * @author Pierrick Vignand + * + * @final + */ +class HttpCodeActivationStrategy extends ErrorLevelActivationStrategy implements ActivationStrategyInterface +{ + private $inner; + private $exclusions; + private $requestStack; + + /** + * @param array $exclusions each exclusion must have a "code" and "urls" keys + * @param ActivationStrategyInterface|int|string $inner an ActivationStrategyInterface to decorate + */ + public function __construct(RequestStack $requestStack, array $exclusions, $inner) + { + if (!$inner instanceof ActivationStrategyInterface) { + trigger_deprecation('symfony/monolog-bridge', '5.2', 'Passing an actionLevel (int|string) as constructor\'s 3rd argument of "%s" is deprecated, "%s" expected.', __CLASS__, ActivationStrategyInterface::class); + + $actionLevel = $inner; + $inner = new ErrorLevelActivationStrategy($actionLevel); + } + + foreach ($exclusions as $exclusion) { + if (!\array_key_exists('code', $exclusion)) { + throw new \LogicException('An exclusion must have a "code" key.'); + } + if (!\array_key_exists('urls', $exclusion)) { + throw new \LogicException('An exclusion must have a "urls" key.'); + } + } + + $this->inner = $inner; + $this->requestStack = $requestStack; + $this->exclusions = $exclusions; + } + + public function isHandlerActivated(array $record): bool + { + $isActivated = $this->inner->isHandlerActivated($record); + + if ( + $isActivated + && isset($record['context']['exception']) + && $record['context']['exception'] instanceof HttpException + && ($request = $this->requestStack->getMasterRequest()) + ) { + foreach ($this->exclusions as $exclusion) { + if ($record['context']['exception']->getStatusCode() !== $exclusion['code']) { + continue; + } + + if (\count($exclusion['urls'])) { + return !preg_match('{('.implode('|', $exclusion['urls']).')}i', $request->getPathInfo()); + } + + return false; + } + } + + return $isActivated; + } +} diff --git a/vendor/symfony/monolog-bridge/Handler/FingersCrossed/NotFoundActivationStrategy.php b/vendor/symfony/monolog-bridge/Handler/FingersCrossed/NotFoundActivationStrategy.php index e5ccf1af..a9806d7e 100644 --- a/vendor/symfony/monolog-bridge/Handler/FingersCrossed/NotFoundActivationStrategy.php +++ b/vendor/symfony/monolog-bridge/Handler/FingersCrossed/NotFoundActivationStrategy.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Monolog\Handler\FingersCrossed; +use Monolog\Handler\FingersCrossed\ActivationStrategyInterface; use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\HttpException; @@ -20,23 +21,36 @@ * * @author Jordi Boggiano * @author Fabien Potencier + * @author Pierrick Vignand + * + * @final */ -class NotFoundActivationStrategy extends ErrorLevelActivationStrategy +class NotFoundActivationStrategy extends ErrorLevelActivationStrategy implements ActivationStrategyInterface { + private $inner; private $exclude; private $requestStack; - public function __construct(RequestStack $requestStack, array $excludedUrls, $actionLevel) + /** + * @param ActivationStrategyInterface|int|string $inner an ActivationStrategyInterface to decorate + */ + public function __construct(RequestStack $requestStack, array $excludedUrls, $inner) { - parent::__construct($actionLevel); + if (!$inner instanceof ActivationStrategyInterface) { + trigger_deprecation('symfony/monolog-bridge', '5.2', 'Passing an actionLevel (int|string) as constructor\'s 3rd argument of "%s" is deprecated, "%s" expected.', __CLASS__, ActivationStrategyInterface::class); + + $actionLevel = $inner; + $inner = new ErrorLevelActivationStrategy($actionLevel); + } + $this->inner = $inner; $this->requestStack = $requestStack; $this->exclude = '{('.implode('|', $excludedUrls).')}i'; } - public function isHandlerActivated(array $record) + public function isHandlerActivated(array $record): bool { - $isActivated = parent::isHandlerActivated($record); + $isActivated = $this->inner->isHandlerActivated($record); if ( $isActivated diff --git a/vendor/symfony/monolog-bridge/Handler/FirePHPHandler.php b/vendor/symfony/monolog-bridge/Handler/FirePHPHandler.php index 9c3ec5f9..0a9a6965 100644 --- a/vendor/symfony/monolog-bridge/Handler/FirePHPHandler.php +++ b/vendor/symfony/monolog-bridge/Handler/FirePHPHandler.php @@ -13,12 +13,14 @@ use Monolog\Handler\FirePHPHandler as BaseFirePHPHandler; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; /** * FirePHPHandler. * * @author Jordi Boggiano + * + * @final */ class FirePHPHandler extends BaseFirePHPHandler { @@ -32,7 +34,7 @@ class FirePHPHandler extends BaseFirePHPHandler /** * Adds the headers to the response once it's created. */ - public function onKernelResponse(FilterResponseEvent $event) + public function onKernelResponse(ResponseEvent $event) { if (!$event->isMasterRequest()) { return; @@ -57,7 +59,7 @@ public function onKernelResponse(FilterResponseEvent $event) /** * {@inheritdoc} */ - protected function sendHeader($header, $content) + protected function sendHeader($header, $content): void { if (!self::$sendHeaders) { return; @@ -73,7 +75,7 @@ protected function sendHeader($header, $content) /** * Override default behavior since we check the user agent in onKernelResponse. */ - protected function headersAccepted() + protected function headersAccepted(): bool { return true; } diff --git a/vendor/symfony/monolog-bridge/Handler/MailerHandler.php b/vendor/symfony/monolog-bridge/Handler/MailerHandler.php new file mode 100644 index 00000000..cf59f45e --- /dev/null +++ b/vendor/symfony/monolog-bridge/Handler/MailerHandler.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Formatter\HtmlFormatter; +use Monolog\Formatter\LineFormatter; +use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Logger; +use Symfony\Component\Mailer\MailerInterface; +use Symfony\Component\Mime\Email; + +/** + * @author Alexander Borisov + */ +class MailerHandler extends AbstractProcessingHandler +{ + private $mailer; + + private $messageTemplate; + + /** + * @param callable|Email $messageTemplate + * @param string|int $level The minimum logging level at which this handler will be triggered + */ + public function __construct(MailerInterface $mailer, $messageTemplate, $level = Logger::DEBUG, bool $bubble = true) + { + parent::__construct($level, $bubble); + + $this->mailer = $mailer; + $this->messageTemplate = $messageTemplate; + } + + /** + * {@inheritdoc} + */ + public function handleBatch(array $records): void + { + $messages = []; + + foreach ($records as $record) { + if ($record['level'] < $this->level) { + continue; + } + $messages[] = $this->processRecord($record); + } + + if (!empty($messages)) { + $this->send((string) $this->getFormatter()->formatBatch($messages), $messages); + } + } + + /** + * {@inheritdoc} + */ + protected function write(array $record): void + { + $this->send((string) $record['formatted'], [$record]); + } + + /** + * Send a mail with the given content. + * + * @param string $content formatted email body to be sent + * @param array $records the array of log records that formed this content + */ + protected function send(string $content, array $records) + { + $this->mailer->send($this->buildMessage($content, $records)); + } + + /** + * Gets the formatter for the Message subject. + * + * @param string $format The format of the subject + */ + protected function getSubjectFormatter(string $format): FormatterInterface + { + return new LineFormatter($format); + } + + /** + * Creates instance of Message to be sent. + * + * @param string $content formatted email body to be sent + * @param array $records Log records that formed the content + */ + protected function buildMessage(string $content, array $records): Email + { + $message = null; + if ($this->messageTemplate instanceof Email) { + $message = clone $this->messageTemplate; + } elseif (\is_callable($this->messageTemplate)) { + $message = \call_user_func($this->messageTemplate, $content, $records); + if (!$message instanceof Email) { + throw new \InvalidArgumentException(sprintf('Could not resolve message from a callable. Instance of "%s" is expected.', Email::class)); + } + } else { + throw new \InvalidArgumentException('Could not resolve message as instance of Email or a callable returning it.'); + } + + if ($records) { + $subjectFormatter = $this->getSubjectFormatter($message->getSubject()); + $message->subject($subjectFormatter->format($this->getHighestRecord($records))); + } + + if ($this->getFormatter() instanceof HtmlFormatter) { + if ($message->getHtmlCharset()) { + $message->html($content, $message->getHtmlCharset()); + } else { + $message->html($content); + } + } else { + if ($message->getTextCharset()) { + $message->text($content, $message->getTextCharset()); + } else { + $message->text($content); + } + } + + return $message; + } + + protected function getHighestRecord(array $records): array + { + $highestRecord = null; + foreach ($records as $record) { + if (null === $highestRecord || $highestRecord['level'] < $record['level']) { + $highestRecord = $record; + } + } + + return $highestRecord; + } +} diff --git a/vendor/symfony/monolog-bridge/Handler/NotifierHandler.php b/vendor/symfony/monolog-bridge/Handler/NotifierHandler.php new file mode 100644 index 00000000..be60c7dc --- /dev/null +++ b/vendor/symfony/monolog-bridge/Handler/NotifierHandler.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Handler; + +use Monolog\Handler\AbstractHandler; +use Monolog\Logger; +use Symfony\Component\Notifier\Notification\Notification; +use Symfony\Component\Notifier\Notifier; +use Symfony\Component\Notifier\NotifierInterface; + +/** + * Uses Notifier as a log handler. + * + * @author Fabien Potencier + */ +class NotifierHandler extends AbstractHandler +{ + private $notifier; + + /** + * @param string|int $level The minimum logging level at which this handler will be triggered + */ + public function __construct(NotifierInterface $notifier, $level = Logger::ERROR, bool $bubble = true) + { + $this->notifier = $notifier; + + parent::__construct(Logger::toMonologLevel($level) < Logger::ERROR ? Logger::ERROR : $level, $bubble); + } + + public function handle(array $record): bool + { + if (!$this->isHandling($record)) { + return false; + } + + $this->notify([$record]); + + return !$this->bubble; + } + + public function handleBatch(array $records): void + { + if ($records = array_filter($records, [$this, 'isHandling'])) { + $this->notify($records); + } + } + + private function notify(array $records): void + { + $record = $this->getHighestRecord($records); + if (($record['context']['exception'] ?? null) instanceof \Throwable) { + $notification = Notification::fromThrowable($record['context']['exception']); + } else { + $notification = new Notification($record['message']); + } + + $notification->importanceFromLogLevelName(Logger::getLevelName($record['level'])); + + $this->notifier->send($notification, ...$this->notifier->getAdminRecipients()); + } + + private function getHighestRecord(array $records) + { + $highestRecord = null; + foreach ($records as $record) { + if (null === $highestRecord || $highestRecord['level'] < $record['level']) { + $highestRecord = $record; + } + } + + return $highestRecord; + } +} diff --git a/vendor/symfony/monolog-bridge/Handler/ServerLogHandler.php b/vendor/symfony/monolog-bridge/Handler/ServerLogHandler.php index faa36512..53491e9d 100644 --- a/vendor/symfony/monolog-bridge/Handler/ServerLogHandler.php +++ b/vendor/symfony/monolog-bridge/Handler/ServerLogHandler.php @@ -11,24 +11,57 @@ namespace Symfony\Bridge\Monolog\Handler; -use Monolog\Handler\AbstractHandler; +use Monolog\Formatter\FormatterInterface; +use Monolog\Handler\AbstractProcessingHandler; +use Monolog\Handler\FormattableHandlerTrait; use Monolog\Logger; use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter; +if (trait_exists(FormattableHandlerTrait::class)) { + class ServerLogHandler extends AbstractProcessingHandler + { + use ServerLogHandlerTrait; + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter(): FormatterInterface + { + return new VarDumperFormatter(); + } + } +} else { + class ServerLogHandler extends AbstractProcessingHandler + { + use ServerLogHandlerTrait; + + /** + * {@inheritdoc} + */ + protected function getDefaultFormatter() + { + return new VarDumperFormatter(); + } + } +} + /** * @author Grégoire Pineau */ -class ServerLogHandler extends AbstractHandler +trait ServerLogHandlerTrait { private $host; private $context; private $socket; - public function __construct($host, $level = Logger::DEBUG, $bubble = true, $context = []) + /** + * @param string|int $level The minimum logging level at which this handler will be triggered + */ + public function __construct(string $host, $level = Logger::DEBUG, bool $bubble = true, array $context = []) { parent::__construct($level, $bubble); - if (false === strpos($host, '://')) { + if (!str_contains($host, '://')) { $host = 'tcp://'.$host; } @@ -39,7 +72,7 @@ public function __construct($host, $level = Logger::DEBUG, $bubble = true, $cont /** * {@inheritdoc} */ - public function handle(array $record) + public function handle(array $record): bool { if (!$this->isHandling($record)) { return false; @@ -55,6 +88,11 @@ public function handle(array $record) restore_error_handler(); } + return parent::handle($record); + } + + protected function write(array $record): void + { $recordFormatted = $this->formatRecord($record); set_error_handler(self::class.'::nullErrorHandler'); @@ -71,14 +109,12 @@ public function handle(array $record) } finally { restore_error_handler(); } - - return false === $this->bubble; } /** * {@inheritdoc} */ - protected function getDefaultFormatter() + protected function getDefaultFormatter(): FormatterInterface { return new VarDumperFormatter(); } @@ -98,15 +134,9 @@ private function createSocket() return $socket; } - private function formatRecord(array $record) + private function formatRecord(array $record): string { - if ($this->processors) { - foreach ($this->processors as $processor) { - $record = \call_user_func($processor, $record); - } - } - - $recordFormatted = $this->getFormatter()->format($record); + $recordFormatted = $record['formatted']; foreach (['log_uuid', 'uuid', 'uid'] as $key) { if (isset($record['extra'][$key])) { diff --git a/vendor/symfony/monolog-bridge/Handler/SwiftMailerHandler.php b/vendor/symfony/monolog-bridge/Handler/SwiftMailerHandler.php index 03cea013..d5470c6b 100644 --- a/vendor/symfony/monolog-bridge/Handler/SwiftMailerHandler.php +++ b/vendor/symfony/monolog-bridge/Handler/SwiftMailerHandler.php @@ -13,12 +13,14 @@ use Monolog\Handler\SwiftMailerHandler as BaseSwiftMailerHandler; use Symfony\Component\Console\Event\ConsoleTerminateEvent; -use Symfony\Component\HttpKernel\Event\PostResponseEvent; +use Symfony\Component\HttpKernel\Event\TerminateEvent; /** * Extended SwiftMailerHandler that flushes mail queue if necessary. * * @author Philipp Kräutli + * + * @final */ class SwiftMailerHandler extends BaseSwiftMailerHandler { @@ -34,7 +36,7 @@ public function setTransport(\Swift_Transport $transport) /** * After the kernel has been terminated we will always flush messages. */ - public function onKernelTerminate(PostResponseEvent $event) + public function onKernelTerminate(TerminateEvent $event) { $this->instantFlush = true; } @@ -50,7 +52,7 @@ public function onCliTerminate(ConsoleTerminateEvent $event) /** * {@inheritdoc} */ - protected function send($content, array $records) + protected function send($content, array $records): void { parent::send($content, $records); @@ -62,7 +64,7 @@ protected function send($content, array $records) /** * {@inheritdoc} */ - public function reset() + public function reset(): void { $this->flushMemorySpool(); } diff --git a/vendor/symfony/monolog-bridge/LICENSE b/vendor/symfony/monolog-bridge/LICENSE index 9e936ec0..9ff2d0d6 100644 --- a/vendor/symfony/monolog-bridge/LICENSE +++ b/vendor/symfony/monolog-bridge/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2020 Fabien Potencier +Copyright (c) 2004-2021 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/monolog-bridge/Logger.php b/vendor/symfony/monolog-bridge/Logger.php index a88b46fd..4643f5b6 100644 --- a/vendor/symfony/monolog-bridge/Logger.php +++ b/vendor/symfony/monolog-bridge/Logger.php @@ -12,22 +12,23 @@ namespace Symfony\Bridge\Monolog; use Monolog\Logger as BaseLogger; +use Monolog\ResettableInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; +use Symfony\Contracts\Service\ResetInterface; /** - * Logger. - * * @author Fabien Potencier */ -class Logger extends BaseLogger implements DebugLoggerInterface +class Logger extends BaseLogger implements DebugLoggerInterface, ResetInterface { /** * {@inheritdoc} */ - public function getLogs() + public function getLogs(Request $request = null) { if ($logger = $this->getDebugLogger()) { - return $logger->getLogs(); + return $logger->getLogs($request); } return []; @@ -36,10 +37,10 @@ public function getLogs() /** * {@inheritdoc} */ - public function countErrors() + public function countErrors(Request $request = null) { if ($logger = $this->getDebugLogger()) { - return $logger->countErrors(); + return $logger->countErrors($request); } return 0; @@ -50,17 +51,42 @@ public function countErrors() */ public function clear() { - if (($logger = $this->getDebugLogger()) && method_exists($logger, 'clear')) { + if ($logger = $this->getDebugLogger()) { $logger->clear(); } } + /** + * {@inheritdoc} + */ + public function reset(): void + { + $this->clear(); + + if ($this instanceof ResettableInterface) { + parent::reset(); + } + } + + public function removeDebugLogger() + { + foreach ($this->processors as $k => $processor) { + if ($processor instanceof DebugLoggerInterface) { + unset($this->processors[$k]); + } + } + + foreach ($this->handlers as $k => $handler) { + if ($handler instanceof DebugLoggerInterface) { + unset($this->handlers[$k]); + } + } + } + /** * Returns a DebugLoggerInterface instance if one is registered with this logger. - * - * @return DebugLoggerInterface|null A DebugLoggerInterface instance or null if none is registered */ - private function getDebugLogger() + private function getDebugLogger(): ?DebugLoggerInterface { foreach ($this->processors as $processor) { if ($processor instanceof DebugLoggerInterface) { diff --git a/vendor/symfony/monolog-bridge/Processor/AbstractTokenProcessor.php b/vendor/symfony/monolog-bridge/Processor/AbstractTokenProcessor.php new file mode 100644 index 00000000..ed37c94b --- /dev/null +++ b/vendor/symfony/monolog-bridge/Processor/AbstractTokenProcessor.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * The base class for security token processors. + * + * @author Dany Maillard + * @author Igor Timoshenko + */ +abstract class AbstractTokenProcessor +{ + /** + * @var TokenStorageInterface + */ + protected $tokenStorage; + + public function __construct(TokenStorageInterface $tokenStorage) + { + $this->tokenStorage = $tokenStorage; + } + + abstract protected function getKey(): string; + + abstract protected function getToken(): ?TokenInterface; + + public function __invoke(array $record): array + { + $record['extra'][$this->getKey()] = null; + + if (null !== $token = $this->getToken()) { + $record['extra'][$this->getKey()] = [ + 'username' => $token->getUsername(), + 'authenticated' => $token->isAuthenticated(), + 'roles' => $token->getRoleNames(), + ]; + } + + return $record; + } +} diff --git a/vendor/symfony/monolog-bridge/Processor/ConsoleCommandProcessor.php b/vendor/symfony/monolog-bridge/Processor/ConsoleCommandProcessor.php new file mode 100644 index 00000000..2891f4f2 --- /dev/null +++ b/vendor/symfony/monolog-bridge/Processor/ConsoleCommandProcessor.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Symfony\Component\Console\ConsoleEvents; +use Symfony\Component\Console\Event\ConsoleEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Adds the current console command information to the log entry. + * + * @author Piotr Stankowski + */ +class ConsoleCommandProcessor implements EventSubscriberInterface, ResetInterface +{ + private $commandData; + private $includeArguments; + private $includeOptions; + + public function __construct(bool $includeArguments = true, bool $includeOptions = false) + { + $this->includeArguments = $includeArguments; + $this->includeOptions = $includeOptions; + } + + public function __invoke(array $records) + { + if (null !== $this->commandData && !isset($records['extra']['command'])) { + $records['extra']['command'] = $this->commandData; + } + + return $records; + } + + public function reset() + { + $this->commandData = null; + } + + public function addCommandData(ConsoleEvent $event) + { + $this->commandData = [ + 'name' => $event->getCommand()->getName(), + ]; + if ($this->includeArguments) { + $this->commandData['arguments'] = $event->getInput()->getArguments(); + } + if ($this->includeOptions) { + $this->commandData['options'] = $event->getInput()->getOptions(); + } + } + + public static function getSubscribedEvents() + { + return [ + ConsoleEvents::COMMAND => ['addCommandData', 1], + ]; + } +} diff --git a/vendor/symfony/monolog-bridge/Processor/DebugProcessor.php b/vendor/symfony/monolog-bridge/Processor/DebugProcessor.php index 2d4529f2..7b7bf23c 100644 --- a/vendor/symfony/monolog-bridge/Processor/DebugProcessor.php +++ b/vendor/symfony/monolog-bridge/Processor/DebugProcessor.php @@ -12,29 +12,45 @@ namespace Symfony\Bridge\Monolog\Processor; use Monolog\Logger; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; +use Symfony\Contracts\Service\ResetInterface; -class DebugProcessor implements DebugLoggerInterface +class DebugProcessor implements DebugLoggerInterface, ResetInterface { private $records = []; - private $errorCount = 0; + private $errorCount = []; + private $requestStack; + + public function __construct(RequestStack $requestStack = null) + { + $this->requestStack = $requestStack; + } public function __invoke(array $record) { - $this->records[] = [ + $hash = $this->requestStack && ($request = $this->requestStack->getCurrentRequest()) ? spl_object_hash($request) : ''; + + $this->records[$hash][] = [ 'timestamp' => $record['datetime'] instanceof \DateTimeInterface ? $record['datetime']->getTimestamp() : strtotime($record['datetime']), 'message' => $record['message'], 'priority' => $record['level'], 'priorityName' => $record['level_name'], 'context' => $record['context'], - 'channel' => isset($record['channel']) ? $record['channel'] : '', + 'channel' => $record['channel'] ?? '', ]; + + if (!isset($this->errorCount[$hash])) { + $this->errorCount[$hash] = 0; + } + switch ($record['level']) { case Logger::ERROR: case Logger::CRITICAL: case Logger::ALERT: case Logger::EMERGENCY: - ++$this->errorCount; + ++$this->errorCount[$hash]; } return $record; @@ -43,17 +59,29 @@ public function __invoke(array $record) /** * {@inheritdoc} */ - public function getLogs() + public function getLogs(Request $request = null) { - return $this->records; + if (null !== $request) { + return $this->records[spl_object_hash($request)] ?? []; + } + + if (0 === \count($this->records)) { + return []; + } + + return array_merge(...array_values($this->records)); } /** * {@inheritdoc} */ - public function countErrors() + public function countErrors(Request $request = null) { - return $this->errorCount; + if (null !== $request) { + return $this->errorCount[spl_object_hash($request)] ?? 0; + } + + return array_sum($this->errorCount); } /** @@ -62,6 +90,14 @@ public function countErrors() public function clear() { $this->records = []; - $this->errorCount = 0; + $this->errorCount = []; + } + + /** + * {@inheritdoc} + */ + public function reset() + { + $this->clear(); } } diff --git a/vendor/symfony/monolog-bridge/Processor/RouteProcessor.php b/vendor/symfony/monolog-bridge/Processor/RouteProcessor.php new file mode 100644 index 00000000..23b95d9b --- /dev/null +++ b/vendor/symfony/monolog-bridge/Processor/RouteProcessor.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\Service\ResetInterface; + +/** + * Adds the current route information to the log entry. + * + * @author Piotr Stankowski + * + * @final + */ +class RouteProcessor implements EventSubscriberInterface, ResetInterface +{ + private $routeData; + private $includeParams; + + public function __construct(bool $includeParams = true) + { + $this->includeParams = $includeParams; + $this->reset(); + } + + public function __invoke(array $records): array + { + if ($this->routeData && !isset($records['extra']['requests'])) { + $records['extra']['requests'] = array_values($this->routeData); + } + + return $records; + } + + public function reset() + { + $this->routeData = []; + } + + public function addRouteData(RequestEvent $event) + { + if ($event->isMasterRequest()) { + $this->reset(); + } + + $request = $event->getRequest(); + if (!$request->attributes->has('_controller')) { + return; + } + + $currentRequestData = [ + 'controller' => $request->attributes->get('_controller'), + 'route' => $request->attributes->get('_route'), + ]; + + if ($this->includeParams) { + $currentRequestData['route_params'] = $request->attributes->get('_route_params'); + } + + $this->routeData[spl_object_id($request)] = $currentRequestData; + } + + public function removeRouteData(FinishRequestEvent $event) + { + $requestId = spl_object_id($event->getRequest()); + unset($this->routeData[$requestId]); + } + + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::REQUEST => ['addRouteData', 1], + KernelEvents::FINISH_REQUEST => ['removeRouteData', 1], + ]; + } +} diff --git a/vendor/symfony/monolog-bridge/Processor/SwitchUserTokenProcessor.php b/vendor/symfony/monolog-bridge/Processor/SwitchUserTokenProcessor.php new file mode 100644 index 00000000..76aa7e47 --- /dev/null +++ b/vendor/symfony/monolog-bridge/Processor/SwitchUserTokenProcessor.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Symfony\Component\Security\Core\Authentication\Token\SwitchUserToken; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + +/** + * Adds the original security token to the log entry. + * + * @author Igor Timoshenko + */ +class SwitchUserTokenProcessor extends AbstractTokenProcessor +{ + /** + * {@inheritdoc} + */ + protected function getKey(): string + { + return 'impersonator_token'; + } + + /** + * {@inheritdoc} + */ + protected function getToken(): ?TokenInterface + { + $token = $this->tokenStorage->getToken(); + + if ($token instanceof SwitchUserToken) { + return $token->getOriginalToken(); + } + + return null; + } +} diff --git a/vendor/symfony/monolog-bridge/Processor/TokenProcessor.php b/vendor/symfony/monolog-bridge/Processor/TokenProcessor.php index 7bf03a03..7ca212eb 100644 --- a/vendor/symfony/monolog-bridge/Processor/TokenProcessor.php +++ b/vendor/symfony/monolog-bridge/Processor/TokenProcessor.php @@ -11,33 +11,29 @@ namespace Symfony\Bridge\Monolog\Processor; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; /** * Adds the current security token to the log entry. * * @author Dany Maillard + * @author Igor Timoshenko */ -class TokenProcessor +class TokenProcessor extends AbstractTokenProcessor { - private $tokenStorage; - - public function __construct(TokenStorageInterface $tokenStorage) + /** + * {@inheritdoc} + */ + protected function getKey(): string { - $this->tokenStorage = $tokenStorage; + return 'token'; } - public function __invoke(array $records) + /** + * {@inheritdoc} + */ + protected function getToken(): ?TokenInterface { - $records['extra']['token'] = null; - if (null !== $token = $this->tokenStorage->getToken()) { - $records['extra']['token'] = [ - 'username' => $token->getUsername(), - 'authenticated' => $token->isAuthenticated(), - 'roles' => array_map(function ($role) { return $role->getRole(); }, $token->getRoles()), - ]; - } - - return $records; + return $this->tokenStorage->getToken(); } } diff --git a/vendor/symfony/monolog-bridge/Processor/WebProcessor.php b/vendor/symfony/monolog-bridge/Processor/WebProcessor.php index 987c72dd..98ec10ca 100644 --- a/vendor/symfony/monolog-bridge/Processor/WebProcessor.php +++ b/vendor/symfony/monolog-bridge/Processor/WebProcessor.php @@ -12,14 +12,18 @@ namespace Symfony\Bridge\Monolog\Processor; use Monolog\Processor\WebProcessor as BaseWebProcessor; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; /** * WebProcessor override to read from the HttpFoundation's Request. * * @author Jordi Boggiano + * + * @final */ -class WebProcessor extends BaseWebProcessor +class WebProcessor extends BaseWebProcessor implements EventSubscriberInterface { public function __construct(array $extraFields = null) { @@ -27,11 +31,18 @@ public function __construct(array $extraFields = null) parent::__construct([], $extraFields); } - public function onKernelRequest(GetResponseEvent $event) + public function onKernelRequest(RequestEvent $event) { if ($event->isMasterRequest()) { $this->serverData = $event->getRequest()->server->all(); $this->serverData['REMOTE_ADDR'] = $event->getRequest()->getClientIp(); } } + + public static function getSubscribedEvents(): array + { + return [ + KernelEvents::REQUEST => ['onKernelRequest', 4096], + ]; + } } diff --git a/vendor/symfony/monolog-bridge/README.md b/vendor/symfony/monolog-bridge/README.md index 2d19b3e2..112c05c6 100644 --- a/vendor/symfony/monolog-bridge/README.md +++ b/vendor/symfony/monolog-bridge/README.md @@ -1,12 +1,13 @@ Monolog Bridge ============== -Provides integration for Monolog with various Symfony components. +The Monolog bridge provides integration for +[Monolog](https://seldaek.github.io/monolog/) with various Symfony components. Resources --------- - * [Contributing](https://symfony.com/doc/current/contributing/index.html) - * [Report issues](https://github.com/symfony/symfony/issues) and - [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/monolog-bridge/Tests/Formatter/ConsoleFormatterTest.php b/vendor/symfony/monolog-bridge/Tests/Formatter/ConsoleFormatterTest.php deleted file mode 100644 index c09597e9..00000000 --- a/vendor/symfony/monolog-bridge/Tests/Formatter/ConsoleFormatterTest.php +++ /dev/null @@ -1,66 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests\Formatter; - -use Monolog\Logger; -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter; - -class ConsoleFormatterTest extends TestCase -{ - /** - * @dataProvider providerFormatTests - */ - public function testFormat(array $record, $expectedMessage) - { - $formatter = new ConsoleFormatter(); - self::assertSame($expectedMessage, $formatter->format($record)); - } - - /** - * @return array - */ - public function providerFormatTests() - { - $currentDateTime = new \DateTime(); - - return [ - 'record with DateTime object in datetime field' => [ - 'record' => [ - 'message' => 'test', - 'context' => [], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => $currentDateTime, - 'extra' => [], - ], - 'expectedMessage' => sprintf( - "%s WARNING [test] test\n", - $currentDateTime->format(ConsoleFormatter::SIMPLE_DATE) - ), - ], - 'record with string in datetime field' => [ - 'record' => [ - 'message' => 'test', - 'context' => [], - 'level' => Logger::WARNING, - 'level_name' => Logger::getLevelName(Logger::WARNING), - 'channel' => 'test', - 'datetime' => '2019-01-01T00:42:00+00:00', - 'extra' => [], - ], - 'expectedMessage' => "2019-01-01T00:42:00+00:00 WARNING [test] test\n", - ], - ]; - } -} diff --git a/vendor/symfony/monolog-bridge/Tests/Handler/ConsoleHandlerTest.php b/vendor/symfony/monolog-bridge/Tests/Handler/ConsoleHandlerTest.php deleted file mode 100644 index 8d6a8eb4..00000000 --- a/vendor/symfony/monolog-bridge/Tests/Handler/ConsoleHandlerTest.php +++ /dev/null @@ -1,206 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests\Handler; - -use Monolog\Logger; -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Handler\ConsoleHandler; -use Symfony\Component\Console\Command\Command; -use Symfony\Component\Console\ConsoleEvents; -use Symfony\Component\Console\Event\ConsoleCommandEvent; -use Symfony\Component\Console\Event\ConsoleTerminateEvent; -use Symfony\Component\Console\Output\BufferedOutput; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\EventDispatcher\EventDispatcher; - -/** - * Tests the ConsoleHandler and also the ConsoleFormatter. - * - * @author Tobias Schultze - */ -class ConsoleHandlerTest extends TestCase -{ - public function testConstructor() - { - $handler = new ConsoleHandler(null, false); - $this->assertFalse($handler->getBubble(), 'the bubble parameter gets propagated'); - } - - public function testIsHandling() - { - $handler = new ConsoleHandler(); - $this->assertFalse($handler->isHandling([]), '->isHandling returns false when no output is set'); - } - - /** - * @dataProvider provideVerbosityMappingTests - */ - public function testVerbosityMapping($verbosity, $level, $isHandling, array $map = []) - { - $output = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock(); - $output - ->expects($this->atLeastOnce()) - ->method('getVerbosity') - ->willReturn($verbosity) - ; - $handler = new ConsoleHandler($output, true, $map); - $this->assertSame($isHandling, $handler->isHandling(['level' => $level]), - '->isHandling returns correct value depending on console verbosity and log level' - ); - - // check that the handler actually outputs the record if it handles it - $levelName = Logger::getLevelName($level); - $levelName = sprintf('%-9s', $levelName); - - $realOutput = $this->getMockBuilder('Symfony\Component\Console\Output\Output')->setMethods(['doWrite'])->getMock(); - $realOutput->setVerbosity($verbosity); - if ($realOutput->isDebug()) { - $log = "16:21:54 $levelName [app] My info message\n"; - } else { - $log = "16:21:54 $levelName [app] My info message\n"; - } - $realOutput - ->expects($isHandling ? $this->once() : $this->never()) - ->method('doWrite') - ->with($log, false); - $handler = new ConsoleHandler($realOutput, true, $map); - - $infoRecord = [ - 'message' => 'My info message', - 'context' => [], - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'app', - 'datetime' => new \DateTime('2013-05-29 16:21:54'), - 'extra' => [], - ]; - $this->assertFalse($handler->handle($infoRecord), 'The handler finished handling the log.'); - } - - public function provideVerbosityMappingTests() - { - return [ - [OutputInterface::VERBOSITY_QUIET, Logger::ERROR, true], - [OutputInterface::VERBOSITY_QUIET, Logger::WARNING, false], - [OutputInterface::VERBOSITY_NORMAL, Logger::WARNING, true], - [OutputInterface::VERBOSITY_NORMAL, Logger::NOTICE, false], - [OutputInterface::VERBOSITY_VERBOSE, Logger::NOTICE, true], - [OutputInterface::VERBOSITY_VERBOSE, Logger::INFO, false], - [OutputInterface::VERBOSITY_VERY_VERBOSE, Logger::INFO, true], - [OutputInterface::VERBOSITY_VERY_VERBOSE, Logger::DEBUG, false], - [OutputInterface::VERBOSITY_DEBUG, Logger::DEBUG, true], - [OutputInterface::VERBOSITY_DEBUG, Logger::EMERGENCY, true], - [OutputInterface::VERBOSITY_NORMAL, Logger::NOTICE, true, [ - OutputInterface::VERBOSITY_NORMAL => Logger::NOTICE, - ]], - [OutputInterface::VERBOSITY_DEBUG, Logger::NOTICE, true, [ - OutputInterface::VERBOSITY_NORMAL => Logger::NOTICE, - ]], - ]; - } - - public function testVerbosityChanged() - { - $output = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock(); - $output - ->expects($this->exactly(2)) - ->method('getVerbosity') - ->willReturnOnConsecutiveCalls( - OutputInterface::VERBOSITY_QUIET, - OutputInterface::VERBOSITY_DEBUG - ) - ; - $handler = new ConsoleHandler($output); - $this->assertFalse($handler->isHandling(['level' => Logger::NOTICE]), - 'when verbosity is set to quiet, the handler does not handle the log' - ); - $this->assertTrue($handler->isHandling(['level' => Logger::NOTICE]), - 'since the verbosity of the output increased externally, the handler is now handling the log' - ); - } - - public function testGetFormatter() - { - $handler = new ConsoleHandler(); - $this->assertInstanceOf('Symfony\Bridge\Monolog\Formatter\ConsoleFormatter', $handler->getFormatter(), - '-getFormatter returns ConsoleFormatter by default' - ); - } - - public function testWritingAndFormatting() - { - $output = $this->getMockBuilder('Symfony\Component\Console\Output\OutputInterface')->getMock(); - $output - ->expects($this->any()) - ->method('getVerbosity') - ->willReturn(OutputInterface::VERBOSITY_DEBUG) - ; - $output - ->expects($this->once()) - ->method('write') - ->with("16:21:54 INFO [app] My info message\n") - ; - - $handler = new ConsoleHandler(null, false); - $handler->setOutput($output); - - $infoRecord = [ - 'message' => 'My info message', - 'context' => [], - 'level' => Logger::INFO, - 'level_name' => Logger::getLevelName(Logger::INFO), - 'channel' => 'app', - 'datetime' => new \DateTime('2013-05-29 16:21:54'), - 'extra' => [], - ]; - - $this->assertTrue($handler->handle($infoRecord), 'The handler finished handling the log as bubble is false.'); - } - - public function testLogsFromListeners() - { - $output = new BufferedOutput(); - $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); - - $handler = new ConsoleHandler(null, false); - - $logger = new Logger('app'); - $logger->pushHandler($handler); - - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(ConsoleEvents::COMMAND, function () use ($logger) { - $logger->addInfo('Before command message.'); - }); - $dispatcher->addListener(ConsoleEvents::TERMINATE, function () use ($logger) { - $logger->addInfo('Before terminate message.'); - }); - - $dispatcher->addSubscriber($handler); - - $dispatcher->addListener(ConsoleEvents::COMMAND, function () use ($logger) { - $logger->addInfo('After command message.'); - }); - $dispatcher->addListener(ConsoleEvents::TERMINATE, function () use ($logger) { - $logger->addInfo('After terminate message.'); - }); - - $event = new ConsoleCommandEvent(new Command('foo'), $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock(), $output); - $dispatcher->dispatch(ConsoleEvents::COMMAND, $event); - $this->assertStringContainsString('Before command message.', $out = $output->fetch()); - $this->assertStringContainsString('After command message.', $out); - - $event = new ConsoleTerminateEvent(new Command('foo'), $this->getMockBuilder('Symfony\Component\Console\Input\InputInterface')->getMock(), $output, 0); - $dispatcher->dispatch(ConsoleEvents::TERMINATE, $event); - $this->assertStringContainsString('Before terminate message.', $out = $output->fetch()); - $this->assertStringContainsString('After terminate message.', $out); - } -} diff --git a/vendor/symfony/monolog-bridge/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php b/vendor/symfony/monolog-bridge/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php deleted file mode 100644 index b0467810..00000000 --- a/vendor/symfony/monolog-bridge/Tests/Handler/FingersCrossed/NotFoundActivationStrategyTest.php +++ /dev/null @@ -1,55 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests\Handler\FingersCrossed; - -use Monolog\Logger; -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpKernel\Exception\HttpException; - -class NotFoundActivationStrategyTest extends TestCase -{ - /** - * @dataProvider isActivatedProvider - */ - public function testIsActivated($url, $record, $expected) - { - $requestStack = new RequestStack(); - $requestStack->push(Request::create($url)); - - $strategy = new NotFoundActivationStrategy($requestStack, ['^/foo', 'bar'], Logger::WARNING); - - $this->assertEquals($expected, $strategy->isHandlerActivated($record)); - } - - public function isActivatedProvider() - { - return [ - ['/test', ['level' => Logger::DEBUG], false], - ['/foo', ['level' => Logger::DEBUG, 'context' => $this->getContextException(404)], false], - ['/baz/bar', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], false], - ['/foo', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], false], - ['/foo', ['level' => Logger::ERROR, 'context' => $this->getContextException(500)], true], - - ['/test', ['level' => Logger::ERROR], true], - ['/baz', ['level' => Logger::ERROR, 'context' => $this->getContextException(404)], true], - ['/baz', ['level' => Logger::ERROR, 'context' => $this->getContextException(500)], true], - ]; - } - - protected function getContextException($code) - { - return ['exception' => new HttpException($code)]; - } -} diff --git a/vendor/symfony/monolog-bridge/Tests/LoggerTest.php b/vendor/symfony/monolog-bridge/Tests/LoggerTest.php deleted file mode 100644 index 4631289d..00000000 --- a/vendor/symfony/monolog-bridge/Tests/LoggerTest.php +++ /dev/null @@ -1,144 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests; - -use Monolog\Handler\TestHandler; -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Handler\DebugHandler; -use Symfony\Bridge\Monolog\Logger; -use Symfony\Bridge\Monolog\Processor\DebugProcessor; - -class LoggerTest extends TestCase -{ - /** - * @group legacy - */ - public function testGetLogsWithDebugHandler() - { - $handler = new DebugHandler(); - $logger = new Logger(__METHOD__, [$handler]); - - $this->assertTrue($logger->error('error message')); - $this->assertCount(1, $logger->getLogs()); - } - - public function testGetLogsWithoutDebugProcessor() - { - $handler = new TestHandler(); - $logger = new Logger(__METHOD__, [$handler]); - - $this->assertTrue($logger->error('error message')); - $this->assertSame([], $logger->getLogs()); - } - - /** - * @group legacy - */ - public function testCountErrorsWithDebugHandler() - { - $handler = new DebugHandler(); - $logger = new Logger(__METHOD__, [$handler]); - - $this->assertTrue($logger->debug('test message')); - $this->assertTrue($logger->info('test message')); - $this->assertTrue($logger->notice('test message')); - $this->assertTrue($logger->warning('test message')); - - $this->assertTrue($logger->error('test message')); - $this->assertTrue($logger->critical('test message')); - $this->assertTrue($logger->alert('test message')); - $this->assertTrue($logger->emergency('test message')); - - $this->assertSame(4, $logger->countErrors()); - } - - /** - * @group legacy - */ - public function testGetLogsWithDebugHandler2() - { - $logger = new Logger('test'); - $logger->pushHandler(new DebugHandler()); - - $logger->addInfo('test'); - $this->assertCount(1, $logger->getLogs()); - list($record) = $logger->getLogs(); - - $this->assertEquals('test', $record['message']); - $this->assertEquals(Logger::INFO, $record['priority']); - } - - public function testCountErrorsWithoutDebugProcessor() - { - $handler = new TestHandler(); - $logger = new Logger(__METHOD__, [$handler]); - - $this->assertTrue($logger->error('error message')); - $this->assertSame(0, $logger->countErrors()); - } - - public function testGetLogsWithDebugProcessor() - { - $handler = new TestHandler(); - $processor = new DebugProcessor(); - $logger = new Logger(__METHOD__, [$handler], [$processor]); - - $this->assertTrue($logger->error('error message')); - $this->assertCount(1, $logger->getLogs()); - } - - public function testCountErrorsWithDebugProcessor() - { - $handler = new TestHandler(); - $processor = new DebugProcessor(); - $logger = new Logger(__METHOD__, [$handler], [$processor]); - - $this->assertTrue($logger->debug('test message')); - $this->assertTrue($logger->info('test message')); - $this->assertTrue($logger->notice('test message')); - $this->assertTrue($logger->warning('test message')); - - $this->assertTrue($logger->error('test message')); - $this->assertTrue($logger->critical('test message')); - $this->assertTrue($logger->alert('test message')); - $this->assertTrue($logger->emergency('test message')); - - $this->assertSame(4, $logger->countErrors()); - } - - public function testGetLogsWithDebugProcessor2() - { - $handler = new TestHandler(); - $logger = new Logger('test', [$handler]); - $logger->pushProcessor(new DebugProcessor()); - - $logger->addInfo('test'); - $this->assertCount(1, $logger->getLogs()); - list($record) = $logger->getLogs(); - - $this->assertEquals('test', $record['message']); - $this->assertEquals(Logger::INFO, $record['priority']); - } - - public function testClear() - { - $handler = new TestHandler(); - $logger = new Logger('test', [$handler]); - $logger->pushProcessor(new DebugProcessor()); - - $logger->addInfo('test'); - $logger->clear(); - - $this->assertEmpty($logger->getLogs()); - $this->assertSame(0, $logger->countErrors()); - } -} diff --git a/vendor/symfony/monolog-bridge/Tests/Processor/DebugProcessorTest.php b/vendor/symfony/monolog-bridge/Tests/Processor/DebugProcessorTest.php deleted file mode 100644 index d9fcccaf..00000000 --- a/vendor/symfony/monolog-bridge/Tests/Processor/DebugProcessorTest.php +++ /dev/null @@ -1,61 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests\Processor; - -use Monolog\Logger; -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Processor\DebugProcessor; - -class DebugProcessorTest extends TestCase -{ - /** - * @dataProvider providerDatetimeFormatTests - */ - public function testDatetimeFormat(array $record, $expectedTimestamp) - { - $processor = new DebugProcessor(); - $processor($record); - - $records = $processor->getLogs(); - self::assertCount(1, $records); - self::assertSame($expectedTimestamp, $records[0]['timestamp']); - } - - /** - * @return array - */ - public function providerDatetimeFormatTests() - { - $record = $this->getRecord(); - - return [ - [array_merge($record, ['datetime' => new \DateTime('2019-01-01T00:01:00+00:00')]), 1546300860], - [array_merge($record, ['datetime' => '2019-01-01T00:01:00+00:00']), 1546300860], - [array_merge($record, ['datetime' => 'foo']), false], - ]; - } - - /** - * @return array - */ - private function getRecord() - { - return [ - 'message' => 'test', - 'context' => [], - 'level' => Logger::DEBUG, - 'level_name' => Logger::getLevelName(Logger::DEBUG), - 'channel' => 'test', - 'datetime' => new \DateTime(), - ]; - } -} diff --git a/vendor/symfony/monolog-bridge/Tests/Processor/TokenProcessorTest.php b/vendor/symfony/monolog-bridge/Tests/Processor/TokenProcessorTest.php deleted file mode 100644 index 1b013486..00000000 --- a/vendor/symfony/monolog-bridge/Tests/Processor/TokenProcessorTest.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests\Processor; - -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Processor\TokenProcessor; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; - -/** - * Tests the TokenProcessor. - * - * @author Dany Maillard - */ -class TokenProcessorTest extends TestCase -{ - public function testProcessor() - { - $token = new UsernamePasswordToken('user', 'password', 'provider', ['ROLE_USER']); - $tokenStorage = $this->getMockBuilder(TokenStorageInterface::class)->getMock(); - $tokenStorage->method('getToken')->willReturn($token); - - $processor = new TokenProcessor($tokenStorage); - $record = ['extra' => []]; - $record = $processor($record); - - $this->assertArrayHasKey('token', $record['extra']); - $this->assertEquals($token->getUsername(), $record['extra']['token']['username']); - $this->assertEquals($token->isAuthenticated(), $record['extra']['token']['authenticated']); - $roles = array_map(function ($role) { return $role->getRole(); }, $token->getRoles()); - $this->assertEquals($roles, $record['extra']['token']['roles']); - } -} diff --git a/vendor/symfony/monolog-bridge/Tests/Processor/WebProcessorTest.php b/vendor/symfony/monolog-bridge/Tests/Processor/WebProcessorTest.php deleted file mode 100644 index a69ab756..00000000 --- a/vendor/symfony/monolog-bridge/Tests/Processor/WebProcessorTest.php +++ /dev/null @@ -1,137 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bridge\Monolog\Tests\Processor; - -use Monolog\Logger; -use PHPUnit\Framework\TestCase; -use Symfony\Bridge\Monolog\Processor\WebProcessor; -use Symfony\Component\HttpFoundation\Request; - -class WebProcessorTest extends TestCase -{ - public function testUsesRequestServerData() - { - list($event, $server) = $this->createRequestEvent(); - - $processor = new WebProcessor(); - $processor->onKernelRequest($event); - $record = $processor($this->getRecord()); - - $this->assertCount(5, $record['extra']); - $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']); - $this->assertEquals($server['REMOTE_ADDR'], $record['extra']['ip']); - $this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']); - $this->assertEquals($server['SERVER_NAME'], $record['extra']['server']); - $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']); - } - - public function testUseRequestClientIp() - { - Request::setTrustedProxies(['192.168.0.1'], Request::HEADER_X_FORWARDED_ALL); - list($event, $server) = $this->createRequestEvent(['X_FORWARDED_FOR' => '192.168.0.2']); - - $processor = new WebProcessor(); - $processor->onKernelRequest($event); - $record = $processor($this->getRecord()); - - $this->assertCount(5, $record['extra']); - $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']); - $this->assertEquals($server['X_FORWARDED_FOR'], $record['extra']['ip']); - $this->assertEquals($server['REQUEST_METHOD'], $record['extra']['http_method']); - $this->assertEquals($server['SERVER_NAME'], $record['extra']['server']); - $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']); - - Request::setTrustedProxies([], -1); - } - - public function testCanBeConstructedWithExtraFields() - { - if (!$this->isExtraFieldsSupported()) { - $this->markTestSkipped('WebProcessor of the installed Monolog version does not support $extraFields parameter'); - } - - list($event, $server) = $this->createRequestEvent(); - - $processor = new WebProcessor(['url', 'referrer']); - $processor->onKernelRequest($event); - $record = $processor($this->getRecord()); - - $this->assertCount(2, $record['extra']); - $this->assertEquals($server['REQUEST_URI'], $record['extra']['url']); - $this->assertEquals($server['HTTP_REFERER'], $record['extra']['referrer']); - } - - /** - * @return array - */ - private function createRequestEvent($additionalServerParameters = []) - { - $server = array_merge( - [ - 'REQUEST_URI' => 'A', - 'REMOTE_ADDR' => '192.168.0.1', - 'REQUEST_METHOD' => 'C', - 'SERVER_NAME' => 'D', - 'HTTP_REFERER' => 'E', - ], - $additionalServerParameters - ); - - $request = new Request(); - $request->server->replace($server); - $request->headers->replace($server); - - $event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') - ->disableOriginalConstructor() - ->getMock(); - $event->expects($this->any()) - ->method('isMasterRequest') - ->willReturn(true); - $event->expects($this->any()) - ->method('getRequest') - ->willReturn($request); - - return [$event, $server]; - } - - /** - * @param int $level - * @param string $message - * - * @return array Record - */ - private function getRecord($level = Logger::WARNING, $message = 'test') - { - return [ - 'message' => $message, - 'context' => [], - 'level' => $level, - 'level_name' => Logger::getLevelName($level), - 'channel' => 'test', - 'datetime' => new \DateTime(), - 'extra' => [], - ]; - } - - private function isExtraFieldsSupported() - { - $monologWebProcessorClass = new \ReflectionClass('Monolog\Processor\WebProcessor'); - - foreach ($monologWebProcessorClass->getConstructor()->getParameters() as $parameter) { - if ('extraFields' === $parameter->getName()) { - return true; - } - } - - return false; - } -} diff --git a/vendor/symfony/monolog-bridge/composer.json b/vendor/symfony/monolog-bridge/composer.json index d76e263d..b7215fc4 100644 --- a/vendor/symfony/monolog-bridge/composer.json +++ b/vendor/symfony/monolog-bridge/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/monolog-bridge", "type": "symfony-bridge", - "description": "Symfony Monolog Bridge", + "description": "Provides integration for Monolog with various Symfony components", "keywords": [], "homepage": "https://symfony.com", "license": "MIT", @@ -16,24 +16,28 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "monolog/monolog": "~1.19", - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "php": ">=7.2.5", + "monolog/monolog": "^1.25.1|^2", + "symfony/service-contracts": "^1.1|^2", + "symfony/http-kernel": "^4.4|^5.0", + "symfony/deprecation-contracts": "^2.1", + "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/security-core": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" + "symfony/console": "^4.4|^5.0", + "symfony/http-client": "^4.4|^5.0", + "symfony/security-core": "^4.4|^5.0", + "symfony/var-dumper": "^4.4|^5.0", + "symfony/mailer": "^4.4|^5.0", + "symfony/mime": "^4.4|^5.0" }, "conflict": { - "symfony/console": "<2.8", - "symfony/http-foundation": "<3.3" + "symfony/console": "<4.4", + "symfony/http-foundation": "<4.4" }, "suggest": { "symfony/http-kernel": "For using the debugging handlers together with the response life cycle of the HTTP kernel.", - "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings. You need version ^2.8 of the console for it.", - "symfony/event-dispatcher": "Needed when using log messages in console commands.", + "symfony/console": "For the possibility to show log messages in console commands depending on verbosity settings.", "symfony/var-dumper": "For using the debugging handlers like the console handler or the log server handler." }, "autoload": { diff --git a/vendor/symfony/monolog-bridge/phpunit.xml.dist b/vendor/symfony/monolog-bridge/phpunit.xml.dist deleted file mode 100644 index 1bda3eca..00000000 --- a/vendor/symfony/monolog-bridge/phpunit.xml.dist +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - ./Tests/ - - - - - - ./ - - ./Resources - ./Tests - ./vendor - - - - diff --git a/vendor/symfony/monolog-bundle/.github/workflows/ci.yaml b/vendor/symfony/monolog-bundle/.github/workflows/ci.yaml new file mode 100644 index 00000000..5d3ac1e4 --- /dev/null +++ b/vendor/symfony/monolog-bundle/.github/workflows/ci.yaml @@ -0,0 +1,54 @@ +name: CI + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + name: PHPUnit Tests + strategy: + fail-fast: false + matrix: + php: [ '7.2', '7.3', '7.4', '8.0', '8.1' ] + monolog: [ '1.*', '2.*' ] + include: + - php: '7.1' + - php: '7.4' + deps: lowest + deprecations: max[self]=0 + - php: '8.1' + deps: highest + monolog: '3.*' + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + ini-values: zend.exception_ignore_args=false + tools: flex + + - name: Configure composer + if: "${{ matrix.deps == 'highest' }}" + run: composer config minimum-stability dev + + - name: Require Monolog version + if: "${{ matrix.monolog != '' }}" + run: composer require --no-update monolog/monolog:${{ matrix.monolog }} + + - name: Composer install + uses: ramsey/composer-install@v1 + with: + dependency-versions: '${{ matrix.deps }}' + + - name: Install PHPUnit dependencies + run: vendor/bin/simple-phpunit install + + - name: Run tests + run: vendor/bin/simple-phpunit -v --coverage-text + env: + SYMFONY_DEPRECATIONS_HELPER: '${{ matrix.deprecations }}' diff --git a/vendor/symfony/monolog-bundle/.travis.yml b/vendor/symfony/monolog-bundle/.travis.yml deleted file mode 100644 index 2dd87338..00000000 --- a/vendor/symfony/monolog-bundle/.travis.yml +++ /dev/null @@ -1,59 +0,0 @@ -language: php - -dist: trusty -sudo: false - -cache: - directories: - - $HOME/.composer/cache/files - - .phpunit - -env: - global: - - SYMFONY_PHPUNIT_DIR=.phpunit - -matrix: - fast_finish: true - include: - - php: 5.6 - env: COMPOSER_FLAGS="--prefer-lowest" SYMFONY_DEPRECATIONS_HELPER=weak - # Test against Symfony LTS versions - - php: 5.6 - env: SYMFONY_VERSION="3.4.*" - - php: 7.0 - - php: 7.1 - # There is a bug in PHPUnit 5.7 - env: SYMFONY_PHPUNIT_VERSION=6.5 - # Test against seldaek/monolog 1.x - - php: 7.2 - env: MONOLOG_VERSION=1.* - - php: 7.3 - env: MONOLOG_VERSION=1.* - - php: 7.4 - env: MONOLOG_VERSION=1.* - # Test against seldaek/monolog 2.x - - php: 7.2 - env: MONOLOG_VERSION=2.* - - php: 7.3 - env: MONOLOG_VERSION=2.* - - php: 7.4 - env: MONOLOG_VERSION=2.* - # Test against dev versions - - php: nightly - env: DEPENDENCIES=dev MONOLOG_VERSION=1.* - - php: nightly - env: DEPENDENCIES=dev MONOLOG_VERSION=2.* - allow_failures: - - php: nightly - -before_install: - - composer self-update - - if [ "$DEPENDENCIES" = "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi; - - if [ "$MONOLOG_VERSION" != "" ]; then composer require --dev --no-update monolog/monolog:"$MONOLOG_VERSION"; fi; - - if [ "$SYMFONY_VERSION" != "" ]; then composer require --dev --no-update symfony/symfony:"$SYMFONY_VERSION"; fi - -install: - - composer update $COMPOSER_FLAGS - - ./vendor/bin/simple-phpunit install - -script: ./vendor/bin/simple-phpunit -v --coverage-text diff --git a/vendor/symfony/monolog-bundle/CHANGELOG.md b/vendor/symfony/monolog-bundle/CHANGELOG.md index e79b3c2f..c452bb47 100644 --- a/vendor/symfony/monolog-bundle/CHANGELOG.md +++ b/vendor/symfony/monolog-bundle/CHANGELOG.md @@ -1,4 +1,32 @@ -## 3.6.0 (xxxx-xx-xx) +## 3.8.0 (2022-05-10) + +* Deprecated ambiguous `elasticsearch` type, use `elastica` instead +* Added support for Monolog 3.0 (requires symfony/monolog-bridge 6.1) +* Added support for `AsMonologProcessor` to autoconfigure processors +* Added support for `FallbackGroupHandler` +* Added support for `ElasticsearchHandler` as `elastic_search` type +* Added support for `ElasticaHandler` as `elastica` type +* Added support for `TelegramBotHandler` as `telegram` +* Added `fill_extra_context` flag for `sentry` handlers +* Added support for configuring PsrLogMessageProcessor (`date_format` and `remove_used_context_fields`) +* Fixed issue on Windows + PHP 8, workaround for https://github.com/php/php-src/issues/8315 +* Fixed MongoDBHandler support when no client id is provided + +## 3.7.1 (2021-11-05) + +* Indicate compatibility with Symfony 6 + +## 3.7.0 (2021-03-31) + +* Use `ActivationStrategy` instead of `actionLevel` when available +* Register resettable processors (`ResettableInterface`) for autoconfiguration (tag: `kernel.reset`) +* Drop support for Symfony 3.4 +* Drop support for PHP < 7.1 +* Fix call to undefined method pushProcessor on handler that does not implement ProcessableHandlerInterface +* Use "use_locking" option with rotating file handler +* Add ability to specify custom Sentry hub service + +## 3.6.0 (2020-10-06) * Added support for Symfony Mailer * Added support for setting log levels from parameters or environment variables diff --git a/vendor/symfony/monolog-bundle/DependencyInjection/Compiler/AddProcessorsPass.php b/vendor/symfony/monolog-bundle/DependencyInjection/Compiler/AddProcessorsPass.php index 7afaa06c..e9d0f8af 100644 --- a/vendor/symfony/monolog-bundle/DependencyInjection/Compiler/AddProcessorsPass.php +++ b/vendor/symfony/monolog-bundle/DependencyInjection/Compiler/AddProcessorsPass.php @@ -11,8 +11,9 @@ namespace Symfony\Bundle\MonologBundle\DependencyInjection\Compiler; -use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; /** @@ -36,6 +37,14 @@ public function process(ContainerBuilder $container) if (!empty($tag['handler'])) { $definition = $container->findDefinition(sprintf('monolog.handler.%s', $tag['handler'])); + $parentDef = $definition; + while (!$parentDef->getClass() && $parentDef instanceof ChildDefinition) { + $parentDef = $container->findDefinition($parentDef->getParent()); + } + $class = $container->getParameterBag()->resolveValue($parentDef->getClass()); + if (!method_exists($class, 'pushProcessor')) { + throw new \InvalidArgumentException(sprintf('The "%s" handler does not accept processors', $tag['handler'])); + } } elseif (!empty($tag['channel'])) { if ('app' === $tag['channel']) { $definition = $container->getDefinition('monolog.logger'); diff --git a/vendor/symfony/monolog-bundle/DependencyInjection/Configuration.php b/vendor/symfony/monolog-bundle/DependencyInjection/Configuration.php index a094fe7b..7dea0247 100644 --- a/vendor/symfony/monolog-bundle/DependencyInjection/Configuration.php +++ b/vendor/symfony/monolog-bundle/DependencyInjection/Configuration.php @@ -11,10 +11,12 @@ namespace Symfony\Bundle\MonologBundle\DependencyInjection; +use Monolog\Logger; +use Symfony\Component\Config\Definition\BaseNode; +use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition; use Symfony\Component\Config\Definition\Builder\TreeBuilder; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; -use Monolog\Logger; /** * This class contains the configuration information for the bundle @@ -38,7 +40,7 @@ * - [verbosity_levels]: level => verbosity configuration * - [level]: level name or int value, defaults to DEBUG * - [bubble]: bool, defaults to true - * - [console_formater_options]: array + * - [console_formatter_options]: array * * - firephp: * - [level]: level name or int value, defaults to DEBUG @@ -63,6 +65,7 @@ * - [level]: level name or int value, defaults to DEBUG * - [bubble]: bool, defaults to true * - [file_permission]: string|null, defaults to null + * - [use_locking]: bool, defaults to false * - [filename_format]: string, defaults to '{filename}-{date}' * - [date_format]: string, defaults to 'Y-m-d' * @@ -78,11 +81,25 @@ * - [level]: level name or int value, defaults to DEBUG * - [bubble]: bool, defaults to true * - * - elasticsearch: + * - elastic_search: + * - elasticsearch: + * - id: optional if host is given + * - host: elastic search host name, with scheme (e.g. "https://127.0.0.1:9200") + * - [user]: elastic search user name + * - [password]: elastic search user password + * - [index]: index name, defaults to monolog + * - [document_type]: document_type, defaults to logs + * - [level]: level name or int value, defaults to DEBUG + * - [bubble]: bool, defaults to true + * + * - elastica: * - elasticsearch: * - id: optional if host is given * - host: elastic search host name. Do not prepend with http(s):// * - [port]: defaults to 9200 + * - [transport]: transport protocol (http by default) + * - [user]: elastic search user name + * - [password]: elastic search user password * - [index]: index name, defaults to monolog * - [document_type]: document_type, defaults to logs * - [level]: level name or int value, defaults to DEBUG @@ -142,6 +159,10 @@ * - members: the wrapped handlers by name * - [bubble]: bool, defaults to true * + * - fallbackgroup + * - members: the wrapped handlers by name + * - [bubble]: bool, defaults to true + * * - syslog: * - ident: string * - [facility]: defaults to 'user', use any of the LOG_* facility constant but without LOG_ prefix, e.g. user for LOG_USER @@ -212,6 +233,10 @@ * - [auto_log_stacks]: bool, defaults to false * - [environment]: string, default to null (no env specified) * + * - sentry: + * - hub_id: Sentry hub custom service id (optional) + * - [fill_extra_context]: bool, defaults to false + * * - newrelic: * - [level]: level name or int value, defaults to DEBUG * - [bubble]: bool, defaults to true @@ -330,6 +355,17 @@ * - [level]: level name or int value, defaults to DEBUG * - [bubble]: bool, defaults to true * + * - telegram: + * - token: Telegram bot access token provided by BotFather + * - channel: Telegram channel name + * - [level]: level name or int value, defaults to DEBUG + * - [bubble]: bool, defaults to true + * - [parse_mode]: optional the kind of formatting that is used for the message + * - [disable_webpage_preview]: bool, defaults to false, disables link previews for links in the message + * - [disable_notification]: bool, defaults to false, sends the message silently. Users will receive a notification with no sound + * - [split_long_messages]: bool, defaults to false, split messages longer than 4096 bytes into multiple messages + * - [delay_between_messages]: bool, defaults to false, adds a 1sec delay/sleep between sending split messages + * * All handlers can also be marked with `nested: true` to make sure they are never added explicitly to the stack * * @author Jordi Boggiano @@ -347,7 +383,7 @@ public function getConfigTreeBuilder() $treeBuilder = new TreeBuilder('monolog'); $rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('monolog'); - $rootNode + $handlers = $rootNode ->fixXmlConfig('channel') ->fixXmlConfig('handler') ->children() @@ -356,624 +392,772 @@ public function getConfigTreeBuilder() ->canBeUnset() ->prototype('scalar')->end() ->end() - ->arrayNode('handlers') + ->arrayNode('handlers'); + + $handlers + ->canBeUnset() + ->useAttributeAsKey('name') + ->validate() + ->ifTrue(function ($v) { return isset($v['debug']); }) + ->thenInvalid('The "debug" name cannot be used as it is reserved for the handler of the profiler') + ->end() + ->example([ + 'syslog' => [ + 'type' => 'stream', + 'path' => '/var/log/symfony.log', + 'level' => 'ERROR', + 'bubble' => 'false', + 'formatter' => 'my_formatter', + ], + 'main' => [ + 'type' => 'fingers_crossed', + 'action_level' => 'WARNING', + 'buffer_size' => 30, + 'handler' => 'custom', + ], + 'custom' => [ + 'type' => 'service', + 'id' => 'my_handler', + ] + ]); + + $handlerNode = $handlers + ->prototype('array') + ->fixXmlConfig('member') + ->fixXmlConfig('excluded_404') + ->fixXmlConfig('excluded_http_code') + ->fixXmlConfig('tag') + ->fixXmlConfig('accepted_level') + ->fixXmlConfig('header') + ->canBeUnset(); + + $handlerNode + ->children() + ->scalarNode('type') + ->isRequired() + ->treatNullLike('null') + ->beforeNormalization() + ->always() + ->then(function ($v) { return strtolower($v); }) + ->end() + ->end() + ->scalarNode('id')->end() // service & rollbar + ->scalarNode('priority')->defaultValue(0)->end() + ->scalarNode('level')->defaultValue('DEBUG')->end() + ->booleanNode('bubble')->defaultTrue()->end() + ->scalarNode('app_name')->defaultNull()->end() + ->booleanNode('fill_extra_context')->defaultFalse()->end() // sentry + ->booleanNode('include_stacktraces')->defaultFalse()->end() + ->arrayNode('process_psr_3_messages') + ->addDefaultsIfNotSet() + ->beforeNormalization() + ->ifTrue(static function ($v) { return !\is_array($v); }) + ->then(static function ($v) { return ['enabled' => $v]; }) + ->end() + ->children() + ->booleanNode('enabled')->defaultNull()->end() + ->scalarNode('date_format')->end() + ->booleanNode('remove_used_context_fields')->end() + ->end() + ->end() + ->scalarNode('path')->defaultValue('%kernel.logs_dir%/%kernel.environment%.log')->end() // stream and rotating + ->scalarNode('file_permission') // stream and rotating + ->defaultNull() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { + if (substr($v, 0, 1) === '0') { + return octdec($v); + } + + return (int) $v; + }) + ->end() + ->end() + ->booleanNode('use_locking')->defaultFalse()->end() // stream and rotating + ->scalarNode('filename_format')->defaultValue('{filename}-{date}')->end() //rotating + ->scalarNode('date_format')->defaultValue('Y-m-d')->end() //rotating + ->scalarNode('ident')->defaultFalse()->end() // syslog and syslogudp + ->scalarNode('logopts')->defaultValue(LOG_PID)->end() // syslog + ->scalarNode('facility')->defaultValue('user')->end() // syslog + ->scalarNode('max_files')->defaultValue(0)->end() // rotating + ->scalarNode('action_level')->defaultValue('WARNING')->end() // fingers_crossed + ->scalarNode('activation_strategy')->defaultNull()->end() // fingers_crossed + ->booleanNode('stop_buffering')->defaultTrue()->end()// fingers_crossed + ->scalarNode('passthru_level')->defaultNull()->end() // fingers_crossed + ->arrayNode('excluded_404s') // fingers_crossed + ->canBeUnset() + ->prototype('scalar')->end() + ->end() + ->arrayNode('excluded_http_codes') // fingers_crossed ->canBeUnset() - ->useAttributeAsKey('name') + ->beforeNormalization() + ->always(function ($values) { + return array_map(function ($value) { + /* + * Allows YAML: + * excluded_http_codes: [403, 404, { 400: ['^/foo', '^/bar'] }] + * + * and XML: + * + * ^/foo + * ^/bar + * + * + */ + + if (is_array($value)) { + return isset($value['code']) ? $value : ['code' => key($value), 'urls' => current($value)]; + } + + return ['code' => $value, 'urls' => []]; + }, $values); + }) + ->end() ->prototype('array') - ->fixXmlConfig('member') - ->fixXmlConfig('excluded_404') - ->fixXmlConfig('excluded_http_code') - ->fixXmlConfig('tag') - ->fixXmlConfig('accepted_level') - ->fixXmlConfig('header') - ->canBeUnset() ->children() - ->scalarNode('type') - ->isRequired() - ->treatNullLike('null') - ->beforeNormalization() - ->always() - ->then(function ($v) { return strtolower($v); }) - ->end() - ->end() - ->scalarNode('id')->end() // service & rollbar - ->scalarNode('priority')->defaultValue(0)->end() - ->scalarNode('level')->defaultValue('DEBUG')->end() - ->booleanNode('bubble')->defaultTrue()->end() - ->scalarNode('app_name')->defaultNull()->end() - ->booleanNode('include_stacktraces')->defaultFalse()->end() - ->booleanNode('process_psr_3_messages')->defaultNull()->end() - ->scalarNode('path')->defaultValue('%kernel.logs_dir%/%kernel.environment%.log')->end() // stream and rotating - ->scalarNode('file_permission') // stream and rotating - ->defaultNull() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { - if (substr($v, 0, 1) === '0') { - return octdec($v); - } - - return (int) $v; - }) - ->end() - ->end() - ->booleanNode('use_locking')->defaultFalse()->end() // stream - ->scalarNode('filename_format')->defaultValue('{filename}-{date}')->end() //rotating - ->scalarNode('date_format')->defaultValue('Y-m-d')->end() //rotating - ->scalarNode('ident')->defaultFalse()->end() // syslog and syslogudp - ->scalarNode('logopts')->defaultValue(LOG_PID)->end() // syslog - ->scalarNode('facility')->defaultValue('user')->end() // syslog - ->scalarNode('max_files')->defaultValue(0)->end() // rotating - ->scalarNode('action_level')->defaultValue('WARNING')->end() // fingers_crossed - ->scalarNode('activation_strategy')->defaultNull()->end() // fingers_crossed - ->booleanNode('stop_buffering')->defaultTrue()->end()// fingers_crossed - ->scalarNode('passthru_level')->defaultNull()->end() // fingers_crossed - ->arrayNode('excluded_404s') // fingers_crossed - ->canBeUnset() - ->prototype('scalar')->end() - ->end() - ->arrayNode('excluded_http_codes') // fingers_crossed - ->canBeUnset() - ->beforeNormalization() - ->always(function ($values) { - return array_map(function ($value) { - /* - * Allows YAML: - * excluded_http_codes: [403, 404, { 400: ['^/foo', '^/bar'] }] - * - * and XML: - * - * ^/foo - * ^/bar - * - * - */ - - if (is_array($value)) { - return isset($value['code']) ? $value : ['code' => key($value), 'urls' => current($value)]; - } - - return ['code' => $value, 'urls' => []]; - }, $values); - }) - ->end() - ->prototype('array') - ->children() - ->scalarNode('code')->end() - ->arrayNode('urls') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->end() - ->arrayNode('accepted_levels') // filter - ->canBeUnset() - ->prototype('scalar')->end() - ->end() - ->scalarNode('min_level')->defaultValue('DEBUG')->end() // filter - ->scalarNode('max_level')->defaultValue('EMERGENCY')->end() //filter - ->scalarNode('buffer_size')->defaultValue(0)->end() // fingers_crossed and buffer - ->booleanNode('flush_on_overflow')->defaultFalse()->end() // buffer - ->scalarNode('handler')->end() // fingers_crossed and buffer - ->scalarNode('url')->end() // cube - ->scalarNode('exchange')->end() // amqp - ->scalarNode('exchange_name')->defaultValue('log')->end() // amqp - ->scalarNode('room')->end() // hipchat - ->scalarNode('message_format')->defaultValue('text')->end() // hipchat - ->scalarNode('api_version')->defaultNull()->end() // hipchat - ->scalarNode('channel')->defaultNull()->end() // slack & slackwebhook & slackbot - ->scalarNode('bot_name')->defaultValue('Monolog')->end() // slack & slackwebhook - ->scalarNode('use_attachment')->defaultTrue()->end() // slack & slackwebhook - ->scalarNode('use_short_attachment')->defaultFalse()->end() // slack & slackwebhook - ->scalarNode('include_extra')->defaultFalse()->end() // slack & slackwebhook - ->scalarNode('icon_emoji')->defaultNull()->end() // slack & slackwebhook - ->scalarNode('webhook_url')->end() // slackwebhook - ->scalarNode('team')->end() // slackbot - ->scalarNode('notify')->defaultFalse()->end() // hipchat - ->scalarNode('nickname')->defaultValue('Monolog')->end() // hipchat - ->scalarNode('token')->end() // pushover & hipchat & loggly & logentries & flowdock & rollbar & slack & slackbot & insightops - ->scalarNode('region')->end() // insightops - ->scalarNode('source')->end() // flowdock - ->booleanNode('use_ssl')->defaultTrue()->end() // logentries & hipchat & insightops - ->variableNode('user') // pushover - ->validate() - ->ifTrue(function ($v) { - return !is_string($v) && !is_array($v); - }) - ->thenInvalid('User must be a string or an array.') - ->end() - ->end() - ->scalarNode('title')->defaultNull()->end() // pushover - ->scalarNode('host')->defaultNull()->end() // syslogudp & hipchat - ->scalarNode('port')->defaultValue(514)->end() // syslogudp - ->arrayNode('publisher') - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['id' => $v]; }) - ->end() - ->children() - ->scalarNode('id')->end() - ->scalarNode('hostname')->end() - ->scalarNode('port')->defaultValue(12201)->end() - ->scalarNode('chunk_size')->defaultValue(1420)->end() - ->end() - ->validate() - ->ifTrue(function ($v) { - return !isset($v['id']) && !isset($v['hostname']); - }) - ->thenInvalid('What must be set is either the hostname or the id.') - ->end() - ->end() // gelf - ->arrayNode('mongo') - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['id' => $v]; }) - ->end() - ->children() - ->scalarNode('id')->end() - ->scalarNode('host')->end() - ->scalarNode('port')->defaultValue(27017)->end() - ->scalarNode('user')->end() - ->scalarNode('pass')->end() - ->scalarNode('database')->defaultValue('monolog')->end() - ->scalarNode('collection')->defaultValue('logs')->end() - ->end() - ->validate() - ->ifTrue(function ($v) { - return !isset($v['id']) && !isset($v['host']); - }) - ->thenInvalid('What must be set is either the host or the id.') - ->end() - ->validate() - ->ifTrue(function ($v) { - return isset($v['user']) && !isset($v['pass']); - }) - ->thenInvalid('If you set user, you must provide a password.') - ->end() - ->end() // mongo - ->arrayNode('elasticsearch') - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['id' => $v]; }) - ->end() - ->children() - ->scalarNode('id')->end() - ->scalarNode('host')->end() - ->scalarNode('port')->defaultValue(9200)->end() - ->scalarNode('transport')->defaultValue('Http')->end() - ->scalarNode('user')->defaultNull()->end() - ->scalarNode('password')->defaultNull()->end() - ->end() - ->validate() - ->ifTrue(function ($v) { - return !isset($v['id']) && !isset($v['host']); - }) - ->thenInvalid('What must be set is either the host or the id.') - ->end() - ->end() // elasticsearch - ->scalarNode('index')->defaultValue('monolog')->end() // elasticsearch - ->scalarNode('document_type')->defaultValue('logs')->end() // elasticsearch - ->scalarNode('ignore_error')->defaultValue(false)->end() // elasticsearch - ->arrayNode('redis') - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['id' => $v]; }) - ->end() - ->children() - ->scalarNode('id')->end() - ->scalarNode('host')->end() - ->scalarNode('password')->defaultNull()->end() - ->scalarNode('port')->defaultValue(6379)->end() - ->scalarNode('database')->defaultValue(0)->end() - ->scalarNode('key_name')->defaultValue('monolog_redis')->end() - ->end() - ->validate() - ->ifTrue(function ($v) { - return !isset($v['id']) && !isset($v['host']); - }) - ->thenInvalid('What must be set is either the host or the service id of the Redis client.') - ->end() - ->end() // redis - ->arrayNode('predis') - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['id' => $v]; }) - ->end() - ->children() - ->scalarNode('id')->end() - ->scalarNode('host')->end() - ->end() - ->validate() - ->ifTrue(function ($v) { - return !isset($v['id']) && !isset($v['host']); - }) - ->thenInvalid('What must be set is either the host or the service id of the Predis client.') - ->end() - ->end() // predis - ->arrayNode('config') - ->canBeUnset() + ->scalarNode('code')->end() + ->arrayNode('urls') ->prototype('scalar')->end() - ->end() // rollbar - ->arrayNode('members') // group, whatfailuregroup - ->canBeUnset() - ->performNoDeepMerging() - ->prototype('scalar')->end() - ->end() - ->scalarNode('from_email')->end() // swift_mailer, native_mailer, symfony_mailer and flowdock - ->arrayNode('to_email') // swift_mailer, native_mailer and symfony_mailer - ->prototype('scalar')->end() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return [$v]; }) - ->end() - ->end() - ->scalarNode('subject')->end() // swift_mailer, native_mailer and symfony_mailer - ->scalarNode('content_type')->defaultNull()->end() // swift_mailer and symfony_mailer - ->arrayNode('headers') // native_mailer - ->canBeUnset() - ->scalarPrototype()->end() - ->end() - ->scalarNode('mailer')->defaultNull()->end() // swift_mailer and symfony_mailer - ->arrayNode('email_prototype') // swift_mailer and symfony_mailer - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['id' => $v]; }) - ->end() - ->children() - ->scalarNode('id')->isRequired()->end() - ->scalarNode('method')->defaultNull()->end() - ->end() - ->end() - ->booleanNode('lazy')->defaultValue(true)->end() // swift_mailer - ->scalarNode('connection_string')->end() // socket_handler - ->scalarNode('timeout')->end() // socket_handler, logentries, pushover, hipchat & slack - ->scalarNode('time')->defaultValue(60)->end() // deduplication - ->scalarNode('deduplication_level')->defaultValue(Logger::ERROR)->end() // deduplication - ->scalarNode('store')->defaultNull()->end() // deduplication - ->scalarNode('connection_timeout')->end() // socket_handler, logentries, pushover, hipchat & slack - ->booleanNode('persistent')->end() // socket_handler - ->scalarNode('dsn')->end() // raven_handler, sentry_handler - ->scalarNode('client_id')->defaultNull()->end() // raven_handler, sentry_handler - ->scalarNode('auto_log_stacks')->defaultFalse()->end() // raven_handler - ->scalarNode('release')->defaultNull()->end() // raven_handler, sentry_handler - ->scalarNode('environment')->defaultNull()->end() // raven_handler, sentry_handler - ->scalarNode('message_type')->defaultValue(0)->end() // error_log - ->arrayNode('tags') // loggly - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return explode(',', $v); }) - ->end() - ->beforeNormalization() - ->ifArray() - ->then(function ($v) { return array_filter(array_map('trim', $v)); }) - ->end() - ->prototype('scalar')->end() - ->end() - // console - ->variableNode('console_formater_options') - ->defaultValue([]) - ->validate() - ->ifTrue(function ($v) { - return !is_array($v); - }) - ->thenInvalid('console_formater_options must an array.') - ->end() - ->end() - ->arrayNode('verbosity_levels') // console - ->beforeNormalization() - ->ifArray() - ->then(function ($v) { - $map = []; - $verbosities = ['VERBOSITY_QUIET', 'VERBOSITY_NORMAL', 'VERBOSITY_VERBOSE', 'VERBOSITY_VERY_VERBOSE', 'VERBOSITY_DEBUG']; - // allow numeric indexed array with ascendning verbosity and lowercase names of the constants - foreach ($v as $verbosity => $level) { - if (is_int($verbosity) && isset($verbosities[$verbosity])) { - $map[$verbosities[$verbosity]] = strtoupper($level); - } else { - $map[strtoupper($verbosity)] = strtoupper($level); - } - } - - return $map; - }) - ->end() - ->children() - ->scalarNode('VERBOSITY_QUIET')->defaultValue('ERROR')->end() - ->scalarNode('VERBOSITY_NORMAL')->defaultValue('WARNING')->end() - ->scalarNode('VERBOSITY_VERBOSE')->defaultValue('NOTICE')->end() - ->scalarNode('VERBOSITY_VERY_VERBOSE')->defaultValue('INFO')->end() - ->scalarNode('VERBOSITY_DEBUG')->defaultValue('DEBUG')->end() - ->end() - ->validate() - ->always(function ($v) { - $map = []; - foreach ($v as $verbosity => $level) { - $verbosityConstant = 'Symfony\Component\Console\Output\OutputInterface::'.$verbosity; - - if (!defined($verbosityConstant)) { - throw new InvalidConfigurationException(sprintf( - 'The configured verbosity "%s" is invalid as it is not defined in Symfony\Component\Console\Output\OutputInterface.', - $verbosity - )); - } - if (!is_numeric($level)) { - $levelConstant = 'Monolog\Logger::'.$level; - if (!defined($levelConstant)) { - throw new InvalidConfigurationException(sprintf( - 'The configured minimum log level "%s" for verbosity "%s" is invalid as it is not defined in Monolog\Logger.', - $level, $verbosity - )); - } - $level = constant($levelConstant); - } else { - $level = (int) $level; - } - - $map[constant($verbosityConstant)] = $level; - } - - return $map; - }) - ->end() ->end() - ->arrayNode('channels') - ->fixXmlConfig('channel', 'elements') - ->canBeUnset() - ->beforeNormalization() - ->ifString() - ->then(function ($v) { return ['elements' => [$v]]; }) - ->end() - ->beforeNormalization() - ->ifTrue(function ($v) { return is_array($v) && is_numeric(key($v)); }) - ->then(function ($v) { return ['elements' => $v]; }) - ->end() - ->validate() - ->ifTrue(function ($v) { return empty($v); }) - ->thenUnset() - ->end() - ->validate() - ->always(function ($v) { - $isExclusive = null; - if (isset($v['type'])) { - $isExclusive = 'exclusive' === $v['type']; - } - - $elements = []; - foreach ($v['elements'] as $element) { - if (0 === strpos($element, '!')) { - if (false === $isExclusive) { - throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list.'); - } - $elements[] = substr($element, 1); - $isExclusive = true; - } else { - if (true === $isExclusive) { - throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list'); - } - $elements[] = $element; - $isExclusive = false; - } - } - - if (!count($elements)) { - return null; - } - - return ['type' => $isExclusive ? 'exclusive' : 'inclusive', 'elements' => $elements]; - }) - ->end() - ->children() - ->scalarNode('type') - ->validate() - ->ifNotInArray(['inclusive', 'exclusive']) - ->thenInvalid('The type of channels has to be inclusive or exclusive') - ->end() - ->end() - ->arrayNode('elements') - ->prototype('scalar')->end() - ->end() - ->end() - ->end() - ->scalarNode('formatter')->end() - ->booleanNode('nested')->defaultFalse()->end() - ->end() - ->validate() - ->ifTrue(function ($v) { return 'service' === $v['type'] && !empty($v['formatter']); }) - ->thenInvalid('Service handlers can not have a formatter configured in the bundle, you must reconfigure the service itself instead') - ->end() - ->validate() - ->ifTrue(function ($v) { return ('fingers_crossed' === $v['type'] || 'buffer' === $v['type'] || 'filter' === $v['type']) && empty($v['handler']); }) - ->thenInvalid('The handler has to be specified to use a FingersCrossedHandler or BufferHandler or FilterHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'fingers_crossed' === $v['type'] && !empty($v['excluded_404s']) && !empty($v['activation_strategy']); }) - ->thenInvalid('You can not use excluded_404s together with a custom activation_strategy in a FingersCrossedHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'fingers_crossed' === $v['type'] && !empty($v['excluded_http_codes']) && !empty($v['activation_strategy']); }) - ->thenInvalid('You can not use excluded_http_codes together with a custom activation_strategy in a FingersCrossedHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'fingers_crossed' === $v['type'] && !empty($v['excluded_http_codes']) && !empty($v['excluded_404s']); }) - ->thenInvalid('You can not use excluded_http_codes together with excluded_404s in a FingersCrossedHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'fingers_crossed' !== $v['type'] && (!empty($v['excluded_http_codes']) || !empty($v['excluded_404s'])); }) - ->thenInvalid('You can only use excluded_http_codes/excluded_404s with a FingersCrossedHandler definition') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'filter' === $v['type'] && "DEBUG" !== $v['min_level'] && !empty($v['accepted_levels']); }) - ->thenInvalid('You can not use min_level together with accepted_levels in a FilterHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'filter' === $v['type'] && "EMERGENCY" !== $v['max_level'] && !empty($v['accepted_levels']); }) - ->thenInvalid('You can not use max_level together with accepted_levels in a FilterHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'rollbar' === $v['type'] && !empty($v['id']) && !empty($v['token']); }) - ->thenInvalid('You can not use both an id and a token in a RollbarHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'rollbar' === $v['type'] && empty($v['id']) && empty($v['token']); }) - ->thenInvalid('The id or the token has to be specified to use a RollbarHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'swift_mailer' === $v['type'] && empty($v['email_prototype']) && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); }) - ->thenInvalid('The sender, recipient and subject or an email prototype have to be specified to use a SwiftMailerHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'native_mailer' === $v['type'] && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); }) - ->thenInvalid('The sender, recipient and subject have to be specified to use a NativeMailerHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'symfony_mailer' === $v['type'] && empty($v['email_prototype']) && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); }) - ->thenInvalid('The sender, recipient and subject or an email prototype have to be specified to use the Symfony MailerHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'service' === $v['type'] && !isset($v['id']); }) - ->thenInvalid('The id has to be specified to use a service as handler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'syslogudp' === $v['type'] && !isset($v['host']); }) - ->thenInvalid('The host has to be specified to use a syslogudp as handler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'gelf' === $v['type'] && !isset($v['publisher']); }) - ->thenInvalid('The publisher has to be specified to use a GelfHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'socket' === $v['type'] && !isset($v['connection_string']); }) - ->thenInvalid('The connection_string has to be specified to use a SocketHandler') ->end() - ->validate() - ->ifTrue(function ($v) { return 'pushover' === $v['type'] && (empty($v['token']) || empty($v['user'])); }) - ->thenInvalid('The token and user have to be specified to use a PushoverHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'raven' === $v['type'] && !array_key_exists('dsn', $v) && null === $v['client_id']; }) - ->thenInvalid('The DSN has to be specified to use a RavenHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'sentry' === $v['type'] && !array_key_exists('dsn', $v) && null === $v['client_id']; }) - ->thenInvalid('The DSN has to be specified to use Sentry\'s handler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'hipchat' === $v['type'] && (empty($v['token']) || empty($v['room'])); }) - ->thenInvalid('The token and room have to be specified to use a HipChatHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'hipchat' === $v['type'] && !in_array($v['message_format'], ['text', 'html']); }) - ->thenInvalid('The message_format has to be "text" or "html" in a HipChatHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'hipchat' === $v['type'] && null !== $v['api_version'] && !in_array($v['api_version'], ['v1', 'v2'], true); }) - ->thenInvalid('The api_version has to be "v1" or "v2" in a HipChatHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'slack' === $v['type'] && (empty($v['token']) || empty($v['channel'])); }) - ->thenInvalid('The token and channel have to be specified to use a SlackHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'slackwebhook' === $v['type'] && (empty($v['webhook_url'])); }) - ->thenInvalid('The webhook_url have to be specified to use a SlackWebhookHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'slackbot' === $v['type'] && (empty($v['team']) || empty($v['token']) || empty($v['channel'])); }) - ->thenInvalid('The team, token and channel have to be specified to use a SlackbotHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'cube' === $v['type'] && empty($v['url']); }) - ->thenInvalid('The url has to be specified to use a CubeHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'mongo' === $v['type'] && !isset($v['mongo']); }) - ->thenInvalid('The mongo configuration has to be specified to use a MongoHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'amqp' === $v['type'] && empty($v['exchange']); }) - ->thenInvalid('The exchange has to be specified to use a AmqpHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'loggly' === $v['type'] && empty($v['token']); }) - ->thenInvalid('The token has to be specified to use a LogglyHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'loggly' === $v['type'] && !empty($v['tags']); }) - ->then(function ($v) { - $invalidTags = preg_grep('/^[a-z0-9][a-z0-9\.\-_]*$/i', $v['tags'], PREG_GREP_INVERT); - if (!empty($invalidTags)) { - throw new InvalidConfigurationException(sprintf('The following Loggly tags are invalid: %s.', implode(', ', $invalidTags))); + ->end() + ->end() + ->arrayNode('accepted_levels') // filter + ->canBeUnset() + ->prototype('scalar')->end() + ->end() + ->scalarNode('min_level')->defaultValue('DEBUG')->end() // filter + ->scalarNode('max_level')->defaultValue('EMERGENCY')->end() //filter + ->scalarNode('buffer_size')->defaultValue(0)->end() // fingers_crossed and buffer + ->booleanNode('flush_on_overflow')->defaultFalse()->end() // buffer + ->scalarNode('handler')->end() // fingers_crossed and buffer + ->scalarNode('url')->end() // cube + ->scalarNode('exchange')->end() // amqp + ->scalarNode('exchange_name')->defaultValue('log')->end() // amqp + ->scalarNode('room')->end() // hipchat + ->scalarNode('message_format')->defaultValue('text')->end() // hipchat + ->scalarNode('api_version')->defaultNull()->end() // hipchat + ->scalarNode('channel')->defaultNull()->end() // slack & slackwebhook & slackbot & telegram + ->scalarNode('bot_name')->defaultValue('Monolog')->end() // slack & slackwebhook + ->scalarNode('use_attachment')->defaultTrue()->end() // slack & slackwebhook + ->scalarNode('use_short_attachment')->defaultFalse()->end() // slack & slackwebhook + ->scalarNode('include_extra')->defaultFalse()->end() // slack & slackwebhook + ->scalarNode('icon_emoji')->defaultNull()->end() // slack & slackwebhook + ->scalarNode('webhook_url')->end() // slackwebhook + ->scalarNode('team')->end() // slackbot + ->scalarNode('notify')->defaultFalse()->end() // hipchat + ->scalarNode('nickname')->defaultValue('Monolog')->end() // hipchat + ->scalarNode('token')->end() // pushover & hipchat & loggly & logentries & flowdock & rollbar & slack & slackbot & insightops & telegram + ->scalarNode('region')->end() // insightops + ->scalarNode('source')->end() // flowdock + ->booleanNode('use_ssl')->defaultTrue()->end() // logentries & hipchat & insightops + ->variableNode('user') // pushover + ->validate() + ->ifTrue(function ($v) { + return !is_string($v) && !is_array($v); + }) + ->thenInvalid('User must be a string or an array.') + ->end() + ->end() + ->scalarNode('title')->defaultNull()->end() // pushover + ->scalarNode('host')->defaultNull()->end() // syslogudp & hipchat + ->scalarNode('port')->defaultValue(514)->end() // syslogudp + ->arrayNode('config') + ->canBeUnset() + ->prototype('scalar')->end() + ->end() // rollbar + ->arrayNode('members') // group, whatfailuregroup, fallbackgroup + ->canBeUnset() + ->performNoDeepMerging() + ->prototype('scalar')->end() + ->end() + ->scalarNode('connection_string')->end() // socket_handler + ->scalarNode('timeout')->end() // socket_handler, logentries, pushover, hipchat & slack + ->scalarNode('time')->defaultValue(60)->end() // deduplication + ->scalarNode('deduplication_level')->defaultValue(Logger::ERROR)->end() // deduplication + ->scalarNode('store')->defaultNull()->end() // deduplication + ->scalarNode('connection_timeout')->end() // socket_handler, logentries, pushover, hipchat & slack + ->booleanNode('persistent')->end() // socket_handler + ->scalarNode('dsn')->end() // raven_handler, sentry_handler + ->scalarNode('hub_id')->defaultNull()->end() // sentry_handler + ->scalarNode('client_id')->defaultNull()->end() // raven_handler, sentry_handler + ->scalarNode('auto_log_stacks')->defaultFalse()->end() // raven_handler + ->scalarNode('release')->defaultNull()->end() // raven_handler, sentry_handler + ->scalarNode('environment')->defaultNull()->end() // raven_handler, sentry_handler + ->scalarNode('message_type')->defaultValue(0)->end() // error_log + ->scalarNode('parse_mode')->defaultNull()->end() // telegram + ->booleanNode('disable_webpage_preview')->defaultNull()->end() // telegram + ->booleanNode('disable_notification')->defaultNull()->end() // telegram + ->booleanNode('split_long_messages')->defaultFalse()->end() // telegram + ->booleanNode('delay_between_messages')->defaultFalse()->end() // telegram + ->arrayNode('tags') // loggly + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return explode(',', $v); }) + ->end() + ->beforeNormalization() + ->ifArray() + ->then(function ($v) { return array_filter(array_map('trim', $v)); }) + ->end() + ->prototype('scalar')->end() + ->end() + // console + ->variableNode('console_formater_options') + ->setDeprecated(...$this->getDeprecationMsg('"%path%.%node%" is deprecated, use "%path%.console_formatter_options" instead.', 3.7)) + ->validate() + ->ifTrue(function ($v) { + return !is_array($v); + }) + ->thenInvalid('The console_formater_options must be an array.') + ->end() + ->end() + ->variableNode('console_formatter_options') + ->defaultValue([]) + ->validate() + ->ifTrue(static function ($v) { return !is_array($v); }) + ->thenInvalid('The console_formatter_options must be an array.') + ->end() + ->end() + ->scalarNode('formatter')->end() + ->booleanNode('nested')->defaultFalse()->end() + ->end(); + + $this->addGelfSection($handlerNode); + $this->addMongoSection($handlerNode); + $this->addElasticsearchSection($handlerNode); + $this->addRedisSection($handlerNode); + $this->addPredisSection($handlerNode); + $this->addMailerSection($handlerNode); + $this->addVerbosityLevelSection($handlerNode); + $this->addChannelsSection($handlerNode); + + $handlerNode + ->beforeNormalization() + ->always(static function ($v) { + if (empty($v['console_formatter_options']) && !empty($v['console_formater_options'])) { + $v['console_formatter_options'] = $v['console_formater_options']; + } + + return $v; + }) + ->end() + ->validate() + ->always(static function ($v) { unset($v['console_formater_options']); return $v; }) + ->end() + ->validate() + ->ifTrue(function ($v) { return 'service' === $v['type'] && !empty($v['formatter']); }) + ->thenInvalid('Service handlers can not have a formatter configured in the bundle, you must reconfigure the service itself instead') + ->end() + ->validate() + ->ifTrue(function ($v) { return ('fingers_crossed' === $v['type'] || 'buffer' === $v['type'] || 'filter' === $v['type']) && empty($v['handler']); }) + ->thenInvalid('The handler has to be specified to use a FingersCrossedHandler or BufferHandler or FilterHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'fingers_crossed' === $v['type'] && !empty($v['excluded_404s']) && !empty($v['activation_strategy']); }) + ->thenInvalid('You can not use excluded_404s together with a custom activation_strategy in a FingersCrossedHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'fingers_crossed' === $v['type'] && !empty($v['excluded_http_codes']) && !empty($v['activation_strategy']); }) + ->thenInvalid('You can not use excluded_http_codes together with a custom activation_strategy in a FingersCrossedHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'fingers_crossed' === $v['type'] && !empty($v['excluded_http_codes']) && !empty($v['excluded_404s']); }) + ->thenInvalid('You can not use excluded_http_codes together with excluded_404s in a FingersCrossedHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'fingers_crossed' !== $v['type'] && (!empty($v['excluded_http_codes']) || !empty($v['excluded_404s'])); }) + ->thenInvalid('You can only use excluded_http_codes/excluded_404s with a FingersCrossedHandler definition') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'filter' === $v['type'] && "DEBUG" !== $v['min_level'] && !empty($v['accepted_levels']); }) + ->thenInvalid('You can not use min_level together with accepted_levels in a FilterHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'filter' === $v['type'] && "EMERGENCY" !== $v['max_level'] && !empty($v['accepted_levels']); }) + ->thenInvalid('You can not use max_level together with accepted_levels in a FilterHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'rollbar' === $v['type'] && !empty($v['id']) && !empty($v['token']); }) + ->thenInvalid('You can not use both an id and a token in a RollbarHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'rollbar' === $v['type'] && empty($v['id']) && empty($v['token']); }) + ->thenInvalid('The id or the token has to be specified to use a RollbarHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'telegram' === $v['type'] && (empty($v['token']) || empty($v['channel'])); }) + ->thenInvalid('The token and channel have to be specified to use a TelegramBotHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'service' === $v['type'] && !isset($v['id']); }) + ->thenInvalid('The id has to be specified to use a service as handler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'syslogudp' === $v['type'] && !isset($v['host']); }) + ->thenInvalid('The host has to be specified to use a syslogudp as handler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'socket' === $v['type'] && !isset($v['connection_string']); }) + ->thenInvalid('The connection_string has to be specified to use a SocketHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'pushover' === $v['type'] && (empty($v['token']) || empty($v['user'])); }) + ->thenInvalid('The token and user have to be specified to use a PushoverHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'raven' === $v['type'] && !array_key_exists('dsn', $v) && null === $v['client_id']; }) + ->thenInvalid('The DSN has to be specified to use a RavenHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'sentry' === $v['type'] && !array_key_exists('dsn', $v) && null === $v['hub_id'] && null === $v['client_id']; }) + ->thenInvalid('The DSN has to be specified to use Sentry\'s handler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'sentry' === $v['type'] && null !== $v['hub_id'] && null !== $v['client_id']; }) + ->thenInvalid('You can not use both a hub_id and a client_id in a Sentry handler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'hipchat' === $v['type'] && (empty($v['token']) || empty($v['room'])); }) + ->thenInvalid('The token and room have to be specified to use a HipChatHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'hipchat' === $v['type'] && !in_array($v['message_format'], ['text', 'html']); }) + ->thenInvalid('The message_format has to be "text" or "html" in a HipChatHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'hipchat' === $v['type'] && null !== $v['api_version'] && !in_array($v['api_version'], ['v1', 'v2'], true); }) + ->thenInvalid('The api_version has to be "v1" or "v2" in a HipChatHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'slack' === $v['type'] && (empty($v['token']) || empty($v['channel'])); }) + ->thenInvalid('The token and channel have to be specified to use a SlackHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'slackwebhook' === $v['type'] && (empty($v['webhook_url'])); }) + ->thenInvalid('The webhook_url have to be specified to use a SlackWebhookHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'slackbot' === $v['type'] && (empty($v['team']) || empty($v['token']) || empty($v['channel'])); }) + ->thenInvalid('The team, token and channel have to be specified to use a SlackbotHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'cube' === $v['type'] && empty($v['url']); }) + ->thenInvalid('The url has to be specified to use a CubeHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'amqp' === $v['type'] && empty($v['exchange']); }) + ->thenInvalid('The exchange has to be specified to use a AmqpHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'loggly' === $v['type'] && empty($v['token']); }) + ->thenInvalid('The token has to be specified to use a LogglyHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'loggly' === $v['type'] && !empty($v['tags']); }) + ->then(function ($v) { + $invalidTags = preg_grep('/^[a-z0-9][a-z0-9\.\-_]*$/i', $v['tags'], PREG_GREP_INVERT); + if (!empty($invalidTags)) { + throw new InvalidConfigurationException(sprintf('The following Loggly tags are invalid: %s.', implode(', ', $invalidTags))); + } + + return $v; + }) + ->end() + ->validate() + ->ifTrue(function ($v) { return 'logentries' === $v['type'] && empty($v['token']); }) + ->thenInvalid('The token has to be specified to use a LogEntriesHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'insightops' === $v['type'] && empty($v['token']); }) + ->thenInvalid('The token has to be specified to use a InsightOpsHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'flowdock' === $v['type'] && empty($v['token']); }) + ->thenInvalid('The token has to be specified to use a FlowdockHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'flowdock' === $v['type'] && empty($v['from_email']); }) + ->thenInvalid('The from_email has to be specified to use a FlowdockHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'flowdock' === $v['type'] && empty($v['source']); }) + ->thenInvalid('The source has to be specified to use a FlowdockHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'server_log' === $v['type'] && empty($v['host']); }) + ->thenInvalid('The host has to be specified to use a ServerLogHandler') + ->end() + ; + + return $treeBuilder; + } + + private function addGelfSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('publisher') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['id' => $v]; }) + ->end() + ->children() + ->scalarNode('id')->end() + ->scalarNode('hostname')->end() + ->scalarNode('port')->defaultValue(12201)->end() + ->scalarNode('chunk_size')->defaultValue(1420)->end() + ->end() + ->validate() + ->ifTrue(function ($v) { + return !isset($v['id']) && !isset($v['hostname']); + }) + ->thenInvalid('What must be set is either the hostname or the id.') + ->end() + ->end() + ->end() + ->validate() + ->ifTrue(function ($v) { return 'gelf' === $v['type'] && !isset($v['publisher']); }) + ->thenInvalid('The publisher has to be specified to use a GelfHandler') + ->end() + ; + } + + private function addMongoSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('mongo') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['id' => $v]; }) + ->end() + ->children() + ->scalarNode('id')->end() + ->scalarNode('host')->end() + ->scalarNode('port')->defaultValue(27017)->end() + ->scalarNode('user')->end() + ->scalarNode('pass')->end() + ->scalarNode('database')->defaultValue('monolog')->end() + ->scalarNode('collection')->defaultValue('logs')->end() + ->end() + ->validate() + ->ifTrue(function ($v) { + return !isset($v['id']) && !isset($v['host']); + }) + ->thenInvalid('What must be set is either the host or the id.') + ->end() + ->validate() + ->ifTrue(function ($v) { + return isset($v['user']) && !isset($v['pass']); + }) + ->thenInvalid('If you set user, you must provide a password.') + ->end() + ->end() + ->end() + ->validate() + ->ifTrue(function ($v) { return 'mongo' === $v['type'] && !isset($v['mongo']); }) + ->thenInvalid('The mongo configuration has to be specified to use a MongoHandler') + ->end() + ; + } + + private function addElasticsearchSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('elasticsearch') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['id' => $v]; }) + ->end() + ->children() + ->scalarNode('id')->end() + ->scalarNode('host')->end() + ->scalarNode('port')->defaultValue(9200)->end() + ->scalarNode('transport')->defaultValue('Http')->end() + ->scalarNode('user')->defaultNull()->end() + ->scalarNode('password')->defaultNull()->end() + ->end() + ->validate() + ->ifTrue(function ($v) { + return !isset($v['id']) && !isset($v['host']); + }) + ->thenInvalid('What must be set is either the host or the id.') + ->end() + ->end() + ->scalarNode('index')->defaultValue('monolog')->end() // elasticsearch & elastic_search & elastica + ->scalarNode('document_type')->defaultValue('logs')->end() // elasticsearch & elastic_search & elastica + ->scalarNode('ignore_error')->defaultValue(false)->end() // elasticsearch & elastic_search & elastica + ->end() + ; + } + + private function addRedisSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('redis') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['id' => $v]; }) + ->end() + ->children() + ->scalarNode('id')->end() + ->scalarNode('host')->end() + ->scalarNode('password')->defaultNull()->end() + ->scalarNode('port')->defaultValue(6379)->end() + ->scalarNode('database')->defaultValue(0)->end() + ->scalarNode('key_name')->defaultValue('monolog_redis')->end() + ->end() + ->validate() + ->ifTrue(function ($v) { + return !isset($v['id']) && !isset($v['host']); + }) + ->thenInvalid('What must be set is either the host or the service id of the Redis client.') + ->end() + ->end() + ->end() + ->validate() + ->ifTrue(function ($v) { return 'redis' === $v['type'] && empty($v['redis']); }) + ->thenInvalid('The host has to be specified to use a RedisLogHandler') + ->end() + ; + } + + private function addPredisSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('predis') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['id' => $v]; }) + ->end() + ->children() + ->scalarNode('id')->end() + ->scalarNode('host')->end() + ->end() + ->validate() + ->ifTrue(function ($v) { + return !isset($v['id']) && !isset($v['host']); + }) + ->thenInvalid('What must be set is either the host or the service id of the Predis client.') + ->end() + ->end() + ->end() + ->validate() + ->ifTrue(function ($v) { return 'predis' === $v['type'] && empty($v['redis']); }) + ->thenInvalid('The host has to be specified to use a RedisLogHandler') + ->end() + ; + } + + private function addMailerSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->scalarNode('from_email')->end() // swift_mailer, native_mailer, symfony_mailer and flowdock + ->arrayNode('to_email') // swift_mailer, native_mailer and symfony_mailer + ->prototype('scalar')->end() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return [$v]; }) + ->end() + ->end() + ->scalarNode('subject')->end() // swift_mailer, native_mailer and symfony_mailer + ->scalarNode('content_type')->defaultNull()->end() // swift_mailer and symfony_mailer + ->arrayNode('headers') // native_mailer + ->canBeUnset() + ->scalarPrototype()->end() + ->end() + ->scalarNode('mailer')->defaultNull()->end() // swift_mailer and symfony_mailer + ->arrayNode('email_prototype') // swift_mailer and symfony_mailer + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['id' => $v]; }) + ->end() + ->children() + ->scalarNode('id')->isRequired()->end() + ->scalarNode('method')->defaultNull()->end() + ->end() + ->end() + ->booleanNode('lazy')->defaultValue(true)->end() // swift_mailer + ->end() + ->validate() + ->ifTrue(function ($v) { return 'swift_mailer' === $v['type'] && empty($v['email_prototype']) && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); }) + ->thenInvalid('The sender, recipient and subject or an email prototype have to be specified to use a SwiftMailerHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'native_mailer' === $v['type'] && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); }) + ->thenInvalid('The sender, recipient and subject have to be specified to use a NativeMailerHandler') + ->end() + ->validate() + ->ifTrue(function ($v) { return 'symfony_mailer' === $v['type'] && empty($v['email_prototype']) && (empty($v['from_email']) || empty($v['to_email']) || empty($v['subject'])); }) + ->thenInvalid('The sender, recipient and subject or an email prototype have to be specified to use the Symfony MailerHandler') + ->end() + ; + } + + private function addVerbosityLevelSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('verbosity_levels') // console + ->beforeNormalization() + ->ifArray() + ->then(function ($v) { + $map = []; + $verbosities = ['VERBOSITY_QUIET', 'VERBOSITY_NORMAL', 'VERBOSITY_VERBOSE', 'VERBOSITY_VERY_VERBOSE', 'VERBOSITY_DEBUG']; + // allow numeric indexed array with ascendning verbosity and lowercase names of the constants + foreach ($v as $verbosity => $level) { + if (is_int($verbosity) && isset($verbosities[$verbosity])) { + $map[$verbosities[$verbosity]] = strtoupper($level); + } else { + $map[strtoupper($verbosity)] = strtoupper($level); } + } - return $v; - }) - ->end() - ->validate() - ->ifTrue(function ($v) { return 'logentries' === $v['type'] && empty($v['token']); }) - ->thenInvalid('The token has to be specified to use a LogEntriesHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'insightops' === $v['type'] && empty($v['token']); }) - ->thenInvalid('The token has to be specified to use a InsightOpsHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'flowdock' === $v['type'] && empty($v['token']); }) - ->thenInvalid('The token has to be specified to use a FlowdockHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'flowdock' === $v['type'] && empty($v['from_email']); }) - ->thenInvalid('The from_email has to be specified to use a FlowdockHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'flowdock' === $v['type'] && empty($v['source']); }) - ->thenInvalid('The source has to be specified to use a FlowdockHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'server_log' === $v['type'] && empty($v['host']); }) - ->thenInvalid('The host has to be specified to use a ServerLogHandler') - ->end() - ->validate() - ->ifTrue(function ($v) { return 'redis' === $v['type'] && empty($v['redis']); }) - ->thenInvalid('The host has to be specified to use a RedisLogHandler') + return $map; + }) + ->end() + ->children() + ->scalarNode('VERBOSITY_QUIET')->defaultValue('ERROR')->end() + ->scalarNode('VERBOSITY_NORMAL')->defaultValue('WARNING')->end() + ->scalarNode('VERBOSITY_VERBOSE')->defaultValue('NOTICE')->end() + ->scalarNode('VERBOSITY_VERY_VERBOSE')->defaultValue('INFO')->end() + ->scalarNode('VERBOSITY_DEBUG')->defaultValue('DEBUG')->end() + ->end() + ->validate() + ->always(function ($v) { + $map = []; + foreach ($v as $verbosity => $level) { + $verbosityConstant = 'Symfony\Component\Console\Output\OutputInterface::'.$verbosity; + + if (!defined($verbosityConstant)) { + throw new InvalidConfigurationException(sprintf( + 'The configured verbosity "%s" is invalid as it is not defined in Symfony\Component\Console\Output\OutputInterface.', + $verbosity + )); + } + + try { + if (Logger::API === 3) { + $level = Logger::toMonologLevel($level)->value; + } else { + $level = Logger::toMonologLevel(is_numeric($level) ? (int) $level : $level); + } + } catch (\Psr\Log\InvalidArgumentException $e) { + throw new InvalidConfigurationException(sprintf( + 'The configured minimum log level "%s" for verbosity "%s" is invalid as it is not defined in Monolog\Logger.', + $level, $verbosity + )); + } + + $map[constant($verbosityConstant)] = $level; + } + + return $map; + }) + ->end() + ->end() + ->end() + ; + } + + private function addChannelsSection(ArrayNodeDefinition $handerNode) + { + $handerNode + ->children() + ->arrayNode('channels') + ->fixXmlConfig('channel', 'elements') + ->canBeUnset() + ->beforeNormalization() + ->ifString() + ->then(function ($v) { return ['elements' => [$v]]; }) + ->end() + ->beforeNormalization() + ->ifTrue(function ($v) { return is_array($v) && is_numeric(key($v)); }) + ->then(function ($v) { return ['elements' => $v]; }) + ->end() + ->validate() + ->ifTrue(function ($v) { return empty($v); }) + ->thenUnset() + ->end() + ->validate() + ->always(function ($v) { + $isExclusive = null; + if (isset($v['type'])) { + $isExclusive = 'exclusive' === $v['type']; + } + + $elements = []; + foreach ($v['elements'] as $element) { + if (0 === strpos($element, '!')) { + if (false === $isExclusive) { + throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list.'); + } + $elements[] = substr($element, 1); + $isExclusive = true; + } else { + if (true === $isExclusive) { + throw new InvalidConfigurationException('Cannot combine exclusive/inclusive definitions in channels list'); + } + $elements[] = $element; + $isExclusive = false; + } + } + + if (!count($elements)) { + return null; + } + + // de-duplicating $elements here in case the handlers are redefined, see https://github.com/symfony/monolog-bundle/issues/433 + return ['type' => $isExclusive ? 'exclusive' : 'inclusive', 'elements' => array_unique($elements)]; + }) + ->end() + ->children() + ->scalarNode('type') + ->validate() + ->ifNotInArray(['inclusive', 'exclusive']) + ->thenInvalid('The type of channels has to be inclusive or exclusive') + ->end() ->end() - ->validate() - ->ifTrue(function ($v) { return 'predis' === $v['type'] && empty($v['redis']); }) - ->thenInvalid('The host has to be specified to use a RedisLogHandler') + ->arrayNode('elements') + ->prototype('scalar')->end() ->end() ->end() - ->validate() - ->ifTrue(function ($v) { return isset($v['debug']); }) - ->thenInvalid('The "debug" name cannot be used as it is reserved for the handler of the profiler') - ->end() - ->example([ - 'syslog' => [ - 'type' => 'stream', - 'path' => '/var/log/symfony.log', - 'level' => 'ERROR', - 'bubble' => 'false', - 'formatter' => 'my_formatter', - ], - 'main' => [ - 'type' => 'fingers_crossed', - 'action_level' => 'WARNING', - 'buffer_size' => 30, - 'handler' => 'custom', - ], - 'custom' => [ - 'type' => 'service', - 'id' => 'my_handler', - ] - ]) ->end() ->end() ; + } - return $treeBuilder; + /** + * Returns the correct deprecation param's as an array for setDeprecated. + * + * Symfony/Config v5.1 introduces a deprecation notice when calling + * setDeprecation() with less than 3 args and the getDeprecation method was + * introduced at the same time. By checking if getDeprecation() exists, + * we can determine the correct param count to use when calling setDeprecated. + * + * @return array{0:string}|array{0:string, 1: numeric-string, string} + */ + private function getDeprecationMsg(string $message, string $version): array + { + if (method_exists(BaseNode::class, 'getDeprecation')) { + return [ + 'symfony/monolog-bundle', + $version, + $message, + ]; + } + + return [$message]; } } diff --git a/vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php b/vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php index 3e24d1fd..7d766714 100644 --- a/vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php +++ b/vendor/symfony/monolog-bundle/DependencyInjection/MonologExtension.php @@ -11,16 +11,21 @@ namespace Symfony\Bundle\MonologBundle\DependencyInjection; +use Monolog\Attribute\AsMonologProcessor; +use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy; +use Monolog\Handler\HandlerInterface; use Monolog\Logger; use Monolog\Processor\ProcessorInterface; -use Monolog\Handler\HandlerInterface; +use Monolog\Processor\PsrLogMessageProcessor; use Monolog\ResettableInterface; use Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy; +use Symfony\Bridge\Monolog\Processor\SwitchUserTokenProcessor; use Symfony\Bridge\Monolog\Processor\TokenProcessor; use Symfony\Bridge\Monolog\Processor\WebProcessor; use Symfony\Bundle\FullStack; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\Argument\BoundArgument; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; @@ -62,7 +67,7 @@ private function levelToMonologConst($level, ContainerBuilder $container) throw new \InvalidArgumentException(sprintf('Could not match "%s" to a log level.', $level)); } - if ($logLevel !== '') { + if ($logLevel !== '' && $logLevel !== $level) { return $this->levelToMonologConst($logLevel, $container); } @@ -120,24 +125,6 @@ public function load(array $configs, ContainerBuilder $container) } } $container->setParameter('monolog.handlers_to_channels', $handlersToChannels); - - if (PHP_VERSION_ID < 70000) { - $this->addClassesToCompile([ - 'Monolog\\Formatter\\FormatterInterface', - 'Monolog\\Formatter\\LineFormatter', - 'Monolog\\Handler\\HandlerInterface', - 'Monolog\\Handler\\AbstractHandler', - 'Monolog\\Handler\\AbstractProcessingHandler', - 'Monolog\\Handler\\StreamHandler', - 'Monolog\\Handler\\FingersCrossedHandler', - 'Monolog\\Handler\\FilterHandler', - 'Monolog\\Handler\\TestHandler', - 'Monolog\\Logger', - 'Symfony\\Bridge\\Monolog\\Logger', - 'Monolog\\Handler\\FingersCrossed\\ActivationStrategyInterface', - 'Monolog\\Handler\\FingersCrossed\\ErrorLevelActivationStrategy', - ]); - } } $container->setParameter('monolog.additional_channels', isset($config['channels']) ? $config['channels'] : []); @@ -150,6 +137,10 @@ public function load(array $configs, ContainerBuilder $container) $container->registerForAutoconfiguration(WebProcessor::class) ->addTag('monolog.processor'); } + if (interface_exists(ResettableInterface::class)) { + $container->registerForAutoconfiguration(ResettableInterface::class) + ->addTag('kernel.reset', ['method' => 'reset']); + } $container->registerForAutoconfiguration(TokenProcessor::class) ->addTag('monolog.processor'); if (interface_exists(HttpClientInterface::class)) { @@ -159,6 +150,21 @@ public function load(array $configs, ContainerBuilder $container) ]); } } + + if (80000 <= \PHP_VERSION_ID && method_exists($container, 'registerAttributeForAutoconfiguration')) { + $container->registerAttributeForAutoconfiguration(AsMonologProcessor::class, static function (ChildDefinition $definition, AsMonologProcessor $attribute, \Reflector $reflector): void { + $tagAttributes = get_object_vars($attribute); + if ($reflector instanceof \ReflectionMethod) { + if (isset($tagAttributes['method'])) { + throw new \LogicException(sprintf('AsMonologProcessor attribute cannot declare a method on "%s::%s()".', $reflector->class, $reflector->name)); + } + + $tagAttributes['method'] = $reflector->getName(); + } + + $definition->addTag('monolog.processor', $tagAttributes); + }); + } } /** @@ -198,18 +204,12 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $definition->setConfigurator(['Symfony\\Bundle\\MonologBundle\\MonologBundle', 'includeStacktraces']); } - if (null === $handler['process_psr_3_messages']) { - $handler['process_psr_3_messages'] = !isset($handler['handler']) && !$handler['members']; + if (null === $handler['process_psr_3_messages']['enabled']) { + $handler['process_psr_3_messages']['enabled'] = !isset($handler['handler']) && !$handler['members']; } - if ($handler['process_psr_3_messages']) { - $processorId = 'monolog.processor.psr_log_message'; - if (!$container->hasDefinition($processorId)) { - $processor = new Definition('Monolog\\Processor\\PsrLogMessageProcessor'); - $processor->setPublic(false); - $container->setDefinition($processorId, $processor); - } - + if ($handler['process_psr_3_messages']['enabled'] && method_exists($handlerClass, 'pushProcessor')) { + $processorId = $this->buildPsrLogMessageProcessor($container, $handler['process_psr_3_messages']); $definition->addMethodCall('pushProcessor', [new Reference($processorId)]); } @@ -229,11 +229,12 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler null, $handler['bubble'], isset($handler['verbosity_levels']) ? $handler['verbosity_levels'] : [], - $handler['console_formater_options'] + $handler['console_formatter_options'] ]); $definition->addTag('kernel.event_subscriber'); break; + case 'chromephp': case 'firephp': $definition->setArguments([ $handler['level'], @@ -287,7 +288,7 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $server .= $handler['mongo']['host'].':'.$handler['mongo']['port']; - $client = new Definition('MongoClient', [ + $client = new Definition('MongoDB\Client', [ $server, ]); @@ -304,38 +305,52 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler break; case 'elasticsearch': + @trigger_error('The "elasticsearch" handler type is deprecated in MonologBundle since version 3.8.0, use the "elastica" type instead, or switch to the official Elastic client using the "elastic_search" type.', E_USER_DEPRECATED); + // no break + + case 'elastica': + case 'elastic_search': if (isset($handler['elasticsearch']['id'])) { - $elasticaClient = new Reference($handler['elasticsearch']['id']); + $client = new Reference($handler['elasticsearch']['id']); } else { - // elastica client new definition - $elasticaClient = new Definition('Elastica\Client'); - $elasticaClientArguments = [ - 'host' => $handler['elasticsearch']['host'], - 'port' => $handler['elasticsearch']['port'], - 'transport' => $handler['elasticsearch']['transport'], - ]; - - if (isset($handler['elasticsearch']['user']) && isset($handler['elasticsearch']['password'])) { - $elasticaClientArguments = array_merge( - $elasticaClientArguments, - [ - 'headers' => [ - 'Authorization' => 'Basic ' . base64_encode($handler['elasticsearch']['user'] . ':' . $handler['elasticsearch']['password']) - ] - ] - ); + if ($handler['type'] === 'elastic_search') { + // v8 has a new Elastic\ prefix + $client = new Definition(class_exists('Elastic\Elasticsearch\Client') ? 'Elastic\Elasticsearch\Client' : 'Elasticsearch\Client'); + $factory = class_exists('Elastic\Elasticsearch\ClientBuilder') ? 'Elastic\Elasticsearch\ClientBuilder' : 'Elasticsearch\ClientBuilder'; + $client->setFactory([$factory, 'fromConfig']); + $clientArguments = [ + 'host' => $handler['elasticsearch']['host'], + ]; + + if (isset($handler['elasticsearch']['user'], $handler['elasticsearch']['password'])) { + $clientArguments['basicAuthentication'] = [$handler['elasticsearch']['user'], $handler['elasticsearch']['password']]; + } + } else { + $client = new Definition('Elastica\Client'); + + $clientArguments = [ + 'host' => $handler['elasticsearch']['host'], + 'port' => $handler['elasticsearch']['port'], + 'transport' => $handler['elasticsearch']['transport'], + ]; + + if (isset($handler['elasticsearch']['user'], $handler['elasticsearch']['password'])) { + $clientArguments['headers'] = [ + 'Authorization' => 'Basic ' . base64_encode($handler['elasticsearch']['user'] . ':' . $handler['elasticsearch']['password']) + ]; + } } - $elasticaClient->setArguments([ - $elasticaClientArguments + $client->setArguments([ + $clientArguments ]); - $elasticaClient->setPublic(false); + $client->setPublic(false); } // elastica handler definition $definition->setArguments([ - $elasticaClient, + $client, [ 'index' => $handler['index'], 'type' => $handler['document_type'], @@ -345,6 +360,25 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $handler['bubble'], ]); break; + + case 'telegram': + if (!class_exists('Monolog\Handler\TelegramBotHandler')) { + throw new \RuntimeException('The TelegramBotHandler is not available. Please update "monolog/monolog" to 2.2.0'); + } + + $definition->setArguments([ + $handler['token'], + $handler['channel'], + $handler['level'], + $handler['bubble'], + $handler['parse_mode'], + $handler['disable_webpage_preview'], + $handler['disable_notification'], + $handler['split_long_messages'], + $handler['delay_between_messages'], + ]); + break; + case 'redis': case 'predis': if (isset($handler['redis']['id'])) { @@ -383,14 +417,6 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler ]); break; - case 'chromephp': - $definition->setArguments([ - $handler['level'], - $handler['bubble'], - ]); - $definition->addTag('kernel.event_listener', ['event' => 'kernel.response', 'method' => 'onKernelResponse']); - break; - case 'rotating_file': $definition->setArguments([ $handler['path'], @@ -398,6 +424,7 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $handler['level'], $handler['bubble'], $handler['file_permission'], + $handler['use_locking'], ]); $definition->addMethodCall('setFilenameFormat', [ $handler['filename_format'], @@ -413,6 +440,11 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $nestedHandlerId = $this->getHandlerId($handler['handler']); $this->markNestedHandler($nestedHandlerId); + $activation = $handler['action_level']; + if (class_exists(SwitchUserTokenProcessor::class)) { + $activation = new Definition(ErrorLevelActivationStrategy::class, [$activation]); + } + if (isset($handler['activation_strategy'])) { $activation = new Reference($handler['activation_strategy']); } elseif (!empty($handler['excluded_404s'])) { @@ -422,7 +454,7 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $activationDef = new Definition('Symfony\Bridge\Monolog\Handler\FingersCrossed\NotFoundActivationStrategy', [ new Reference('request_stack'), $handler['excluded_404s'], - $handler['action_level'] + $activation ]); $container->setDefinition($handlerId.'.not_found_strategy', $activationDef); $activation = new Reference($handlerId.'.not_found_strategy'); @@ -433,12 +465,10 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $activationDef = new Definition('Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy', [ new Reference('request_stack'), $handler['excluded_http_codes'], - $handler['action_level'] + $activation ]); $container->setDefinition($handlerId.'.http_code_strategy', $activationDef); $activation = new Reference($handlerId.'.http_code_strategy'); - } else { - $activation = $handler['action_level']; } $definition->setArguments([ @@ -733,47 +763,53 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler break; case 'sentry': - if (null !== $handler['client_id']) { - $clientId = $handler['client_id']; + if (null !== $handler['hub_id']) { + $hub = new Reference($handler['hub_id']); } else { - $options = new Definition( - 'Sentry\\Options', - [['dsn' => $handler['dsn']]] - ); + if (null !== $handler['client_id']) { + $clientId = $handler['client_id']; + } else { + $options = new Definition( + 'Sentry\\Options', + [['dsn' => $handler['dsn']]] + ); - if (!empty($handler['environment'])) { - $options->addMethodCall('setEnvironment', [$handler['environment']]); - } + if (!empty($handler['environment'])) { + $options->addMethodCall('setEnvironment', [$handler['environment']]); + } - if (!empty($handler['release'])) { - $options->addMethodCall('setRelease', [$handler['release']]); - } + if (!empty($handler['release'])) { + $options->addMethodCall('setRelease', [$handler['release']]); + } - $builder = new Definition('Sentry\\ClientBuilder', [$options]); + $builder = new Definition('Sentry\\ClientBuilder', [$options]); - $client = new Definition('Sentry\\Client'); - $client->setFactory([$builder, 'getClient']); + $client = new Definition('Sentry\\Client'); + $client->setFactory([$builder, 'getClient']); - $clientId = 'monolog.sentry.client.'.sha1($handler['dsn']); - $container->setDefinition($clientId, $client); + $clientId = 'monolog.sentry.client.'.sha1($handler['dsn']); + $container->setDefinition($clientId, $client); - if (!$container->hasAlias('Sentry\\ClientInterface')) { - $container->setAlias('Sentry\\ClientInterface', $clientId); + if (!$container->hasAlias('Sentry\\ClientInterface')) { + $container->setAlias('Sentry\\ClientInterface', $clientId); + } } - } - $hub = new Definition( - 'Sentry\\State\\Hub', - [new Reference($clientId)] - ); + $hub = new Definition( + 'Sentry\\State\\Hub', + [new Reference($clientId)] + ); + $container->setDefinition(sprintf('monolog.handler.%s.hub', $name), $hub); - // can't set the hub to the current hub, getting into a recursion otherwise... - //$hub->addMethodCall('setCurrent', array($hub)); + // can't set the hub to the current hub, getting into a recursion otherwise... + //$hub->addMethodCall('setCurrent', array($hub)); + } $definition->setArguments([ $hub, $handler['level'], $handler['bubble'], + $handler['fill_extra_context'], ]); break; @@ -901,6 +937,7 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler case 'browser_console': case 'test': case 'null': + case 'noop': case 'debug': $definition->setArguments([ $handler['level'], @@ -990,6 +1027,7 @@ private function getHandlerClassByType($handlerType) 'filter' => 'Monolog\Handler\FilterHandler', 'mongo' => 'Monolog\Handler\MongoDBHandler', 'elasticsearch' => 'Monolog\Handler\ElasticSearchHandler', + 'telegram' => 'Monolog\Handler\TelegramBotHandler', 'server_log' => 'Symfony\Bridge\Monolog\Handler\ServerLogHandler', 'redis' => 'Monolog\Handler\RedisHandler', 'predis' => 'Monolog\Handler\RedisHandler', @@ -997,15 +1035,11 @@ private function getHandlerClassByType($handlerType) ]; $v2HandlerTypesAdded = [ + 'elastica' => 'Monolog\Handler\ElasticaHandler', 'elasticsearch' => 'Monolog\Handler\ElasticaHandler', + 'elastic_search' => 'Monolog\Handler\ElasticsearchHandler', 'fallbackgroup' => 'Monolog\Handler\FallbackGroupHandler', - 'logmatic' => 'Monolog\Handler\LogmaticHandler', 'noop' => 'Monolog\Handler\NoopHandler', - 'overflow' => 'Monolog\Handler\OverflowHandler', - 'process' => 'Monolog\Handler\ProcessHandler', - 'sendgrid' => 'Monolog\Handler\SendGridHandler', - 'sqs' => 'Monolog\Handler\SqsHandler', - 'telegram' => 'Monolog\Handler\TelegramBotHandler', ]; $v2HandlerTypesRemoved = [ @@ -1014,25 +1048,75 @@ private function getHandlerClassByType($handlerType) 'slackbot', ]; - if (Logger::API === 2) { + $v3HandlerTypesRemoved = [ + 'swift_mailer', + ]; + + if (Logger::API >= 2) { $typeToClassMapping = array_merge($typeToClassMapping, $v2HandlerTypesAdded); foreach($v2HandlerTypesRemoved as $v2HandlerTypeRemoved) { unset($typeToClassMapping[$v2HandlerTypeRemoved]); } } + if (Logger::API >= 3) { + foreach($v3HandlerTypesRemoved as $v3HandlerTypeRemoved) { + unset($typeToClassMapping[$v3HandlerTypeRemoved]); + } + } + if (!isset($typeToClassMapping[$handlerType])) { if (Logger::API === 1 && array_key_exists($handlerType, $v2HandlerTypesAdded)) { throw new \InvalidArgumentException(sprintf('"%s" was added in Monolog v2, please upgrade if you wish to use it.', $handlerType)); } - if (Logger::API === 2 && array_key_exists($handlerType, $v2HandlerTypesRemoved)) { + if (Logger::API >= 2 && array_key_exists($handlerType, $v2HandlerTypesRemoved)) { throw new \InvalidArgumentException(sprintf('"%s" was removed in Monolog v2.', $handlerType)); } + if (Logger::API >= 3 && array_key_exists($handlerType, $v3HandlerTypesRemoved)) { + throw new \InvalidArgumentException(sprintf('"%s" was removed in Monolog v3.', $handlerType)); + } + throw new \InvalidArgumentException(sprintf('There is no handler class defined for handler "%s".', $handlerType)); } return $typeToClassMapping[$handlerType]; } + + private function buildPsrLogMessageProcessor(ContainerBuilder $container, array $processorOptions): string + { + static $hasConstructorArguments; + + if (!isset($hasConstructorArguments)) { + $reflectionConstructor = (new \ReflectionClass(PsrLogMessageProcessor::class))->getConstructor(); + $hasConstructorArguments = null !== $reflectionConstructor && $reflectionConstructor->getNumberOfParameters() > 0; + unset($reflectionConstructor); + } + + $processorId = 'monolog.processor.psr_log_message'; + $processorArguments = []; + + unset($processorOptions['enabled']); + + if (!empty($processorOptions)) { + if (!$hasConstructorArguments) { + throw new \RuntimeException('Monolog 1.26 or higher is required for the "date_format" and "remove_used_context_fields" options to be used.'); + } + $processorArguments = [ + $processorOptions['date_format'] ?? null, + $processorOptions['remove_used_context_fields'] ?? false, + ]; + $processorId .= '.'.ContainerBuilder::hash($processorArguments); + } + + if (!$container->hasDefinition($processorId)) { + $processor = new Definition(PsrLogMessageProcessor::class); + $processor->setPublic(false); + $processor->setArguments($processorArguments); + $container->setDefinition($processorId, $processor); + } + + return $processorId; + } } diff --git a/vendor/symfony/monolog-bundle/MonologBundle.php b/vendor/symfony/monolog-bundle/MonologBundle.php index ba159196..12e0cb67 100644 --- a/vendor/symfony/monolog-bundle/MonologBundle.php +++ b/vendor/symfony/monolog-bundle/MonologBundle.php @@ -23,8 +23,6 @@ use Symfony\Bundle\MonologBundle\DependencyInjection\Compiler\FixEmptyLoggerPass; /** - * Bundle. - * * @author Jordi Boggiano */ class MonologBundle extends Bundle diff --git a/vendor/symfony/monolog-bundle/Resources/config/schema/monolog-1.0.xsd b/vendor/symfony/monolog-bundle/Resources/config/schema/monolog-1.0.xsd index 38bb1401..b00e969e 100644 --- a/vendor/symfony/monolog-bundle/Resources/config/schema/monolog-1.0.xsd +++ b/vendor/symfony/monolog-bundle/Resources/config/schema/monolog-1.0.xsd @@ -29,6 +29,7 @@ + @@ -67,6 +68,7 @@ + @@ -191,7 +193,13 @@ - + + + + + + + diff --git a/vendor/symfony/monolog-bundle/composer.json b/vendor/symfony/monolog-bundle/composer.json index 5c6d810b..d30d233a 100644 --- a/vendor/symfony/monolog-bundle/composer.json +++ b/vendor/symfony/monolog-bundle/composer.json @@ -3,7 +3,7 @@ "type": "symfony-bundle", "description": "Symfony MonologBundle", "keywords": ["log", "logging"], - "homepage": "http://symfony.com", + "homepage": "https://symfony.com", "license": "MIT", "authors": [ { @@ -12,21 +12,21 @@ }, { "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" + "homepage": "https://symfony.com/contributors" } ], "require": { - "php": ">=5.6", - "symfony/monolog-bridge": "~3.4 || ~4.0 || ^5.0", - "symfony/dependency-injection": "~3.4.10 || ^4.0.10 || ^5.0", - "symfony/config": "~3.4 || ~4.0 || ^5.0", - "symfony/http-kernel": "~3.4 || ~4.0 || ^5.0", - "monolog/monolog": "~1.22 || ~2.0" + "php": ">=7.1.3", + "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0", + "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0", + "symfony/config": "~4.4 || ^5.0 || ^6.0", + "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0", + "monolog/monolog": "^1.22 || ^2.0 || ^3.0" }, "require-dev": { - "symfony/yaml": "~3.4 || ~4.0 || ^5.0", - "symfony/console": "~3.4 || ~4.0 || ^5.0", - "symfony/phpunit-bridge": "^4.4 || ^5.0" + "symfony/yaml": "~4.4 || ^5.0 || ^6.0", + "symfony/console": "~4.4 || ^5.0 || ^6.0", + "symfony/phpunit-bridge": "^5.2 || ^6.0" }, "autoload": { "psr-4": { "Symfony\\Bundle\\MonologBundle\\": "" }, diff --git a/vendor/symfony/polyfill-apcu/Apcu.php b/vendor/symfony/polyfill-apcu/Apcu.php deleted file mode 100644 index 4dc5bf9a..00000000 --- a/vendor/symfony/polyfill-apcu/Apcu.php +++ /dev/null @@ -1,106 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Polyfill\Apcu; - -/** - * Apcu for Zend Server Data Cache. - * - * @author Kate Gray - * @author Nicolas Grekas - * - * @internal - */ -final class Apcu -{ - public static function apcu_add($key, $var = null, $ttl = 0) - { - if (!\is_array($key)) { - return apc_add($key, $var, $ttl); - } - - $errors = []; - foreach ($key as $k => $v) { - if (!apc_add($k, $v, $ttl)) { - $errors[$k] = -1; - } - } - - return $errors; - } - - public static function apcu_store($key, $var = null, $ttl = 0) - { - if (!\is_array($key)) { - return apc_store($key, $var, $ttl); - } - - $errors = []; - foreach ($key as $k => $v) { - if (!apc_store($k, $v, $ttl)) { - $errors[$k] = -1; - } - } - - return $errors; - } - - public static function apcu_exists($keys) - { - if (!\is_array($keys)) { - return apc_exists($keys); - } - - $existing = []; - foreach ($keys as $k) { - if (apc_exists($k)) { - $existing[$k] = true; - } - } - - return $existing; - } - - public static function apcu_fetch($key, &$success = null) - { - if (!\is_array($key)) { - return apc_fetch($key, $success); - } - - $succeeded = true; - $values = []; - foreach ($key as $k) { - $v = apc_fetch($k, $success); - if ($success) { - $values[$k] = $v; - } else { - $succeeded = false; - } - } - $success = $succeeded; - - return $values; - } - - public static function apcu_delete($key) - { - if (!\is_array($key)) { - return apc_delete($key); - } - - $success = true; - foreach ($key as $k) { - $success = apc_delete($k) && $success; - } - - return $success; - } -} diff --git a/vendor/symfony/polyfill-apcu/LICENSE b/vendor/symfony/polyfill-apcu/LICENSE deleted file mode 100644 index 4cd8bdd3..00000000 --- a/vendor/symfony/polyfill-apcu/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2015-2019 Fabien Potencier - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is furnished -to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/symfony/polyfill-apcu/README.md b/vendor/symfony/polyfill-apcu/README.md deleted file mode 100644 index 57f4bf6b..00000000 --- a/vendor/symfony/polyfill-apcu/README.md +++ /dev/null @@ -1,12 +0,0 @@ -Symfony Polyfill / APCu -======================== - -This component provides `apcu_*` functions and the `APCuIterator` class to users of the legacy APC extension. - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-apcu/bootstrap.php b/vendor/symfony/polyfill-apcu/bootstrap.php deleted file mode 100644 index 96b2706a..00000000 --- a/vendor/symfony/polyfill-apcu/bootstrap.php +++ /dev/null @@ -1,83 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Polyfill\Apcu as p; - -if (!extension_loaded('apc') && !extension_loaded('apcu')) { - return; -} - -if (\PHP_VERSION_ID >= 80000) { - return require __DIR__.'/bootstrap80.php'; -} - -if (extension_loaded('Zend Data Cache')) { - if (!function_exists('apcu_add')) { - function apcu_add($key, $value = null, $ttl = 0) { return p\Apcu::apcu_add($key, $value, $ttl); } - } - if (!function_exists('apcu_delete')) { - function apcu_delete($key) { return p\Apcu::apcu_delete($key); } - } - if (!function_exists('apcu_exists')) { - function apcu_exists($key) { return p\Apcu::apcu_exists($key); } - } - if (!function_exists('apcu_fetch')) { - function apcu_fetch($key, &$success = null) { return p\Apcu::apcu_fetch($key, $success); } - } - if (!function_exists('apcu_store')) { - function apcu_store($key, $value = null, $ttl = 0) { return p\Apcu::apcu_store($key, $value, $ttl); } - } -} else { - if (!function_exists('apcu_add')) { - function apcu_add($key, $value = null, $ttl = 0) { return apc_add($key, $value, $ttl); } - } - if (!function_exists('apcu_delete')) { - function apcu_delete($key) { return apc_delete($key); } - } - if (!function_exists('apcu_exists')) { - function apcu_exists($key) { return apc_exists($key); } - } - if (!function_exists('apcu_fetch')) { - function apcu_fetch($key, &$success = null) { return apc_fetch($key, $success); } - } - if (!function_exists('apcu_store')) { - function apcu_store($key, $value = null, $ttl = 0) { return apc_store($key, $value, $ttl); } - } -} - -if (!function_exists('apcu_cache_info')) { - function apcu_cache_info($limited = false) { return apc_cache_info('user', $limited); } -} -if (!function_exists('apcu_cas')) { - function apcu_cas($key, $old, $new) { return apc_cas($key, $old, $new); } -} -if (!function_exists('apcu_clear_cache')) { - function apcu_clear_cache() { return apc_clear_cache('user'); } -} -if (!function_exists('apcu_dec')) { - function apcu_dec($key, $step = 1, &$success = false) { return apc_dec($key, $step, $success); } -} -if (!function_exists('apcu_inc')) { - function apcu_inc($key, $step = 1, &$success = false) { return apc_inc($key, $step, $success); } -} -if (!function_exists('apcu_sma_info')) { - function apcu_sma_info($limited = false) { return apc_sma_info($limited); } -} - -if (!class_exists('APCuIterator', false) && class_exists('APCIterator', false)) { - class APCuIterator extends APCIterator - { - public function __construct($search = null, $format = \APC_ITER_ALL, $chunk_size = 100, $list = \APC_LIST_ACTIVE) - { - parent::__construct('user', $search, $format, $chunk_size, $list); - } - } -} diff --git a/vendor/symfony/polyfill-apcu/bootstrap80.php b/vendor/symfony/polyfill-apcu/bootstrap80.php deleted file mode 100644 index 69e9f160..00000000 --- a/vendor/symfony/polyfill-apcu/bootstrap80.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -use Symfony\Polyfill\Apcu as p; - -if (extension_loaded('Zend Data Cache')) { - if (!function_exists('apcu_add')) { - function apcu_add($key, mixed $value, ?int $ttl = 0): array|bool { return p\Apcu::apcu_add($key, $value, (int) $ttl); } - } - if (!function_exists('apcu_delete')) { - function apcu_delete($key): array|bool { return p\Apcu::apcu_delete($key); } - } - if (!function_exists('apcu_exists')) { - function apcu_exists($key): array|bool { return p\Apcu::apcu_exists($key); } - } - if (!function_exists('apcu_fetch')) { - function apcu_fetch($key, &$success = null): mixed { return p\Apcu::apcu_fetch($key, $success); } - } - if (!function_exists('apcu_store')) { - function apcu_store($key, mixed $value, ?int $ttl = 0): array|bool { return p\Apcu::apcu_store($key, $value, (int) $ttl); } - } -} else { - if (!function_exists('apcu_add')) { - function apcu_add($key, mixed $value, ?int $ttl = 0): array|bool { return apc_add($key, $value, (int) $ttl); } - } - if (!function_exists('apcu_delete')) { - function apcu_delete($key): array|bool { return apc_delete($key); } - } - if (!function_exists('apcu_exists')) { - function apcu_exists($key): array|bool { return apc_exists($key); } - } - if (!function_exists('apcu_fetch')) { - function apcu_fetch($key, &$success = null) { return apc_fetch($key, $success); } - } - if (!function_exists('apcu_store')) { - function apcu_store($key, mixed $value, ?int $ttl = 0): array|bool { return apc_store($key, $value, (int) $ttl); } - } -} - -if (!function_exists('apcu_cache_info')) { - function apcu_cache_info($limited = false) { return apc_cache_info('user', $limited); } -} -if (!function_exists('apcu_cas')) { - function apcu_cas($key, $old, $new) { return apc_cas($key, $old, $new); } -} -if (!function_exists('apcu_clear_cache')) { - function apcu_clear_cache() { return apc_clear_cache('user'); } -} -if (!function_exists('apcu_dec')) { - function apcu_dec($key, $step = 1, &$success = false) { return apc_dec($key, $step, $success); } -} -if (!function_exists('apcu_inc')) { - function apcu_inc($key, $step = 1, &$success = false) { return apc_inc($key, $step, $success); } -} -if (!function_exists('apcu_sma_info')) { - function apcu_sma_info($limited = false) { return apc_sma_info($limited); } -} - -if (!class_exists('APCuIterator', false) && class_exists('APCIterator', false)) { - class APCuIterator extends APCIterator - { - public function __construct($search = null, $format = APC_ITER_ALL, $chunk_size = 100, $list = APC_LIST_ACTIVE) - { - parent::__construct('user', $search, $format, $chunk_size, $list); - } - } -} diff --git a/vendor/symfony/polyfill-apcu/composer.json b/vendor/symfony/polyfill-apcu/composer.json deleted file mode 100644 index 99c13030..00000000 --- a/vendor/symfony/polyfill-apcu/composer.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "symfony/polyfill-apcu", - "type": "library", - "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions", - "keywords": ["polyfill", "shim", "compatibility", "portable", "apcu"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=7.1" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Apcu\\": "" }, - "files": [ "bootstrap.php" ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - } -} diff --git a/vendor/symfony/polyfill-ctype/LICENSE b/vendor/symfony/polyfill-ctype/LICENSE index 3f853aaf..7536caea 100644 --- a/vendor/symfony/polyfill-ctype/LICENSE +++ b/vendor/symfony/polyfill-ctype/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/polyfill-ctype/composer.json b/vendor/symfony/polyfill-ctype/composer.json index 1b3efff5..e5c978f1 100644 --- a/vendor/symfony/polyfill-ctype/composer.json +++ b/vendor/symfony/polyfill-ctype/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", diff --git a/vendor/symfony/polyfill-mbstring/LICENSE b/vendor/symfony/polyfill-mbstring/LICENSE index 4cd8bdd3..6e3afce6 100644 --- a/vendor/symfony/polyfill-mbstring/LICENSE +++ b/vendor/symfony/polyfill-mbstring/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-present Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/polyfill-mbstring/Mbstring.php b/vendor/symfony/polyfill-mbstring/Mbstring.php index bce5c4a8..2e0b9694 100644 --- a/vendor/symfony/polyfill-mbstring/Mbstring.php +++ b/vendor/symfony/polyfill-mbstring/Mbstring.php @@ -69,7 +69,7 @@ final class Mbstring { public const MB_CASE_FOLD = \PHP_INT_MAX; - private const CASE_FOLD = [ + private const SIMPLE_CASE_FOLD = [ ['µ', 'ſ', "\xCD\x85", 'ς', "\xCF\x90", "\xCF\x91", "\xCF\x95", "\xCF\x96", "\xCF\xB0", "\xCF\xB1", "\xCF\xB5", "\xE1\xBA\x9B", "\xE1\xBE\xBE"], ['μ', 's', 'ι', 'σ', 'β', 'θ', 'φ', 'π', 'κ', 'ρ', 'ε', "\xE1\xB9\xA1", 'ι'], ]; @@ -301,7 +301,11 @@ public static function mb_convert_case($s, $mode, $encoding = null) $map = $upper; } else { if (self::MB_CASE_FOLD === $mode) { - $s = str_replace(self::CASE_FOLD[0], self::CASE_FOLD[1], $s); + static $caseFolding = null; + if (null === $caseFolding) { + $caseFolding = self::getData('caseFolding'); + } + $s = strtr($s, $caseFolding); } static $lower = null; @@ -406,6 +410,12 @@ public static function mb_encoding_aliases($encoding) public static function mb_check_encoding($var = null, $encoding = null) { + if (PHP_VERSION_ID < 70200 && \is_array($var)) { + trigger_error('mb_check_encoding() expects parameter 1 to be string, array given', \E_USER_WARNING); + + return null; + } + if (null === $encoding) { if (null === $var) { return false; @@ -413,7 +423,21 @@ public static function mb_check_encoding($var = null, $encoding = null) $encoding = self::$internalEncoding; } - return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + if (!\is_array($var)) { + return self::mb_detect_encoding($var, [$encoding]) || false !== @iconv($encoding, $encoding, $var); + } + + foreach ($var as $key => $value) { + if (!self::mb_check_encoding($key, $encoding)) { + return false; + } + if (!self::mb_check_encoding($value, $encoding)) { + return false; + } + } + + return true; + } public static function mb_detect_encoding($str, $encodingList = null, $strict = false) @@ -638,8 +662,10 @@ public static function mb_substr($s, $start, $length = null, $encoding = null) public static function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + [$haystack, $needle] = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], [ + self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding), + self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding), + ]); return self::mb_strpos($haystack, $needle, $offset, $encoding); } @@ -674,8 +700,11 @@ public static function mb_strrichr($haystack, $needle, $part = false, $encoding public static function mb_strripos($haystack, $needle, $offset = 0, $encoding = null) { - $haystack = self::mb_convert_case($haystack, self::MB_CASE_FOLD, $encoding); - $needle = self::mb_convert_case($needle, self::MB_CASE_FOLD, $encoding); + $haystack = self::mb_convert_case($haystack, \MB_CASE_LOWER, $encoding); + $needle = self::mb_convert_case($needle, \MB_CASE_LOWER, $encoding); + + $haystack = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $haystack); + $needle = str_replace(self::SIMPLE_CASE_FOLD[0], self::SIMPLE_CASE_FOLD[1], $needle); return self::mb_strrpos($haystack, $needle, $offset, $encoding); } @@ -798,6 +827,50 @@ public static function mb_ord($s, $encoding = null) return $code; } + public static function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = \STR_PAD_RIGHT, string $encoding = null): string + { + if (!\in_array($pad_type, [\STR_PAD_RIGHT, \STR_PAD_LEFT, \STR_PAD_BOTH], true)) { + throw new \ValueError('mb_str_pad(): Argument #4 ($pad_type) must be STR_PAD_LEFT, STR_PAD_RIGHT, or STR_PAD_BOTH'); + } + + if (null === $encoding) { + $encoding = self::mb_internal_encoding(); + } + + try { + $validEncoding = @self::mb_check_encoding('', $encoding); + } catch (\ValueError $e) { + throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + // BC for PHP 7.3 and lower + if (!$validEncoding) { + throw new \ValueError(sprintf('mb_str_pad(): Argument #5 ($encoding) must be a valid encoding, "%s" given', $encoding)); + } + + if (self::mb_strlen($pad_string, $encoding) <= 0) { + throw new \ValueError('mb_str_pad(): Argument #3 ($pad_string) must be a non-empty string'); + } + + $paddingRequired = $length - self::mb_strlen($string, $encoding); + + if ($paddingRequired < 1) { + return $string; + } + + switch ($pad_type) { + case \STR_PAD_LEFT: + return self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding).$string; + case \STR_PAD_RIGHT: + return $string.self::mb_substr(str_repeat($pad_string, $paddingRequired), 0, $paddingRequired, $encoding); + default: + $leftPaddingLength = floor($paddingRequired / 2); + $rightPaddingLength = $paddingRequired - $leftPaddingLength; + + return self::mb_substr(str_repeat($pad_string, $leftPaddingLength), 0, $leftPaddingLength, $encoding).$string.self::mb_substr(str_repeat($pad_string, $rightPaddingLength), 0, $rightPaddingLength, $encoding); + } + } + private static function getSubpart($pos, $part, $haystack, $encoding) { if (false === $pos) { diff --git a/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php b/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php new file mode 100644 index 00000000..512bba0b --- /dev/null +++ b/vendor/symfony/polyfill-mbstring/Resources/unidata/caseFolding.php @@ -0,0 +1,119 @@ + 'i̇', + 'µ' => 'μ', + 'ſ' => 's', + 'ͅ' => 'ι', + 'ς' => 'σ', + 'ϐ' => 'β', + 'ϑ' => 'θ', + 'ϕ' => 'φ', + 'ϖ' => 'π', + 'ϰ' => 'κ', + 'ϱ' => 'ρ', + 'ϵ' => 'ε', + 'ẛ' => 'ṡ', + 'ι' => 'ι', + 'ß' => 'ss', + 'ʼn' => 'ʼn', + 'ǰ' => 'ǰ', + 'ΐ' => 'ΐ', + 'ΰ' => 'ΰ', + 'և' => 'եւ', + 'ẖ' => 'ẖ', + 'ẗ' => 'ẗ', + 'ẘ' => 'ẘ', + 'ẙ' => 'ẙ', + 'ẚ' => 'aʾ', + 'ẞ' => 'ss', + 'ὐ' => 'ὐ', + 'ὒ' => 'ὒ', + 'ὔ' => 'ὔ', + 'ὖ' => 'ὖ', + 'ᾀ' => 'ἀι', + 'ᾁ' => 'ἁι', + 'ᾂ' => 'ἂι', + 'ᾃ' => 'ἃι', + 'ᾄ' => 'ἄι', + 'ᾅ' => 'ἅι', + 'ᾆ' => 'ἆι', + 'ᾇ' => 'ἇι', + 'ᾈ' => 'ἀι', + 'ᾉ' => 'ἁι', + 'ᾊ' => 'ἂι', + 'ᾋ' => 'ἃι', + 'ᾌ' => 'ἄι', + 'ᾍ' => 'ἅι', + 'ᾎ' => 'ἆι', + 'ᾏ' => 'ἇι', + 'ᾐ' => 'ἠι', + 'ᾑ' => 'ἡι', + 'ᾒ' => 'ἢι', + 'ᾓ' => 'ἣι', + 'ᾔ' => 'ἤι', + 'ᾕ' => 'ἥι', + 'ᾖ' => 'ἦι', + 'ᾗ' => 'ἧι', + 'ᾘ' => 'ἠι', + 'ᾙ' => 'ἡι', + 'ᾚ' => 'ἢι', + 'ᾛ' => 'ἣι', + 'ᾜ' => 'ἤι', + 'ᾝ' => 'ἥι', + 'ᾞ' => 'ἦι', + 'ᾟ' => 'ἧι', + 'ᾠ' => 'ὠι', + 'ᾡ' => 'ὡι', + 'ᾢ' => 'ὢι', + 'ᾣ' => 'ὣι', + 'ᾤ' => 'ὤι', + 'ᾥ' => 'ὥι', + 'ᾦ' => 'ὦι', + 'ᾧ' => 'ὧι', + 'ᾨ' => 'ὠι', + 'ᾩ' => 'ὡι', + 'ᾪ' => 'ὢι', + 'ᾫ' => 'ὣι', + 'ᾬ' => 'ὤι', + 'ᾭ' => 'ὥι', + 'ᾮ' => 'ὦι', + 'ᾯ' => 'ὧι', + 'ᾲ' => 'ὰι', + 'ᾳ' => 'αι', + 'ᾴ' => 'άι', + 'ᾶ' => 'ᾶ', + 'ᾷ' => 'ᾶι', + 'ᾼ' => 'αι', + 'ῂ' => 'ὴι', + 'ῃ' => 'ηι', + 'ῄ' => 'ήι', + 'ῆ' => 'ῆ', + 'ῇ' => 'ῆι', + 'ῌ' => 'ηι', + 'ῒ' => 'ῒ', + 'ῖ' => 'ῖ', + 'ῗ' => 'ῗ', + 'ῢ' => 'ῢ', + 'ῤ' => 'ῤ', + 'ῦ' => 'ῦ', + 'ῧ' => 'ῧ', + 'ῲ' => 'ὼι', + 'ῳ' => 'ωι', + 'ῴ' => 'ώι', + 'ῶ' => 'ῶ', + 'ῷ' => 'ῶι', + 'ῼ' => 'ωι', + 'ff' => 'ff', + 'fi' => 'fi', + 'fl' => 'fl', + 'ffi' => 'ffi', + 'ffl' => 'ffl', + 'ſt' => 'st', + 'st' => 'st', + 'ﬓ' => 'մն', + 'ﬔ' => 'մե', + 'ﬕ' => 'մի', + 'ﬖ' => 'վն', + 'ﬗ' => 'մխ', +]; diff --git a/vendor/symfony/polyfill-mbstring/bootstrap.php b/vendor/symfony/polyfill-mbstring/bootstrap.php index 1fedd1f7..ecf1a035 100644 --- a/vendor/symfony/polyfill-mbstring/bootstrap.php +++ b/vendor/symfony/polyfill-mbstring/bootstrap.php @@ -132,6 +132,10 @@ function mb_scrub($string, $encoding = null) { $encoding = null === $encoding ? function mb_str_split($string, $length = 1, $encoding = null) { return p\Mbstring::mb_str_split($string, $length, $encoding); } } +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/vendor/symfony/polyfill-mbstring/bootstrap80.php b/vendor/symfony/polyfill-mbstring/bootstrap80.php index 82f5ac4d..2f9fb5b4 100644 --- a/vendor/symfony/polyfill-mbstring/bootstrap80.php +++ b/vendor/symfony/polyfill-mbstring/bootstrap80.php @@ -128,6 +128,10 @@ function mb_scrub(?string $string, ?string $encoding = null): string { $encoding function mb_str_split(?string $string, ?int $length = 1, ?string $encoding = null): array { return p\Mbstring::mb_str_split((string) $string, (int) $length, $encoding); } } +if (!function_exists('mb_str_pad')) { + function mb_str_pad(string $string, int $length, string $pad_string = ' ', int $pad_type = STR_PAD_RIGHT, ?string $encoding = null): string { return p\Mbstring::mb_str_pad($string, $length, $pad_string, $pad_type, $encoding); } +} + if (extension_loaded('mbstring')) { return; } diff --git a/vendor/symfony/polyfill-mbstring/composer.json b/vendor/symfony/polyfill-mbstring/composer.json index 44895536..943e5029 100644 --- a/vendor/symfony/polyfill-mbstring/composer.json +++ b/vendor/symfony/polyfill-mbstring/composer.json @@ -31,7 +31,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-main": "1.27-dev" + "dev-main": "1.28-dev" }, "thanks": { "name": "symfony/polyfill", diff --git a/vendor/symfony/polyfill-php73/LICENSE b/vendor/symfony/polyfill-php73/LICENSE new file mode 100644 index 00000000..7536caea --- /dev/null +++ b/vendor/symfony/polyfill-php73/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php73/Php73.php b/vendor/symfony/polyfill-php73/Php73.php new file mode 100644 index 00000000..65c35a6a --- /dev/null +++ b/vendor/symfony/polyfill-php73/Php73.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php73; + +/** + * @author Gabriel Caruso + * @author Ion Bazan + * + * @internal + */ +final class Php73 +{ + public static $startAt = 1533462603; + + /** + * @param bool $asNum + * + * @return array|float|int + */ + public static function hrtime($asNum = false) + { + $ns = microtime(false); + $s = substr($ns, 11) - self::$startAt; + $ns = 1E9 * (float) $ns; + + if ($asNum) { + $ns += $s * 1E9; + + return \PHP_INT_SIZE === 4 ? $ns : (int) $ns; + } + + return [$s, (int) $ns]; + } +} diff --git a/vendor/symfony/polyfill-php73/README.md b/vendor/symfony/polyfill-php73/README.md new file mode 100644 index 00000000..032fafbd --- /dev/null +++ b/vendor/symfony/polyfill-php73/README.md @@ -0,0 +1,18 @@ +Symfony Polyfill / Php73 +======================== + +This component provides functions added to PHP 7.3 core: + +- [`array_key_first`](https://php.net/array_key_first) +- [`array_key_last`](https://php.net/array_key_last) +- [`hrtime`](https://php.net/function.hrtime) +- [`is_countable`](https://php.net/is_countable) +- [`JsonException`](https://php.net/JsonException) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php b/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php new file mode 100644 index 00000000..f06d6c26 --- /dev/null +++ b/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 70300) { + class JsonException extends Exception + { + } +} diff --git a/vendor/symfony/polyfill-php73/bootstrap.php b/vendor/symfony/polyfill-php73/bootstrap.php new file mode 100644 index 00000000..d6b21538 --- /dev/null +++ b/vendor/symfony/polyfill-php73/bootstrap.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php73 as p; + +if (\PHP_VERSION_ID >= 70300) { + return; +} + +if (!function_exists('is_countable')) { + function is_countable($value) { return is_array($value) || $value instanceof Countable || $value instanceof ResourceBundle || $value instanceof SimpleXmlElement; } +} +if (!function_exists('hrtime')) { + require_once __DIR__.'/Php73.php'; + p\Php73::$startAt = (int) microtime(true); + function hrtime($as_number = false) { return p\Php73::hrtime($as_number); } +} +if (!function_exists('array_key_first')) { + function array_key_first(array $array) { foreach ($array as $key => $value) { return $key; } } +} +if (!function_exists('array_key_last')) { + function array_key_last(array $array) { return key(array_slice($array, -1, 1, true)); } +} diff --git a/vendor/symfony/polyfill-php73/composer.json b/vendor/symfony/polyfill-php73/composer.json new file mode 100644 index 00000000..48295ef9 --- /dev/null +++ b/vendor/symfony/polyfill-php73/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/polyfill-php73", + "type": "library", + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php73\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-php80/LICENSE b/vendor/symfony/polyfill-php80/LICENSE new file mode 100644 index 00000000..0ed3a246 --- /dev/null +++ b/vendor/symfony/polyfill-php80/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2020-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php80/Php80.php b/vendor/symfony/polyfill-php80/Php80.php new file mode 100644 index 00000000..362dd1a9 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Php80.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Ion Bazan + * @author Nico Oelgart + * @author Nicolas Grekas + * + * @internal + */ +final class Php80 +{ + public static function fdiv(float $dividend, float $divisor): float + { + return @($dividend / $divisor); + } + + public static function get_debug_type($value): string + { + switch (true) { + case null === $value: return 'null'; + case \is_bool($value): return 'bool'; + case \is_string($value): return 'string'; + case \is_array($value): return 'array'; + case \is_int($value): return 'int'; + case \is_float($value): return 'float'; + case \is_object($value): break; + case $value instanceof \__PHP_Incomplete_Class: return '__PHP_Incomplete_Class'; + default: + if (null === $type = @get_resource_type($value)) { + return 'unknown'; + } + + if ('Unknown' === $type) { + $type = 'closed'; + } + + return "resource ($type)"; + } + + $class = \get_class($value); + + if (false === strpos($class, '@')) { + return $class; + } + + return (get_parent_class($class) ?: key(class_implements($class)) ?: 'class').'@anonymous'; + } + + public static function get_resource_id($res): int + { + if (!\is_resource($res) && null === @get_resource_type($res)) { + throw new \TypeError(sprintf('Argument 1 passed to get_resource_id() must be of the type resource, %s given', get_debug_type($res))); + } + + return (int) $res; + } + + public static function preg_last_error_msg(): string + { + switch (preg_last_error()) { + case \PREG_INTERNAL_ERROR: + return 'Internal error'; + case \PREG_BAD_UTF8_ERROR: + return 'Malformed UTF-8 characters, possibly incorrectly encoded'; + case \PREG_BAD_UTF8_OFFSET_ERROR: + return 'The offset did not correspond to the beginning of a valid UTF-8 code point'; + case \PREG_BACKTRACK_LIMIT_ERROR: + return 'Backtrack limit exhausted'; + case \PREG_RECURSION_LIMIT_ERROR: + return 'Recursion limit exhausted'; + case \PREG_JIT_STACKLIMIT_ERROR: + return 'JIT stack limit exhausted'; + case \PREG_NO_ERROR: + return 'No error'; + default: + return 'Unknown error'; + } + } + + public static function str_contains(string $haystack, string $needle): bool + { + return '' === $needle || false !== strpos($haystack, $needle); + } + + public static function str_starts_with(string $haystack, string $needle): bool + { + return 0 === strncmp($haystack, $needle, \strlen($needle)); + } + + public static function str_ends_with(string $haystack, string $needle): bool + { + if ('' === $needle || $needle === $haystack) { + return true; + } + + if ('' === $haystack) { + return false; + } + + $needleLength = \strlen($needle); + + return $needleLength <= \strlen($haystack) && 0 === substr_compare($haystack, $needle, -$needleLength); + } +} diff --git a/vendor/symfony/polyfill-php80/PhpToken.php b/vendor/symfony/polyfill-php80/PhpToken.php new file mode 100644 index 00000000..fe6e6910 --- /dev/null +++ b/vendor/symfony/polyfill-php80/PhpToken.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php80; + +/** + * @author Fedonyuk Anton + * + * @internal + */ +class PhpToken implements \Stringable +{ + /** + * @var int + */ + public $id; + + /** + * @var string + */ + public $text; + + /** + * @var int + */ + public $line; + + /** + * @var int + */ + public $pos; + + public function __construct(int $id, string $text, int $line = -1, int $position = -1) + { + $this->id = $id; + $this->text = $text; + $this->line = $line; + $this->pos = $position; + } + + public function getTokenName(): ?string + { + if ('UNKNOWN' === $name = token_name($this->id)) { + $name = \strlen($this->text) > 1 || \ord($this->text) < 32 ? null : $this->text; + } + + return $name; + } + + /** + * @param int|string|array $kind + */ + public function is($kind): bool + { + foreach ((array) $kind as $value) { + if (\in_array($value, [$this->id, $this->text], true)) { + return true; + } + } + + return false; + } + + public function isIgnorable(): bool + { + return \in_array($this->id, [\T_WHITESPACE, \T_COMMENT, \T_DOC_COMMENT, \T_OPEN_TAG], true); + } + + public function __toString(): string + { + return (string) $this->text; + } + + /** + * @return static[] + */ + public static function tokenize(string $code, int $flags = 0): array + { + $line = 1; + $position = 0; + $tokens = token_get_all($code, $flags); + foreach ($tokens as $index => $token) { + if (\is_string($token)) { + $id = \ord($token); + $text = $token; + } else { + [$id, $text, $line] = $token; + } + $tokens[$index] = new static($id, $text, $line, $position); + $position += \strlen($text); + } + + return $tokens; + } +} diff --git a/vendor/symfony/polyfill-php80/README.md b/vendor/symfony/polyfill-php80/README.md new file mode 100644 index 00000000..3816c559 --- /dev/null +++ b/vendor/symfony/polyfill-php80/README.md @@ -0,0 +1,25 @@ +Symfony Polyfill / Php80 +======================== + +This component provides features added to PHP 8.0 core: + +- [`Stringable`](https://php.net/stringable) interface +- [`fdiv`](https://php.net/fdiv) +- [`ValueError`](https://php.net/valueerror) class +- [`UnhandledMatchError`](https://php.net/unhandledmatcherror) class +- `FILTER_VALIDATE_BOOL` constant +- [`get_debug_type`](https://php.net/get_debug_type) +- [`PhpToken`](https://php.net/phptoken) class +- [`preg_last_error_msg`](https://php.net/preg_last_error_msg) +- [`str_contains`](https://php.net/str_contains) +- [`str_starts_with`](https://php.net/str_starts_with) +- [`str_ends_with`](https://php.net/str_ends_with) +- [`get_resource_id`](https://php.net/get_resource_id) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php b/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php new file mode 100644 index 00000000..2b955423 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/Attribute.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +#[Attribute(Attribute::TARGET_CLASS)] +final class Attribute +{ + public const TARGET_CLASS = 1; + public const TARGET_FUNCTION = 2; + public const TARGET_METHOD = 4; + public const TARGET_PROPERTY = 8; + public const TARGET_CLASS_CONSTANT = 16; + public const TARGET_PARAMETER = 32; + public const TARGET_ALL = 63; + public const IS_REPEATABLE = 64; + + /** @var int */ + public $flags; + + public function __construct(int $flags = self::TARGET_ALL) + { + $this->flags = $flags; + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php b/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php new file mode 100644 index 00000000..bd1212f6 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/PhpToken.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000 && extension_loaded('tokenizer')) { + class PhpToken extends Symfony\Polyfill\Php80\PhpToken + { + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php b/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php new file mode 100644 index 00000000..7c62d750 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/Stringable.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + interface Stringable + { + /** + * @return string + */ + public function __toString(); + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php b/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php new file mode 100644 index 00000000..01c6c6c8 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/UnhandledMatchError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class UnhandledMatchError extends Error + { + } +} diff --git a/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php b/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php new file mode 100644 index 00000000..783dbc28 --- /dev/null +++ b/vendor/symfony/polyfill-php80/Resources/stubs/ValueError.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80000) { + class ValueError extends Error + { + } +} diff --git a/vendor/symfony/polyfill-php80/bootstrap.php b/vendor/symfony/polyfill-php80/bootstrap.php new file mode 100644 index 00000000..e5f7dbc1 --- /dev/null +++ b/vendor/symfony/polyfill-php80/bootstrap.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php80 as p; + +if (\PHP_VERSION_ID >= 80000) { + return; +} + +if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) { + define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN); +} + +if (!function_exists('fdiv')) { + function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); } +} +if (!function_exists('preg_last_error_msg')) { + function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); } +} +if (!function_exists('str_contains')) { + function str_contains(?string $haystack, ?string $needle): bool { return p\Php80::str_contains($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_starts_with')) { + function str_starts_with(?string $haystack, ?string $needle): bool { return p\Php80::str_starts_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('str_ends_with')) { + function str_ends_with(?string $haystack, ?string $needle): bool { return p\Php80::str_ends_with($haystack ?? '', $needle ?? ''); } +} +if (!function_exists('get_debug_type')) { + function get_debug_type($value): string { return p\Php80::get_debug_type($value); } +} +if (!function_exists('get_resource_id')) { + function get_resource_id($resource): int { return p\Php80::get_resource_id($resource); } +} diff --git a/vendor/symfony/polyfill-php80/composer.json b/vendor/symfony/polyfill-php80/composer.json new file mode 100644 index 00000000..f1801f40 --- /dev/null +++ b/vendor/symfony/polyfill-php80/composer.json @@ -0,0 +1,40 @@ +{ + "name": "symfony/polyfill-php80", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php80\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/polyfill-php81/LICENSE b/vendor/symfony/polyfill-php81/LICENSE new file mode 100644 index 00000000..99c6bdf3 --- /dev/null +++ b/vendor/symfony/polyfill-php81/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2021-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/polyfill-php81/Php81.php b/vendor/symfony/polyfill-php81/Php81.php new file mode 100644 index 00000000..f0507b76 --- /dev/null +++ b/vendor/symfony/polyfill-php81/Php81.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php81; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class Php81 +{ + public static function array_is_list(array $array): bool + { + if ([] === $array || $array === array_values($array)) { + return true; + } + + $nextKey = -1; + + foreach ($array as $k => $v) { + if ($k !== ++$nextKey) { + return false; + } + } + + return true; + } +} diff --git a/vendor/symfony/polyfill-php81/README.md b/vendor/symfony/polyfill-php81/README.md new file mode 100644 index 00000000..c07ef782 --- /dev/null +++ b/vendor/symfony/polyfill-php81/README.md @@ -0,0 +1,18 @@ +Symfony Polyfill / Php81 +======================== + +This component provides features added to PHP 8.1 core: + +- [`array_is_list`](https://php.net/array_is_list) +- [`enum_exists`](https://php.net/enum-exists) +- [`MYSQLI_REFRESH_REPLICA`](https://php.net/mysqli.constants#constantmysqli-refresh-replica) constant +- [`ReturnTypeWillChange`](https://wiki.php.net/rfc/internal_method_return_types) +- [`CURLStringFile`](https://php.net/CURLStringFile) (but only if PHP >= 7.4 is used) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php b/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php new file mode 100644 index 00000000..eb5952ee --- /dev/null +++ b/vendor/symfony/polyfill-php81/Resources/stubs/CURLStringFile.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID >= 70400 && extension_loaded('curl')) { + /** + * @property string $data + */ + class CURLStringFile extends CURLFile + { + private $data; + + public function __construct(string $data, string $postname, string $mime = 'application/octet-stream') + { + $this->data = $data; + parent::__construct('data://application/octet-stream;base64,'.base64_encode($data), $mime, $postname); + } + + public function __set(string $name, $value): void + { + if ('data' !== $name) { + $this->$name = $value; + + return; + } + + if (is_object($value) ? !method_exists($value, '__toString') : !is_scalar($value)) { + throw new \TypeError('Cannot assign '.gettype($value).' to property CURLStringFile::$data of type string'); + } + + $this->name = 'data://application/octet-stream;base64,'.base64_encode($value); + } + + public function __isset(string $name): bool + { + return isset($this->$name); + } + + public function &__get(string $name) + { + return $this->$name; + } + } +} diff --git a/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php b/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php new file mode 100644 index 00000000..cb7720a8 --- /dev/null +++ b/vendor/symfony/polyfill-php81/Resources/stubs/ReturnTypeWillChange.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (\PHP_VERSION_ID < 80100) { + #[Attribute(Attribute::TARGET_METHOD)] + final class ReturnTypeWillChange + { + public function __construct() + { + } + } +} diff --git a/vendor/symfony/polyfill-php81/bootstrap.php b/vendor/symfony/polyfill-php81/bootstrap.php new file mode 100644 index 00000000..9f872e02 --- /dev/null +++ b/vendor/symfony/polyfill-php81/bootstrap.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php81 as p; + +if (\PHP_VERSION_ID >= 80100) { + return; +} + +if (defined('MYSQLI_REFRESH_SLAVE') && !defined('MYSQLI_REFRESH_REPLICA')) { + define('MYSQLI_REFRESH_REPLICA', 64); +} + +if (!function_exists('array_is_list')) { + function array_is_list(array $array): bool { return p\Php81::array_is_list($array); } +} + +if (!function_exists('enum_exists')) { + function enum_exists(string $enum, bool $autoload = true): bool { return $autoload && class_exists($enum) && false; } +} diff --git a/vendor/symfony/polyfill-php81/composer.json b/vendor/symfony/polyfill-php81/composer.json new file mode 100644 index 00000000..e02d673d --- /dev/null +++ b/vendor/symfony/polyfill-php81/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/polyfill-php81", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.1" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php81\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/vendor/symfony/filesystem/.gitignore b/vendor/symfony/service-contracts/.gitignore similarity index 100% rename from vendor/symfony/filesystem/.gitignore rename to vendor/symfony/service-contracts/.gitignore diff --git a/vendor/symfony/service-contracts/Attribute/Required.php b/vendor/symfony/service-contracts/Attribute/Required.php new file mode 100644 index 00000000..9df85118 --- /dev/null +++ b/vendor/symfony/service-contracts/Attribute/Required.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +/** + * A required dependency. + * + * This attribute indicates that a property holds a required dependency. The annotated property or method should be + * considered during the instantiation process of the containing class. + * + * @author Alexander M. Turek + */ +#[\Attribute(\Attribute::TARGET_METHOD | \Attribute::TARGET_PROPERTY)] +final class Required +{ +} diff --git a/vendor/symfony/service-contracts/Attribute/SubscribedService.php b/vendor/symfony/service-contracts/Attribute/SubscribedService.php new file mode 100644 index 00000000..10d1bc38 --- /dev/null +++ b/vendor/symfony/service-contracts/Attribute/SubscribedService.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Attribute; + +use Symfony\Contracts\Service\ServiceSubscriberTrait; + +/** + * Use with {@see ServiceSubscriberTrait} to mark a method's return type + * as a subscribed service. + * + * @author Kevin Bond + */ +#[\Attribute(\Attribute::TARGET_METHOD)] +final class SubscribedService +{ + /** + * @param string|null $key The key to use for the service + * If null, use "ClassName::methodName" + */ + public function __construct( + public ?string $key = null + ) { + } +} diff --git a/vendor/symfony/service-contracts/CHANGELOG.md b/vendor/symfony/service-contracts/CHANGELOG.md new file mode 100644 index 00000000..7932e261 --- /dev/null +++ b/vendor/symfony/service-contracts/CHANGELOG.md @@ -0,0 +1,5 @@ +CHANGELOG +========= + +The changelog is maintained for all Symfony contracts at the following URL: +https://github.com/symfony/contracts/blob/main/CHANGELOG.md diff --git a/vendor/symfony/service-contracts/LICENSE b/vendor/symfony/service-contracts/LICENSE new file mode 100644 index 00000000..74cdc2db --- /dev/null +++ b/vendor/symfony/service-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-2022 Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/service-contracts/README.md b/vendor/symfony/service-contracts/README.md new file mode 100644 index 00000000..41e054a1 --- /dev/null +++ b/vendor/symfony/service-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Service Contracts +========================= + +A set of abstractions extracted out of the Symfony components. + +Can be used to build on semantics that the Symfony components proved useful - and +that already have battle tested implementations. + +See https://github.com/symfony/contracts/blob/main/README.md for more information. diff --git a/vendor/symfony/service-contracts/ResetInterface.php b/vendor/symfony/service-contracts/ResetInterface.php new file mode 100644 index 00000000..1af1075e --- /dev/null +++ b/vendor/symfony/service-contracts/ResetInterface.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + public function reset(); +} diff --git a/vendor/symfony/service-contracts/ServiceLocatorTrait.php b/vendor/symfony/service-contracts/ServiceLocatorTrait.php new file mode 100644 index 00000000..74dfa436 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceLocatorTrait.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +// Help opcache.preload discover always-needed symbols +class_exists(ContainerExceptionInterface::class); +class_exists(NotFoundExceptionInterface::class); + +/** + * A trait to help implement ServiceProviderInterface. + * + * @author Robin Chalas + * @author Nicolas Grekas + */ +trait ServiceLocatorTrait +{ + private $factories; + private $loading = []; + private $providedTypes; + + /** + * @param callable[] $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + * + * @return bool + */ + public function has(string $id) + { + return isset($this->factories[$id]); + } + + /** + * {@inheritdoc} + * + * @return mixed + */ + public function get(string $id) + { + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + + if (isset($this->loading[$id])) { + $ids = array_values($this->loading); + $ids = \array_slice($this->loading, array_search($id, $ids)); + $ids[] = $id; + + throw $this->createCircularReferenceException($id, $ids); + } + + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + + /** + * {@inheritdoc} + */ + public function getProvidedServices(): array + { + if (null === $this->providedTypes) { + $this->providedTypes = []; + + foreach ($this->factories as $name => $factory) { + if (!\is_callable($factory)) { + $this->providedTypes[$name] = '?'; + } else { + $type = (new \ReflectionFunction($factory))->getReturnType(); + + $this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').($type instanceof \ReflectionNamedType ? $type->getName() : $type) : '?'; + } + } + } + + return $this->providedTypes; + } + + private function createNotFoundException(string $id): NotFoundExceptionInterface + { + if (!$alternatives = array_keys($this->factories)) { + $message = 'is empty...'; + } else { + $last = array_pop($alternatives); + if ($alternatives) { + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + } else { + $message = sprintf('only knows about the "%s" service.', $last); + } + } + + if ($this->loading) { + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + } else { + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { + }; + } + + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface + { + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + }; + } +} diff --git a/vendor/symfony/service-contracts/ServiceProviderInterface.php b/vendor/symfony/service-contracts/ServiceProviderInterface.php new file mode 100644 index 00000000..c60ad0bd --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceProviderInterface.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; + +/** + * A ServiceProviderInterface exposes the identifiers and the types of services provided by a container. + * + * @author Nicolas Grekas + * @author Mateusz Sip + */ +interface ServiceProviderInterface extends ContainerInterface +{ + /** + * Returns an associative array of service types keyed by the identifiers provided by the current container. + * + * Examples: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface + * * ['foo' => '?'] means the container provides service name "foo" of unspecified type + * * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null + * + * @return string[] The provided service types, keyed by service names + */ + public function getProvidedServices(): array; +} diff --git a/vendor/symfony/service-contracts/ServiceSubscriberInterface.php b/vendor/symfony/service-contracts/ServiceSubscriberInterface.php new file mode 100644 index 00000000..098ab908 --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceSubscriberInterface.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types required by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * ['logger' => 'Psr\Log\LoggerInterface'] means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * ['loggers' => 'Psr\Log\LoggerInterface[]'] means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * ['Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface'] + * + * otherwise: + * + * * ['logger' => '?Psr\Log\LoggerInterface'] denotes an optional dependency + * * ['loggers' => '?Psr\Log\LoggerInterface[]'] denotes an optional iterable dependency + * * ['?Psr\Log\LoggerInterface'] is a shortcut for + * * ['Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface'] + * + * @return string[] The required service types, optionally keyed by service names + */ + public static function getSubscribedServices(); +} diff --git a/vendor/symfony/service-contracts/ServiceSubscriberTrait.php b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php new file mode 100644 index 00000000..16e3eb2c --- /dev/null +++ b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\Attribute\SubscribedService; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services from + * method return types. Service ids are available as "ClassName::methodName". + * + * @author Kevin Bond + */ +trait ServiceSubscriberTrait +{ + /** @var ContainerInterface */ + protected $container; + + /** + * {@inheritdoc} + */ + public static function getSubscribedServices(): array + { + $services = method_exists(get_parent_class(self::class) ?: '', __FUNCTION__) ? parent::getSubscribedServices() : []; + $attributeOptIn = false; + + if (\PHP_VERSION_ID >= 80000) { + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!$attribute = $method->getAttributes(SubscribedService::class)[0] ?? null) { + continue; + } + + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + throw new \LogicException(sprintf('Cannot use "%s" on method "%s::%s()" (can only be used on non-static, non-abstract methods with no parameters).', SubscribedService::class, self::class, $method->name)); + } + + if (!$returnType = $method->getReturnType()) { + throw new \LogicException(sprintf('Cannot use "%s" on methods without a return type in "%s::%s()".', SubscribedService::class, $method->name, self::class)); + } + + $serviceId = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; + + if ($returnType->allowsNull()) { + $serviceId = '?'.$serviceId; + } + + $services[$attribute->newInstance()->key ?? self::class.'::'.$method->name] = $serviceId; + $attributeOptIn = true; + } + } + + if (!$attributeOptIn) { + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + continue; + } + + if (self::class !== $method->getDeclaringClass()->name) { + continue; + } + + if (!($returnType = $method->getReturnType()) instanceof \ReflectionNamedType) { + continue; + } + + if ($returnType->isBuiltin()) { + continue; + } + + if (\PHP_VERSION_ID >= 80000) { + trigger_deprecation('symfony/service-contracts', '2.5', 'Using "%s" in "%s" without using the "%s" attribute on any method is deprecated.', ServiceSubscriberTrait::class, self::class, SubscribedService::class); + } + + $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); + } + } + + return $services; + } + + /** + * @required + * + * @return ContainerInterface|null + */ + public function setContainer(ContainerInterface $container) + { + $this->container = $container; + + if (method_exists(get_parent_class(self::class) ?: '', __FUNCTION__)) { + return parent::setContainer($container); + } + + return null; + } +} diff --git a/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php new file mode 100644 index 00000000..2a1b565f --- /dev/null +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Contracts\Service\Test; + +use PHPUnit\Framework\TestCase; +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceLocatorTrait; + +abstract class ServiceLocatorTest extends TestCase +{ + /** + * @return ContainerInterface + */ + protected function getServiceLocator(array $factories) + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + ]); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator([ + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + ]); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + public function testThrowsOnUndefinedInternalService() + { + if (!$this->getExpectedException()) { + $this->expectException(\Psr\Container\NotFoundExceptionInterface::class); + $this->expectExceptionMessage('The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service.'); + } + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } + + public function testThrowsOnCircularReference() + { + $this->expectException(\Psr\Container\ContainerExceptionInterface::class); + $this->expectExceptionMessage('Circular reference detected for service "bar", path: "bar -> baz -> bar".'); + $locator = $this->getServiceLocator([ + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + ]); + + $locator->get('foo'); + } +} diff --git a/vendor/symfony/service-contracts/composer.json b/vendor/symfony/service-contracts/composer.json new file mode 100644 index 00000000..f0586370 --- /dev/null +++ b/vendor/symfony/service-contracts/composer.json @@ -0,0 +1,42 @@ +{ + "name": "symfony/service-contracts", + "type": "library", + "description": "Generic abstractions related to writing services", + "keywords": ["abstractions", "contracts", "decoupling", "interfaces", "interoperability", "standards"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Service\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + } +} diff --git a/vendor/symfony/var-dumper/CHANGELOG.md b/vendor/symfony/var-dumper/CHANGELOG.md new file mode 100644 index 00000000..f58ed317 --- /dev/null +++ b/vendor/symfony/var-dumper/CHANGELOG.md @@ -0,0 +1,72 @@ +CHANGELOG +========= + +5.4 +--- + + * Add ability to style integer and double values independently + * Add casters for Symfony's UUIDs and ULIDs + * Add support for `Fiber` + +5.2.0 +----- + + * added support for PHPUnit `--colors` option + * added `VAR_DUMPER_FORMAT=server` env var value support + * prevent replacing the handler when the `VAR_DUMPER_FORMAT` env var is set + +5.1.0 +----- + + * added `RdKafka` support + +4.4.0 +----- + + * added `VarDumperTestTrait::setUpVarDumper()` and `VarDumperTestTrait::tearDownVarDumper()` + to configure casters & flags to use in tests + * added `ImagineCaster` and infrastructure to dump images + * added the stamps of a message after it is dispatched in `TraceableMessageBus` and `MessengerDataCollector` collected data + * added `UuidCaster` + * made all casters final + * added support for the `NO_COLOR` env var (https://no-color.org/) + +4.3.0 +----- + + * added `DsCaster` to support dumping the contents of data structures from the Ds extension + +4.2.0 +----- + + * support selecting the format to use by setting the environment variable `VAR_DUMPER_FORMAT` to `html` or `cli` + +4.1.0 +----- + + * added a `ServerDumper` to send serialized Data clones to a server + * added a `ServerDumpCommand` and `DumpServer` to run a server collecting + and displaying dumps on a single place with multiple formats support + * added `CliDescriptor` and `HtmlDescriptor` descriptors for `server:dump` CLI and HTML formats support + +4.0.0 +----- + + * support for passing `\ReflectionClass` instances to the `Caster::castObject()` + method has been dropped, pass class names as strings instead + * the `Data::getRawData()` method has been removed + * the `VarDumperTestTrait::assertDumpEquals()` method expects a 3rd `$filter = 0` + argument and moves `$message = ''` argument at 4th position. + * the `VarDumperTestTrait::assertDumpMatchesFormat()` method expects a 3rd `$filter = 0` + argument and moves `$message = ''` argument at 4th position. + +3.4.0 +----- + + * added `AbstractCloner::setMinDepth()` function to ensure minimum tree depth + * deprecated `MongoCaster` + +2.7.0 +----- + + * deprecated `Cloner\Data::getLimitedClone()`. Use `withMaxDepth`, `withMaxItemsPerDepth` or `withRefHandles` instead. diff --git a/vendor/symfony/var-dumper/Caster/AmqpCaster.php b/vendor/symfony/var-dumper/Caster/AmqpCaster.php new file mode 100644 index 00000000..dc3b6219 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/AmqpCaster.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Amqp related classes to array representation. + * + * @author Grégoire Pineau + * + * @final + */ +class AmqpCaster +{ + private const FLAGS = [ + \AMQP_DURABLE => 'AMQP_DURABLE', + \AMQP_PASSIVE => 'AMQP_PASSIVE', + \AMQP_EXCLUSIVE => 'AMQP_EXCLUSIVE', + \AMQP_AUTODELETE => 'AMQP_AUTODELETE', + \AMQP_INTERNAL => 'AMQP_INTERNAL', + \AMQP_NOLOCAL => 'AMQP_NOLOCAL', + \AMQP_AUTOACK => 'AMQP_AUTOACK', + \AMQP_IFEMPTY => 'AMQP_IFEMPTY', + \AMQP_IFUNUSED => 'AMQP_IFUNUSED', + \AMQP_MANDATORY => 'AMQP_MANDATORY', + \AMQP_IMMEDIATE => 'AMQP_IMMEDIATE', + \AMQP_MULTIPLE => 'AMQP_MULTIPLE', + \AMQP_NOWAIT => 'AMQP_NOWAIT', + \AMQP_REQUEUE => 'AMQP_REQUEUE', + ]; + + private const EXCHANGE_TYPES = [ + \AMQP_EX_TYPE_DIRECT => 'AMQP_EX_TYPE_DIRECT', + \AMQP_EX_TYPE_FANOUT => 'AMQP_EX_TYPE_FANOUT', + \AMQP_EX_TYPE_TOPIC => 'AMQP_EX_TYPE_TOPIC', + \AMQP_EX_TYPE_HEADERS => 'AMQP_EX_TYPE_HEADERS', + ]; + + public static function castConnection(\AMQPConnection $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'is_connected' => $c->isConnected(), + ]; + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPConnection\x00login"])) { + return $a; + } + + // BC layer in the amqp lib + if (method_exists($c, 'getReadTimeout')) { + $timeout = $c->getReadTimeout(); + } else { + $timeout = $c->getTimeout(); + } + + $a += [ + $prefix.'is_connected' => $c->isConnected(), + $prefix.'login' => $c->getLogin(), + $prefix.'password' => $c->getPassword(), + $prefix.'host' => $c->getHost(), + $prefix.'vhost' => $c->getVhost(), + $prefix.'port' => $c->getPort(), + $prefix.'read_timeout' => $timeout, + ]; + + return $a; + } + + public static function castChannel(\AMQPChannel $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'is_connected' => $c->isConnected(), + $prefix.'channel_id' => $c->getChannelId(), + ]; + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPChannel\x00connection"])) { + return $a; + } + + $a += [ + $prefix.'connection' => $c->getConnection(), + $prefix.'prefetch_size' => $c->getPrefetchSize(), + $prefix.'prefetch_count' => $c->getPrefetchCount(), + ]; + + return $a; + } + + public static function castQueue(\AMQPQueue $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'flags' => self::extractFlags($c->getFlags()), + ]; + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPQueue\x00name"])) { + return $a; + } + + $a += [ + $prefix.'connection' => $c->getConnection(), + $prefix.'channel' => $c->getChannel(), + $prefix.'name' => $c->getName(), + $prefix.'arguments' => $c->getArguments(), + ]; + + return $a; + } + + public static function castExchange(\AMQPExchange $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'flags' => self::extractFlags($c->getFlags()), + ]; + + $type = isset(self::EXCHANGE_TYPES[$c->getType()]) ? new ConstStub(self::EXCHANGE_TYPES[$c->getType()], $c->getType()) : $c->getType(); + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPExchange\x00name"])) { + $a["\x00AMQPExchange\x00type"] = $type; + + return $a; + } + + $a += [ + $prefix.'connection' => $c->getConnection(), + $prefix.'channel' => $c->getChannel(), + $prefix.'name' => $c->getName(), + $prefix.'type' => $type, + $prefix.'arguments' => $c->getArguments(), + ]; + + return $a; + } + + public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $deliveryMode = new ConstStub($c->getDeliveryMode().(2 === $c->getDeliveryMode() ? ' (persistent)' : ' (non-persistent)'), $c->getDeliveryMode()); + + // Recent version of the extension already expose private properties + if (isset($a["\x00AMQPEnvelope\x00body"])) { + $a["\0AMQPEnvelope\0delivery_mode"] = $deliveryMode; + + return $a; + } + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $a += [$prefix.'body' => $c->getBody()]; + } + + $a += [ + $prefix.'delivery_tag' => $c->getDeliveryTag(), + $prefix.'is_redelivery' => $c->isRedelivery(), + $prefix.'exchange_name' => $c->getExchangeName(), + $prefix.'routing_key' => $c->getRoutingKey(), + $prefix.'content_type' => $c->getContentType(), + $prefix.'content_encoding' => $c->getContentEncoding(), + $prefix.'headers' => $c->getHeaders(), + $prefix.'delivery_mode' => $deliveryMode, + $prefix.'priority' => $c->getPriority(), + $prefix.'correlation_id' => $c->getCorrelationId(), + $prefix.'reply_to' => $c->getReplyTo(), + $prefix.'expiration' => $c->getExpiration(), + $prefix.'message_id' => $c->getMessageId(), + $prefix.'timestamp' => $c->getTimeStamp(), + $prefix.'type' => $c->getType(), + $prefix.'user_id' => $c->getUserId(), + $prefix.'app_id' => $c->getAppId(), + ]; + + return $a; + } + + private static function extractFlags(int $flags): ConstStub + { + $flagsArray = []; + + foreach (self::FLAGS as $value => $name) { + if ($flags & $value) { + $flagsArray[] = $name; + } + } + + if (!$flagsArray) { + $flagsArray = ['AMQP_NOPARAM']; + } + + return new ConstStub(implode('|', $flagsArray), $flags); + } +} diff --git a/vendor/symfony/var-dumper/Caster/ArgsStub.php b/vendor/symfony/var-dumper/Caster/ArgsStub.php new file mode 100644 index 00000000..b3f7bbee --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ArgsStub.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a list of function arguments. + * + * @author Nicolas Grekas + */ +class ArgsStub extends EnumStub +{ + private static $parameters = []; + + public function __construct(array $args, string $function, ?string $class) + { + [$variadic, $params] = self::getParameters($function, $class); + + $values = []; + foreach ($args as $k => $v) { + $values[$k] = !\is_scalar($v) && !$v instanceof Stub ? new CutStub($v) : $v; + } + if (null === $params) { + parent::__construct($values, false); + + return; + } + if (\count($values) < \count($params)) { + $params = \array_slice($params, 0, \count($values)); + } elseif (\count($values) > \count($params)) { + $values[] = new EnumStub(array_splice($values, \count($params)), false); + $params[] = $variadic; + } + if (['...'] === $params) { + $this->dumpKeys = false; + $this->value = $values[0]->value; + } else { + $this->value = array_combine($params, $values); + } + } + + private static function getParameters(string $function, ?string $class): array + { + if (isset(self::$parameters[$k = $class.'::'.$function])) { + return self::$parameters[$k]; + } + + try { + $r = null !== $class ? new \ReflectionMethod($class, $function) : new \ReflectionFunction($function); + } catch (\ReflectionException $e) { + return [null, null]; + } + + $variadic = '...'; + $params = []; + foreach ($r->getParameters() as $v) { + $k = '$'.$v->name; + if ($v->isPassedByReference()) { + $k = '&'.$k; + } + if ($v->isVariadic()) { + $variadic .= $k; + } else { + $params[] = $k; + } + } + + return self::$parameters[$k] = [$variadic, $params]; + } +} diff --git a/vendor/symfony/var-dumper/Caster/Caster.php b/vendor/symfony/var-dumper/Caster/Caster.php new file mode 100644 index 00000000..81bfd54e --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/Caster.php @@ -0,0 +1,170 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Helper for filtering out properties in casters. + * + * @author Nicolas Grekas + * + * @final + */ +class Caster +{ + public const EXCLUDE_VERBOSE = 1; + public const EXCLUDE_VIRTUAL = 2; + public const EXCLUDE_DYNAMIC = 4; + public const EXCLUDE_PUBLIC = 8; + public const EXCLUDE_PROTECTED = 16; + public const EXCLUDE_PRIVATE = 32; + public const EXCLUDE_NULL = 64; + public const EXCLUDE_EMPTY = 128; + public const EXCLUDE_NOT_IMPORTANT = 256; + public const EXCLUDE_STRICT = 512; + + public const PREFIX_VIRTUAL = "\0~\0"; + public const PREFIX_DYNAMIC = "\0+\0"; + public const PREFIX_PROTECTED = "\0*\0"; + + /** + * Casts objects to arrays and adds the dynamic property prefix. + * + * @param bool $hasDebugInfo Whether the __debugInfo method exists on $obj or not + */ + public static function castObject(object $obj, string $class, bool $hasDebugInfo = false, string $debugClass = null): array + { + if ($hasDebugInfo) { + try { + $debugInfo = $obj->__debugInfo(); + } catch (\Throwable $e) { + // ignore failing __debugInfo() + $hasDebugInfo = false; + } + } + + $a = $obj instanceof \Closure ? [] : (array) $obj; + + if ($obj instanceof \__PHP_Incomplete_Class) { + return $a; + } + + if ($a) { + static $publicProperties = []; + $debugClass = $debugClass ?? get_debug_type($obj); + + $i = 0; + $prefixedKeys = []; + foreach ($a as $k => $v) { + if ("\0" !== ($k[0] ?? '')) { + if (!isset($publicProperties[$class])) { + foreach ((new \ReflectionClass($class))->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { + $publicProperties[$class][$prop->name] = true; + } + } + if (!isset($publicProperties[$class][$k])) { + $prefixedKeys[$i] = self::PREFIX_DYNAMIC.$k; + } + } elseif ($debugClass !== $class && 1 === strpos($k, $class)) { + $prefixedKeys[$i] = "\0".$debugClass.strrchr($k, "\0"); + } + ++$i; + } + if ($prefixedKeys) { + $keys = array_keys($a); + foreach ($prefixedKeys as $i => $k) { + $keys[$i] = $k; + } + $a = array_combine($keys, $a); + } + } + + if ($hasDebugInfo && \is_array($debugInfo)) { + foreach ($debugInfo as $k => $v) { + if (!isset($k[0]) || "\0" !== $k[0]) { + if (\array_key_exists(self::PREFIX_DYNAMIC.$k, $a)) { + continue; + } + $k = self::PREFIX_VIRTUAL.$k; + } + + unset($a[$k]); + $a[$k] = $v; + } + } + + return $a; + } + + /** + * Filters out the specified properties. + * + * By default, a single match in the $filter bit field filters properties out, following an "or" logic. + * When EXCLUDE_STRICT is set, an "and" logic is applied: all bits must match for a property to be removed. + * + * @param array $a The array containing the properties to filter + * @param int $filter A bit field of Caster::EXCLUDE_* constants specifying which properties to filter out + * @param string[] $listedProperties List of properties to exclude when Caster::EXCLUDE_VERBOSE is set, and to preserve when Caster::EXCLUDE_NOT_IMPORTANT is set + * @param int|null &$count Set to the number of removed properties + */ + public static function filter(array $a, int $filter, array $listedProperties = [], ?int &$count = 0): array + { + $count = 0; + + foreach ($a as $k => $v) { + $type = self::EXCLUDE_STRICT & $filter; + + if (null === $v) { + $type |= self::EXCLUDE_NULL & $filter; + $type |= self::EXCLUDE_EMPTY & $filter; + } elseif (false === $v || '' === $v || '0' === $v || 0 === $v || 0.0 === $v || [] === $v) { + $type |= self::EXCLUDE_EMPTY & $filter; + } + if ((self::EXCLUDE_NOT_IMPORTANT & $filter) && !\in_array($k, $listedProperties, true)) { + $type |= self::EXCLUDE_NOT_IMPORTANT; + } + if ((self::EXCLUDE_VERBOSE & $filter) && \in_array($k, $listedProperties, true)) { + $type |= self::EXCLUDE_VERBOSE; + } + + if (!isset($k[1]) || "\0" !== $k[0]) { + $type |= self::EXCLUDE_PUBLIC & $filter; + } elseif ('~' === $k[1]) { + $type |= self::EXCLUDE_VIRTUAL & $filter; + } elseif ('+' === $k[1]) { + $type |= self::EXCLUDE_DYNAMIC & $filter; + } elseif ('*' === $k[1]) { + $type |= self::EXCLUDE_PROTECTED & $filter; + } else { + $type |= self::EXCLUDE_PRIVATE & $filter; + } + + if ((self::EXCLUDE_STRICT & $filter) ? $type === $filter : $type) { + unset($a[$k]); + ++$count; + } + } + + return $a; + } + + public static function castPhpIncompleteClass(\__PHP_Incomplete_Class $c, array $a, Stub $stub, bool $isNested): array + { + if (isset($a['__PHP_Incomplete_Class_Name'])) { + $stub->class .= '('.$a['__PHP_Incomplete_Class_Name'].')'; + unset($a['__PHP_Incomplete_Class_Name']); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ClassStub.php b/vendor/symfony/var-dumper/Caster/ClassStub.php new file mode 100644 index 00000000..48f84835 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ClassStub.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a PHP class identifier. + * + * @author Nicolas Grekas + */ +class ClassStub extends ConstStub +{ + /** + * @param string $identifier A PHP identifier, e.g. a class, method, interface, etc. name + * @param callable $callable The callable targeted by the identifier when it is ambiguous or not a real PHP identifier + */ + public function __construct(string $identifier, $callable = null) + { + $this->value = $identifier; + + try { + if (null !== $callable) { + if ($callable instanceof \Closure) { + $r = new \ReflectionFunction($callable); + } elseif (\is_object($callable)) { + $r = [$callable, '__invoke']; + } elseif (\is_array($callable)) { + $r = $callable; + } elseif (false !== $i = strpos($callable, '::')) { + $r = [substr($callable, 0, $i), substr($callable, 2 + $i)]; + } else { + $r = new \ReflectionFunction($callable); + } + } elseif (0 < $i = strpos($identifier, '::') ?: strpos($identifier, '->')) { + $r = [substr($identifier, 0, $i), substr($identifier, 2 + $i)]; + } else { + $r = new \ReflectionClass($identifier); + } + + if (\is_array($r)) { + try { + $r = new \ReflectionMethod($r[0], $r[1]); + } catch (\ReflectionException $e) { + $r = new \ReflectionClass($r[0]); + } + } + + if (str_contains($identifier, "@anonymous\0")) { + $this->value = $identifier = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $identifier); + } + + if (null !== $callable && $r instanceof \ReflectionFunctionAbstract) { + $s = ReflectionCaster::castFunctionAbstract($r, [], new Stub(), true, Caster::EXCLUDE_VERBOSE); + $s = ReflectionCaster::getSignature($s); + + if (str_ends_with($identifier, '()')) { + $this->value = substr_replace($identifier, $s, -2); + } else { + $this->value .= $s; + } + } + } catch (\ReflectionException $e) { + return; + } finally { + if (0 < $i = strrpos($this->value, '\\')) { + $this->attr['ellipsis'] = \strlen($this->value) - $i; + $this->attr['ellipsis-type'] = 'class'; + $this->attr['ellipsis-tail'] = 1; + } + } + + if ($f = $r->getFileName()) { + $this->attr['file'] = $f; + $this->attr['line'] = $r->getStartLine(); + } + } + + public static function wrapCallable($callable) + { + if (\is_object($callable) || !\is_callable($callable)) { + return $callable; + } + + if (!\is_array($callable)) { + $callable = new static($callable, $callable); + } elseif (\is_string($callable[0])) { + $callable[0] = new static($callable[0], $callable); + } else { + $callable[1] = new static($callable[1], $callable); + } + + return $callable; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ConstStub.php b/vendor/symfony/var-dumper/Caster/ConstStub.php new file mode 100644 index 00000000..8b017974 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ConstStub.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a PHP constant and its value. + * + * @author Nicolas Grekas + */ +class ConstStub extends Stub +{ + public function __construct(string $name, $value = null) + { + $this->class = $name; + $this->value = 1 < \func_num_args() ? $value : $name; + } + + /** + * @return string + */ + public function __toString() + { + return (string) $this->value; + } +} diff --git a/vendor/symfony/var-dumper/Caster/CutArrayStub.php b/vendor/symfony/var-dumper/Caster/CutArrayStub.php new file mode 100644 index 00000000..0e4fb363 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/CutArrayStub.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents a cut array. + * + * @author Nicolas Grekas + */ +class CutArrayStub extends CutStub +{ + public $preservedSubset; + + public function __construct(array $value, array $preservedKeys) + { + parent::__construct($value); + + $this->preservedSubset = array_intersect_key($value, array_flip($preservedKeys)); + $this->cut -= \count($this->preservedSubset); + } +} diff --git a/vendor/symfony/var-dumper/Caster/CutStub.php b/vendor/symfony/var-dumper/Caster/CutStub.php new file mode 100644 index 00000000..464c6dbd --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/CutStub.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents the main properties of a PHP variable, pre-casted by a caster. + * + * @author Nicolas Grekas + */ +class CutStub extends Stub +{ + public function __construct($value) + { + $this->value = $value; + + switch (\gettype($value)) { + case 'object': + $this->type = self::TYPE_OBJECT; + $this->class = \get_class($value); + + if ($value instanceof \Closure) { + ReflectionCaster::castClosure($value, [], $this, true, Caster::EXCLUDE_VERBOSE); + } + + $this->cut = -1; + break; + + case 'array': + $this->type = self::TYPE_ARRAY; + $this->class = self::ARRAY_ASSOC; + $this->cut = $this->value = \count($value); + break; + + case 'resource': + case 'unknown type': + case 'resource (closed)': + $this->type = self::TYPE_RESOURCE; + $this->handle = (int) $value; + if ('Unknown' === $this->class = @get_resource_type($value)) { + $this->class = 'Closed'; + } + $this->cut = -1; + break; + + case 'string': + $this->type = self::TYPE_STRING; + $this->class = preg_match('//u', $value) ? self::STRING_UTF8 : self::STRING_BINARY; + $this->cut = self::STRING_BINARY === $this->class ? \strlen($value) : mb_strlen($value, 'UTF-8'); + $this->value = ''; + break; + } + } +} diff --git a/vendor/symfony/var-dumper/Caster/DOMCaster.php b/vendor/symfony/var-dumper/Caster/DOMCaster.php new file mode 100644 index 00000000..4dd16e0e --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DOMCaster.php @@ -0,0 +1,304 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts DOM related classes to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class DOMCaster +{ + private const ERROR_CODES = [ + \DOM_PHP_ERR => 'DOM_PHP_ERR', + \DOM_INDEX_SIZE_ERR => 'DOM_INDEX_SIZE_ERR', + \DOMSTRING_SIZE_ERR => 'DOMSTRING_SIZE_ERR', + \DOM_HIERARCHY_REQUEST_ERR => 'DOM_HIERARCHY_REQUEST_ERR', + \DOM_WRONG_DOCUMENT_ERR => 'DOM_WRONG_DOCUMENT_ERR', + \DOM_INVALID_CHARACTER_ERR => 'DOM_INVALID_CHARACTER_ERR', + \DOM_NO_DATA_ALLOWED_ERR => 'DOM_NO_DATA_ALLOWED_ERR', + \DOM_NO_MODIFICATION_ALLOWED_ERR => 'DOM_NO_MODIFICATION_ALLOWED_ERR', + \DOM_NOT_FOUND_ERR => 'DOM_NOT_FOUND_ERR', + \DOM_NOT_SUPPORTED_ERR => 'DOM_NOT_SUPPORTED_ERR', + \DOM_INUSE_ATTRIBUTE_ERR => 'DOM_INUSE_ATTRIBUTE_ERR', + \DOM_INVALID_STATE_ERR => 'DOM_INVALID_STATE_ERR', + \DOM_SYNTAX_ERR => 'DOM_SYNTAX_ERR', + \DOM_INVALID_MODIFICATION_ERR => 'DOM_INVALID_MODIFICATION_ERR', + \DOM_NAMESPACE_ERR => 'DOM_NAMESPACE_ERR', + \DOM_INVALID_ACCESS_ERR => 'DOM_INVALID_ACCESS_ERR', + \DOM_VALIDATION_ERR => 'DOM_VALIDATION_ERR', + ]; + + private const NODE_TYPES = [ + \XML_ELEMENT_NODE => 'XML_ELEMENT_NODE', + \XML_ATTRIBUTE_NODE => 'XML_ATTRIBUTE_NODE', + \XML_TEXT_NODE => 'XML_TEXT_NODE', + \XML_CDATA_SECTION_NODE => 'XML_CDATA_SECTION_NODE', + \XML_ENTITY_REF_NODE => 'XML_ENTITY_REF_NODE', + \XML_ENTITY_NODE => 'XML_ENTITY_NODE', + \XML_PI_NODE => 'XML_PI_NODE', + \XML_COMMENT_NODE => 'XML_COMMENT_NODE', + \XML_DOCUMENT_NODE => 'XML_DOCUMENT_NODE', + \XML_DOCUMENT_TYPE_NODE => 'XML_DOCUMENT_TYPE_NODE', + \XML_DOCUMENT_FRAG_NODE => 'XML_DOCUMENT_FRAG_NODE', + \XML_NOTATION_NODE => 'XML_NOTATION_NODE', + \XML_HTML_DOCUMENT_NODE => 'XML_HTML_DOCUMENT_NODE', + \XML_DTD_NODE => 'XML_DTD_NODE', + \XML_ELEMENT_DECL_NODE => 'XML_ELEMENT_DECL_NODE', + \XML_ATTRIBUTE_DECL_NODE => 'XML_ATTRIBUTE_DECL_NODE', + \XML_ENTITY_DECL_NODE => 'XML_ENTITY_DECL_NODE', + \XML_NAMESPACE_DECL_NODE => 'XML_NAMESPACE_DECL_NODE', + ]; + + public static function castException(\DOMException $e, array $a, Stub $stub, bool $isNested) + { + $k = Caster::PREFIX_PROTECTED.'code'; + if (isset($a[$k], self::ERROR_CODES[$a[$k]])) { + $a[$k] = new ConstStub(self::ERROR_CODES[$a[$k]], $a[$k]); + } + + return $a; + } + + public static function castLength($dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'length' => $dom->length, + ]; + + return $a; + } + + public static function castImplementation(\DOMImplementation $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'Core' => '1.0', + Caster::PREFIX_VIRTUAL.'XML' => '2.0', + ]; + + return $a; + } + + public static function castNode(\DOMNode $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'nodeName' => $dom->nodeName, + 'nodeValue' => new CutStub($dom->nodeValue), + 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), + 'parentNode' => new CutStub($dom->parentNode), + 'childNodes' => $dom->childNodes, + 'firstChild' => new CutStub($dom->firstChild), + 'lastChild' => new CutStub($dom->lastChild), + 'previousSibling' => new CutStub($dom->previousSibling), + 'nextSibling' => new CutStub($dom->nextSibling), + 'attributes' => $dom->attributes, + 'ownerDocument' => new CutStub($dom->ownerDocument), + 'namespaceURI' => $dom->namespaceURI, + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + 'baseURI' => $dom->baseURI ? new LinkStub($dom->baseURI) : $dom->baseURI, + 'textContent' => new CutStub($dom->textContent), + ]; + + return $a; + } + + public static function castNameSpaceNode(\DOMNameSpaceNode $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'nodeName' => $dom->nodeName, + 'nodeValue' => new CutStub($dom->nodeValue), + 'nodeType' => new ConstStub(self::NODE_TYPES[$dom->nodeType], $dom->nodeType), + 'prefix' => $dom->prefix, + 'localName' => $dom->localName, + 'namespaceURI' => $dom->namespaceURI, + 'ownerDocument' => new CutStub($dom->ownerDocument), + 'parentNode' => new CutStub($dom->parentNode), + ]; + + return $a; + } + + public static function castDocument(\DOMDocument $dom, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $a += [ + 'doctype' => $dom->doctype, + 'implementation' => $dom->implementation, + 'documentElement' => new CutStub($dom->documentElement), + 'actualEncoding' => $dom->actualEncoding, + 'encoding' => $dom->encoding, + 'xmlEncoding' => $dom->xmlEncoding, + 'standalone' => $dom->standalone, + 'xmlStandalone' => $dom->xmlStandalone, + 'version' => $dom->version, + 'xmlVersion' => $dom->xmlVersion, + 'strictErrorChecking' => $dom->strictErrorChecking, + 'documentURI' => $dom->documentURI ? new LinkStub($dom->documentURI) : $dom->documentURI, + 'config' => $dom->config, + 'formatOutput' => $dom->formatOutput, + 'validateOnParse' => $dom->validateOnParse, + 'resolveExternals' => $dom->resolveExternals, + 'preserveWhiteSpace' => $dom->preserveWhiteSpace, + 'recover' => $dom->recover, + 'substituteEntities' => $dom->substituteEntities, + ]; + + if (!($filter & Caster::EXCLUDE_VERBOSE)) { + $formatOutput = $dom->formatOutput; + $dom->formatOutput = true; + $a += [Caster::PREFIX_VIRTUAL.'xml' => $dom->saveXML()]; + $dom->formatOutput = $formatOutput; + } + + return $a; + } + + public static function castCharacterData(\DOMCharacterData $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'data' => $dom->data, + 'length' => $dom->length, + ]; + + return $a; + } + + public static function castAttr(\DOMAttr $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'name' => $dom->name, + 'specified' => $dom->specified, + 'value' => $dom->value, + 'ownerElement' => $dom->ownerElement, + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + + return $a; + } + + public static function castElement(\DOMElement $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'tagName' => $dom->tagName, + 'schemaTypeInfo' => $dom->schemaTypeInfo, + ]; + + return $a; + } + + public static function castText(\DOMText $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'wholeText' => $dom->wholeText, + ]; + + return $a; + } + + public static function castTypeinfo(\DOMTypeinfo $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'typeName' => $dom->typeName, + 'typeNamespace' => $dom->typeNamespace, + ]; + + return $a; + } + + public static function castDomError(\DOMDomError $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'severity' => $dom->severity, + 'message' => $dom->message, + 'type' => $dom->type, + 'relatedException' => $dom->relatedException, + 'related_data' => $dom->related_data, + 'location' => $dom->location, + ]; + + return $a; + } + + public static function castLocator(\DOMLocator $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'lineNumber' => $dom->lineNumber, + 'columnNumber' => $dom->columnNumber, + 'offset' => $dom->offset, + 'relatedNode' => $dom->relatedNode, + 'uri' => $dom->uri ? new LinkStub($dom->uri, $dom->lineNumber) : $dom->uri, + ]; + + return $a; + } + + public static function castDocumentType(\DOMDocumentType $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'name' => $dom->name, + 'entities' => $dom->entities, + 'notations' => $dom->notations, + 'publicId' => $dom->publicId, + 'systemId' => $dom->systemId, + 'internalSubset' => $dom->internalSubset, + ]; + + return $a; + } + + public static function castNotation(\DOMNotation $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'publicId' => $dom->publicId, + 'systemId' => $dom->systemId, + ]; + + return $a; + } + + public static function castEntity(\DOMEntity $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'publicId' => $dom->publicId, + 'systemId' => $dom->systemId, + 'notationName' => $dom->notationName, + 'actualEncoding' => $dom->actualEncoding, + 'encoding' => $dom->encoding, + 'version' => $dom->version, + ]; + + return $a; + } + + public static function castProcessingInstruction(\DOMProcessingInstruction $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'target' => $dom->target, + 'data' => $dom->data, + ]; + + return $a; + } + + public static function castXPath(\DOMXPath $dom, array $a, Stub $stub, bool $isNested) + { + $a += [ + 'document' => $dom->document, + ]; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/DateCaster.php b/vendor/symfony/var-dumper/Caster/DateCaster.php new file mode 100644 index 00000000..d07bac58 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DateCaster.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts DateTimeInterface related classes to array representation. + * + * @author Dany Maillard + * + * @final + */ +class DateCaster +{ + private const PERIOD_LIMIT = 3; + + public static function castDateTime(\DateTimeInterface $d, array $a, Stub $stub, bool $isNested, int $filter) + { + $prefix = Caster::PREFIX_VIRTUAL; + $location = $d->getTimezone() ? $d->getTimezone()->getLocation() : null; + $fromNow = (new \DateTime())->diff($d); + + $title = $d->format('l, F j, Y') + ."\n".self::formatInterval($fromNow).' from now' + .($location ? ($d->format('I') ? "\nDST On" : "\nDST Off") : '') + ; + + unset( + $a[Caster::PREFIX_DYNAMIC.'date'], + $a[Caster::PREFIX_DYNAMIC.'timezone'], + $a[Caster::PREFIX_DYNAMIC.'timezone_type'] + ); + $a[$prefix.'date'] = new ConstStub(self::formatDateTime($d, $location ? ' e (P)' : ' P'), $title); + + $stub->class .= $d->format(' @U'); + + return $a; + } + + public static function castInterval(\DateInterval $interval, array $a, Stub $stub, bool $isNested, int $filter) + { + $now = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); + $numberOfSeconds = $now->add($interval)->getTimestamp() - $now->getTimestamp(); + $title = number_format($numberOfSeconds, 0, '.', ' ').'s'; + + $i = [Caster::PREFIX_VIRTUAL.'interval' => new ConstStub(self::formatInterval($interval), $title)]; + + return $filter & Caster::EXCLUDE_VERBOSE ? $i : $i + $a; + } + + private static function formatInterval(\DateInterval $i): string + { + $format = '%R '; + + if (0 === $i->y && 0 === $i->m && ($i->h >= 24 || $i->i >= 60 || $i->s >= 60)) { + $d = new \DateTimeImmutable('@0', new \DateTimeZone('UTC')); + $i = $d->diff($d->add($i)); // recalculate carry over points + $format .= 0 < $i->days ? '%ad ' : ''; + } else { + $format .= ($i->y ? '%yy ' : '').($i->m ? '%mm ' : '').($i->d ? '%dd ' : ''); + } + + $format .= $i->h || $i->i || $i->s || $i->f ? '%H:%I:'.self::formatSeconds($i->s, substr($i->f, 2)) : ''; + $format = '%R ' === $format ? '0s' : $format; + + return $i->format(rtrim($format)); + } + + public static function castTimeZone(\DateTimeZone $timeZone, array $a, Stub $stub, bool $isNested, int $filter) + { + $location = $timeZone->getLocation(); + $formatted = (new \DateTime('now', $timeZone))->format($location ? 'e (P)' : 'P'); + $title = $location && \extension_loaded('intl') ? \Locale::getDisplayRegion('-'.$location['country_code']) : ''; + + $z = [Caster::PREFIX_VIRTUAL.'timezone' => new ConstStub($formatted, $title)]; + + return $filter & Caster::EXCLUDE_VERBOSE ? $z : $z + $a; + } + + public static function castPeriod(\DatePeriod $p, array $a, Stub $stub, bool $isNested, int $filter) + { + $dates = []; + foreach (clone $p as $i => $d) { + if (self::PERIOD_LIMIT === $i) { + $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC')); + $dates[] = sprintf('%s more', ($end = $p->getEndDate()) + ? ceil(($end->format('U.u') - $d->format('U.u')) / ((int) $now->add($p->getDateInterval())->format('U.u') - (int) $now->format('U.u'))) + : $p->recurrences - $i + ); + break; + } + $dates[] = sprintf('%s) %s', $i + 1, self::formatDateTime($d)); + } + + $period = sprintf( + 'every %s, from %s%s %s', + self::formatInterval($p->getDateInterval()), + $p->include_start_date ? '[' : ']', + self::formatDateTime($p->getStartDate()), + ($end = $p->getEndDate()) ? 'to '.self::formatDateTime($end).(\PHP_VERSION_ID >= 80200 && $p->include_end_date ? ']' : '[') : 'recurring '.$p->recurrences.' time/s' + ); + + $p = [Caster::PREFIX_VIRTUAL.'period' => new ConstStub($period, implode("\n", $dates))]; + + return $filter & Caster::EXCLUDE_VERBOSE ? $p : $p + $a; + } + + private static function formatDateTime(\DateTimeInterface $d, string $extra = ''): string + { + return $d->format('Y-m-d H:i:'.self::formatSeconds($d->format('s'), $d->format('u')).$extra); + } + + private static function formatSeconds(string $s, string $us): string + { + return sprintf('%02d.%s', $s, 0 === ($len = \strlen($t = rtrim($us, '0'))) ? '0' : ($len <= 3 ? str_pad($t, 3, '0') : $us)); + } +} diff --git a/vendor/symfony/var-dumper/Caster/DoctrineCaster.php b/vendor/symfony/var-dumper/Caster/DoctrineCaster.php new file mode 100644 index 00000000..129b2cb4 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DoctrineCaster.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Doctrine\Common\Proxy\Proxy as CommonProxy; +use Doctrine\ORM\PersistentCollection; +use Doctrine\ORM\Proxy\Proxy as OrmProxy; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Doctrine related classes to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class DoctrineCaster +{ + public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, bool $isNested) + { + foreach (['__cloner__', '__initializer__'] as $k) { + if (\array_key_exists($k, $a)) { + unset($a[$k]); + ++$stub->cut; + } + } + + return $a; + } + + public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, bool $isNested) + { + foreach (['_entityPersister', '_identifier'] as $k) { + if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { + unset($a[$k]); + ++$stub->cut; + } + } + + return $a; + } + + public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, bool $isNested) + { + foreach (['snapshot', 'association', 'typeClass'] as $k) { + if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { + $a[$k] = new CutStub($a[$k]); + } + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/DsCaster.php b/vendor/symfony/var-dumper/Caster/DsCaster.php new file mode 100644 index 00000000..b34b6700 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DsCaster.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Ds\Collection; +use Ds\Map; +use Ds\Pair; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Ds extension classes to array representation. + * + * @author Jáchym Toušek + * + * @final + */ +class DsCaster +{ + public static function castCollection(Collection $c, array $a, Stub $stub, bool $isNested): array + { + $a[Caster::PREFIX_VIRTUAL.'count'] = $c->count(); + $a[Caster::PREFIX_VIRTUAL.'capacity'] = $c->capacity(); + + if (!$c instanceof Map) { + $a += $c->toArray(); + } + + return $a; + } + + public static function castMap(Map $c, array $a, Stub $stub, bool $isNested): array + { + foreach ($c as $k => $v) { + $a[] = new DsPairStub($k, $v); + } + + return $a; + } + + public static function castPair(Pair $c, array $a, Stub $stub, bool $isNested): array + { + foreach ($c->toArray() as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } + + public static function castPairStub(DsPairStub $c, array $a, Stub $stub, bool $isNested): array + { + if ($isNested) { + $stub->class = Pair::class; + $stub->value = null; + $stub->handle = 0; + + $a = $c->value; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/DsPairStub.php b/vendor/symfony/var-dumper/Caster/DsPairStub.php new file mode 100644 index 00000000..a1dcc156 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/DsPairStub.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + */ +class DsPairStub extends Stub +{ + public function __construct($key, $value) + { + $this->value = [ + Caster::PREFIX_VIRTUAL.'key' => $key, + Caster::PREFIX_VIRTUAL.'value' => $value, + ]; + } +} diff --git a/vendor/symfony/var-dumper/Caster/EnumStub.php b/vendor/symfony/var-dumper/Caster/EnumStub.php new file mode 100644 index 00000000..7a4e98a2 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/EnumStub.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents an enumeration of values. + * + * @author Nicolas Grekas + */ +class EnumStub extends Stub +{ + public $dumpKeys = true; + + public function __construct(array $values, bool $dumpKeys = true) + { + $this->value = $values; + $this->dumpKeys = $dumpKeys; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ExceptionCaster.php b/vendor/symfony/var-dumper/Caster/ExceptionCaster.php new file mode 100644 index 00000000..7f5cb65e --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ExceptionCaster.php @@ -0,0 +1,388 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Exception\ThrowingCasterException; + +/** + * Casts common Exception classes to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class ExceptionCaster +{ + public static $srcContext = 1; + public static $traceArgs = true; + public static $errorTypes = [ + \E_DEPRECATED => 'E_DEPRECATED', + \E_USER_DEPRECATED => 'E_USER_DEPRECATED', + \E_RECOVERABLE_ERROR => 'E_RECOVERABLE_ERROR', + \E_ERROR => 'E_ERROR', + \E_WARNING => 'E_WARNING', + \E_PARSE => 'E_PARSE', + \E_NOTICE => 'E_NOTICE', + \E_CORE_ERROR => 'E_CORE_ERROR', + \E_CORE_WARNING => 'E_CORE_WARNING', + \E_COMPILE_ERROR => 'E_COMPILE_ERROR', + \E_COMPILE_WARNING => 'E_COMPILE_WARNING', + \E_USER_ERROR => 'E_USER_ERROR', + \E_USER_WARNING => 'E_USER_WARNING', + \E_USER_NOTICE => 'E_USER_NOTICE', + \E_STRICT => 'E_STRICT', + ]; + + private static $framesCache = []; + + public static function castError(\Error $e, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + return self::filterExceptionArray($stub->class, $a, "\0Error\0", $filter); + } + + public static function castException(\Exception $e, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + return self::filterExceptionArray($stub->class, $a, "\0Exception\0", $filter); + } + + public static function castErrorException(\ErrorException $e, array $a, Stub $stub, bool $isNested) + { + if (isset($a[$s = Caster::PREFIX_PROTECTED.'severity'], self::$errorTypes[$a[$s]])) { + $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); + } + + return $a; + } + + public static function castThrowingCasterException(ThrowingCasterException $e, array $a, Stub $stub, bool $isNested) + { + $trace = Caster::PREFIX_VIRTUAL.'trace'; + $prefix = Caster::PREFIX_PROTECTED; + $xPrefix = "\0Exception\0"; + + if (isset($a[$xPrefix.'previous'], $a[$trace]) && $a[$xPrefix.'previous'] instanceof \Exception) { + $b = (array) $a[$xPrefix.'previous']; + $class = get_debug_type($a[$xPrefix.'previous']); + self::traceUnshift($b[$xPrefix.'trace'], $class, $b[$prefix.'file'], $b[$prefix.'line']); + $a[$trace] = new TraceStub($b[$xPrefix.'trace'], false, 0, -\count($a[$trace]->value)); + } + + unset($a[$xPrefix.'previous'], $a[$prefix.'code'], $a[$prefix.'file'], $a[$prefix.'line']); + + return $a; + } + + public static function castSilencedErrorContext(SilencedErrorContext $e, array $a, Stub $stub, bool $isNested) + { + $sPrefix = "\0".SilencedErrorContext::class."\0"; + + if (!isset($a[$s = $sPrefix.'severity'])) { + return $a; + } + + if (isset(self::$errorTypes[$a[$s]])) { + $a[$s] = new ConstStub(self::$errorTypes[$a[$s]], $a[$s]); + } + + $trace = [[ + 'file' => $a[$sPrefix.'file'], + 'line' => $a[$sPrefix.'line'], + ]]; + + if (isset($a[$sPrefix.'trace'])) { + $trace = array_merge($trace, $a[$sPrefix.'trace']); + } + + unset($a[$sPrefix.'file'], $a[$sPrefix.'line'], $a[$sPrefix.'trace']); + $a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs); + + return $a; + } + + public static function castTraceStub(TraceStub $trace, array $a, Stub $stub, bool $isNested) + { + if (!$isNested) { + return $a; + } + $stub->class = ''; + $stub->handle = 0; + $frames = $trace->value; + $prefix = Caster::PREFIX_VIRTUAL; + + $a = []; + $j = \count($frames); + if (0 > $i = $trace->sliceOffset) { + $i = max(0, $j + $i); + } + if (!isset($trace->value[$i])) { + return []; + } + $lastCall = isset($frames[$i]['function']) ? (isset($frames[$i]['class']) ? $frames[0]['class'].$frames[$i]['type'] : '').$frames[$i]['function'].'()' : ''; + $frames[] = ['function' => '']; + $collapse = false; + + for ($j += $trace->numberingOffset - $i++; isset($frames[$i]); ++$i, --$j) { + $f = $frames[$i]; + $call = isset($f['function']) ? (isset($f['class']) ? $f['class'].$f['type'] : '').$f['function'] : '???'; + + $frame = new FrameStub( + [ + 'object' => $f['object'] ?? null, + 'class' => $f['class'] ?? null, + 'type' => $f['type'] ?? null, + 'function' => $f['function'] ?? null, + ] + $frames[$i - 1], + false, + true + ); + $f = self::castFrameStub($frame, [], $frame, true); + if (isset($f[$prefix.'src'])) { + foreach ($f[$prefix.'src']->value as $label => $frame) { + if (str_starts_with($label, "\0~collapse=0")) { + if ($collapse) { + $label = substr_replace($label, '1', 11, 1); + } else { + $collapse = true; + } + } + $label = substr_replace($label, "title=Stack level $j.&", 2, 0); + } + $f = $frames[$i - 1]; + if ($trace->keepArgs && !empty($f['args']) && $frame instanceof EnumStub) { + $frame->value['arguments'] = new ArgsStub($f['args'], $f['function'] ?? null, $f['class'] ?? null); + } + } elseif ('???' !== $lastCall) { + $label = new ClassStub($lastCall); + if (isset($label->attr['ellipsis'])) { + $label->attr['ellipsis'] += 2; + $label = substr_replace($prefix, "ellipsis-type=class&ellipsis={$label->attr['ellipsis']}&ellipsis-tail=1&title=Stack level $j.", 2, 0).$label->value.'()'; + } else { + $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$label->value.'()'; + } + } else { + $label = substr_replace($prefix, "title=Stack level $j.", 2, 0).$lastCall; + } + $a[substr_replace($label, sprintf('separator=%s&', $frame instanceof EnumStub ? ' ' : ':'), 2, 0)] = $frame; + + $lastCall = $call; + } + if (null !== $trace->sliceLength) { + $a = \array_slice($a, 0, $trace->sliceLength, true); + } + + return $a; + } + + public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, bool $isNested) + { + if (!$isNested) { + return $a; + } + $f = $frame->value; + $prefix = Caster::PREFIX_VIRTUAL; + + if (isset($f['file'], $f['line'])) { + $cacheKey = $f; + unset($cacheKey['object'], $cacheKey['args']); + $cacheKey[] = self::$srcContext; + $cacheKey = implode('-', $cacheKey); + + if (isset(self::$framesCache[$cacheKey])) { + $a[$prefix.'src'] = self::$framesCache[$cacheKey]; + } else { + if (preg_match('/\((\d+)\)(?:\([\da-f]{32}\))? : (?:eval\(\)\'d code|runtime-created function)$/', $f['file'], $match)) { + $f['file'] = substr($f['file'], 0, -\strlen($match[0])); + $f['line'] = (int) $match[1]; + } + $src = $f['line']; + $srcKey = $f['file']; + $ellipsis = new LinkStub($srcKey, 0); + $srcAttr = 'collapse='.(int) $ellipsis->inVendor; + $ellipsisTail = $ellipsis->attr['ellipsis-tail'] ?? 0; + $ellipsis = $ellipsis->attr['ellipsis'] ?? 0; + + if (is_file($f['file']) && 0 <= self::$srcContext) { + if (!empty($f['class']) && (is_subclass_of($f['class'], 'Twig\Template') || is_subclass_of($f['class'], 'Twig_Template')) && method_exists($f['class'], 'getDebugInfo')) { + $template = null; + if (isset($f['object'])) { + $template = $f['object']; + } elseif ((new \ReflectionClass($f['class']))->isInstantiable()) { + $template = unserialize(sprintf('O:%d:"%s":0:{}', \strlen($f['class']), $f['class'])); + } + if (null !== $template) { + $ellipsis = 0; + $templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : ''); + $templateInfo = $template->getDebugInfo(); + if (isset($templateInfo[$f['line']])) { + if (!method_exists($template, 'getSourceContext') || !is_file($templatePath = $template->getSourceContext()->getPath())) { + $templatePath = null; + } + if ($templateSrc) { + $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, 'twig', $templatePath, $f); + $srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']]; + } + } + } + } + if ($srcKey == $f['file']) { + $src = self::extractSource(file_get_contents($f['file']), $f['line'], self::$srcContext, 'php', $f['file'], $f); + $srcKey .= ':'.$f['line']; + if ($ellipsis) { + $ellipsis += 1 + \strlen($f['line']); + } + } + $srcAttr .= sprintf('&separator= &file=%s&line=%d', rawurlencode($f['file']), $f['line']); + } else { + $srcAttr .= '&separator=:'; + } + $srcAttr .= $ellipsis ? '&ellipsis-type=path&ellipsis='.$ellipsis.'&ellipsis-tail='.$ellipsisTail : ''; + self::$framesCache[$cacheKey] = $a[$prefix.'src'] = new EnumStub(["\0~$srcAttr\0$srcKey" => $src]); + } + } + + unset($a[$prefix.'args'], $a[$prefix.'line'], $a[$prefix.'file']); + if ($frame->inTraceStub) { + unset($a[$prefix.'class'], $a[$prefix.'type'], $a[$prefix.'function']); + } + foreach ($a as $k => $v) { + if (!$v) { + unset($a[$k]); + } + } + if ($frame->keepArgs && !empty($f['args'])) { + $a[$prefix.'arguments'] = new ArgsStub($f['args'], $f['function'], $f['class']); + } + + return $a; + } + + private static function filterExceptionArray(string $xClass, array $a, string $xPrefix, int $filter): array + { + if (isset($a[$xPrefix.'trace'])) { + $trace = $a[$xPrefix.'trace']; + unset($a[$xPrefix.'trace']); // Ensures the trace is always last + } else { + $trace = []; + } + + if (!($filter & Caster::EXCLUDE_VERBOSE) && $trace) { + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + self::traceUnshift($trace, $xClass, $a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + } + $a[Caster::PREFIX_VIRTUAL.'trace'] = new TraceStub($trace, self::$traceArgs); + } + if (empty($a[$xPrefix.'previous'])) { + unset($a[$xPrefix.'previous']); + } + unset($a[$xPrefix.'string'], $a[Caster::PREFIX_DYNAMIC.'xdebug_message'], $a[Caster::PREFIX_DYNAMIC.'__destructorException']); + + if (isset($a[Caster::PREFIX_PROTECTED.'message']) && str_contains($a[Caster::PREFIX_PROTECTED.'message'], "@anonymous\0")) { + $a[Caster::PREFIX_PROTECTED.'message'] = preg_replace_callback('/[a-zA-Z_\x7f-\xff][\\\\a-zA-Z0-9_\x7f-\xff]*+@anonymous\x00.*?\.php(?:0x?|:[0-9]++\$)[0-9a-fA-F]++/', function ($m) { + return class_exists($m[0], false) ? (get_parent_class($m[0]) ?: key(class_implements($m[0])) ?: 'class').'@anonymous' : $m[0]; + }, $a[Caster::PREFIX_PROTECTED.'message']); + } + + if (isset($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line'])) { + $a[Caster::PREFIX_PROTECTED.'file'] = new LinkStub($a[Caster::PREFIX_PROTECTED.'file'], $a[Caster::PREFIX_PROTECTED.'line']); + } + + return $a; + } + + private static function traceUnshift(array &$trace, ?string $class, string $file, int $line): void + { + if (isset($trace[0]['file'], $trace[0]['line']) && $trace[0]['file'] === $file && $trace[0]['line'] === $line) { + return; + } + array_unshift($trace, [ + 'function' => $class ? 'new '.$class : null, + 'file' => $file, + 'line' => $line, + ]); + } + + private static function extractSource(string $srcLines, int $line, int $srcContext, string $lang, ?string $file, array $frame): EnumStub + { + $srcLines = explode("\n", $srcLines); + $src = []; + + for ($i = $line - 1 - $srcContext; $i <= $line - 1 + $srcContext; ++$i) { + $src[] = ($srcLines[$i] ?? '')."\n"; + } + + if ($frame['function'] ?? false) { + $stub = new CutStub(new \stdClass()); + $stub->class = (isset($frame['class']) ? $frame['class'].$frame['type'] : '').$frame['function']; + $stub->type = Stub::TYPE_OBJECT; + $stub->attr['cut_hash'] = true; + $stub->attr['file'] = $frame['file']; + $stub->attr['line'] = $frame['line']; + + try { + $caller = isset($frame['class']) ? new \ReflectionMethod($frame['class'], $frame['function']) : new \ReflectionFunction($frame['function']); + $stub->class .= ReflectionCaster::getSignature(ReflectionCaster::castFunctionAbstract($caller, [], $stub, true, Caster::EXCLUDE_VERBOSE)); + + if ($f = $caller->getFileName()) { + $stub->attr['file'] = $f; + $stub->attr['line'] = $caller->getStartLine(); + } + } catch (\ReflectionException $e) { + // ignore fake class/function + } + + $srcLines = ["\0~separator=\0" => $stub]; + } else { + $stub = null; + $srcLines = []; + } + + $ltrim = 0; + do { + $pad = null; + for ($i = $srcContext << 1; $i >= 0; --$i) { + if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) { + if (null === $pad) { + $pad = $c; + } + if ((' ' !== $c && "\t" !== $c) || $pad !== $c) { + break; + } + } + } + ++$ltrim; + } while (0 > $i && null !== $pad); + + --$ltrim; + + foreach ($src as $i => $c) { + if ($ltrim) { + $c = isset($c[$ltrim]) && "\r" !== $c[$ltrim] ? substr($c, $ltrim) : ltrim($c, " \t"); + } + $c = substr($c, 0, -1); + if ($i !== $srcContext) { + $c = new ConstStub('default', $c); + } else { + $c = new ConstStub($c, $stub ? 'in '.$stub->class : ''); + if (null !== $file) { + $c->attr['file'] = $file; + $c->attr['line'] = $line; + } + } + $c->attr['lang'] = $lang; + $srcLines[sprintf("\0~separator=› &%d\0", $i + $line - $srcContext)] = $c; + } + + return new EnumStub($srcLines); + } +} diff --git a/vendor/symfony/var-dumper/Caster/FiberCaster.php b/vendor/symfony/var-dumper/Caster/FiberCaster.php new file mode 100644 index 00000000..c74a9e59 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/FiberCaster.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Fiber related classes to array representation. + * + * @author Grégoire Pineau + */ +final class FiberCaster +{ + public static function castFiber(\Fiber $fiber, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($fiber->isTerminated()) { + $status = 'terminated'; + } elseif ($fiber->isRunning()) { + $status = 'running'; + } elseif ($fiber->isSuspended()) { + $status = 'suspended'; + } elseif ($fiber->isStarted()) { + $status = 'started'; + } else { + $status = 'not started'; + } + + $a[$prefix.'status'] = $status; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/FrameStub.php b/vendor/symfony/var-dumper/Caster/FrameStub.php new file mode 100644 index 00000000..87867552 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/FrameStub.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents a single backtrace frame as returned by debug_backtrace() or Exception->getTrace(). + * + * @author Nicolas Grekas + */ +class FrameStub extends EnumStub +{ + public $keepArgs; + public $inTraceStub; + + public function __construct(array $frame, bool $keepArgs = true, bool $inTraceStub = false) + { + $this->value = $frame; + $this->keepArgs = $keepArgs; + $this->inTraceStub = $inTraceStub; + } +} diff --git a/vendor/symfony/var-dumper/Caster/GmpCaster.php b/vendor/symfony/var-dumper/Caster/GmpCaster.php new file mode 100644 index 00000000..b018cc7f --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/GmpCaster.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts GMP objects to array representation. + * + * @author Hamza Amrouche + * @author Nicolas Grekas + * + * @final + */ +class GmpCaster +{ + public static function castGmp(\GMP $gmp, array $a, Stub $stub, bool $isNested, int $filter): array + { + $a[Caster::PREFIX_VIRTUAL.'value'] = new ConstStub(gmp_strval($gmp), gmp_strval($gmp)); + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ImagineCaster.php b/vendor/symfony/var-dumper/Caster/ImagineCaster.php new file mode 100644 index 00000000..d1289da3 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ImagineCaster.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Imagine\Image\ImageInterface; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Grégoire Pineau + */ +final class ImagineCaster +{ + public static function castImage(ImageInterface $c, array $a, Stub $stub, bool $isNested): array + { + $imgData = $c->get('png'); + if (\strlen($imgData) > 1 * 1000 * 1000) { + $a += [ + Caster::PREFIX_VIRTUAL.'image' => new ConstStub($c->getSize()), + ]; + } else { + $a += [ + Caster::PREFIX_VIRTUAL.'image' => new ImgStub($imgData, 'image/png', $c->getSize()), + ]; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ImgStub.php b/vendor/symfony/var-dumper/Caster/ImgStub.php new file mode 100644 index 00000000..a16681f7 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ImgStub.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * @author Grégoire Pineau + */ +class ImgStub extends ConstStub +{ + public function __construct(string $data, string $contentType, string $size = '') + { + $this->value = ''; + $this->attr['img-data'] = $data; + $this->attr['img-size'] = $size; + $this->attr['content-type'] = $contentType; + } +} diff --git a/vendor/symfony/var-dumper/Caster/IntlCaster.php b/vendor/symfony/var-dumper/Caster/IntlCaster.php new file mode 100644 index 00000000..1ed91d4d --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/IntlCaster.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * @author Jan Schädlich + * + * @final + */ +class IntlCaster +{ + public static function castMessageFormatter(\MessageFormatter $c, array $a, Stub $stub, bool $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), + Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), + ]; + + return self::castError($c, $a); + } + + public static function castNumberFormatter(\NumberFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $a += [ + Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), + Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), + ]; + + if ($filter & Caster::EXCLUDE_VERBOSE) { + $stub->cut += 3; + + return self::castError($c, $a); + } + + $a += [ + Caster::PREFIX_VIRTUAL.'attributes' => new EnumStub( + [ + 'PARSE_INT_ONLY' => $c->getAttribute(\NumberFormatter::PARSE_INT_ONLY), + 'GROUPING_USED' => $c->getAttribute(\NumberFormatter::GROUPING_USED), + 'DECIMAL_ALWAYS_SHOWN' => $c->getAttribute(\NumberFormatter::DECIMAL_ALWAYS_SHOWN), + 'MAX_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_INTEGER_DIGITS), + 'MIN_INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_INTEGER_DIGITS), + 'INTEGER_DIGITS' => $c->getAttribute(\NumberFormatter::INTEGER_DIGITS), + 'MAX_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_FRACTION_DIGITS), + 'MIN_FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_FRACTION_DIGITS), + 'FRACTION_DIGITS' => $c->getAttribute(\NumberFormatter::FRACTION_DIGITS), + 'MULTIPLIER' => $c->getAttribute(\NumberFormatter::MULTIPLIER), + 'GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::GROUPING_SIZE), + 'ROUNDING_MODE' => $c->getAttribute(\NumberFormatter::ROUNDING_MODE), + 'ROUNDING_INCREMENT' => $c->getAttribute(\NumberFormatter::ROUNDING_INCREMENT), + 'FORMAT_WIDTH' => $c->getAttribute(\NumberFormatter::FORMAT_WIDTH), + 'PADDING_POSITION' => $c->getAttribute(\NumberFormatter::PADDING_POSITION), + 'SECONDARY_GROUPING_SIZE' => $c->getAttribute(\NumberFormatter::SECONDARY_GROUPING_SIZE), + 'SIGNIFICANT_DIGITS_USED' => $c->getAttribute(\NumberFormatter::SIGNIFICANT_DIGITS_USED), + 'MIN_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MIN_SIGNIFICANT_DIGITS), + 'MAX_SIGNIFICANT_DIGITS' => $c->getAttribute(\NumberFormatter::MAX_SIGNIFICANT_DIGITS), + 'LENIENT_PARSE' => $c->getAttribute(\NumberFormatter::LENIENT_PARSE), + ] + ), + Caster::PREFIX_VIRTUAL.'text_attributes' => new EnumStub( + [ + 'POSITIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_PREFIX), + 'POSITIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::POSITIVE_SUFFIX), + 'NEGATIVE_PREFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_PREFIX), + 'NEGATIVE_SUFFIX' => $c->getTextAttribute(\NumberFormatter::NEGATIVE_SUFFIX), + 'PADDING_CHARACTER' => $c->getTextAttribute(\NumberFormatter::PADDING_CHARACTER), + 'CURRENCY_CODE' => $c->getTextAttribute(\NumberFormatter::CURRENCY_CODE), + 'DEFAULT_RULESET' => $c->getTextAttribute(\NumberFormatter::DEFAULT_RULESET), + 'PUBLIC_RULESETS' => $c->getTextAttribute(\NumberFormatter::PUBLIC_RULESETS), + ] + ), + Caster::PREFIX_VIRTUAL.'symbols' => new EnumStub( + [ + 'DECIMAL_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL), + 'GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::GROUPING_SEPARATOR_SYMBOL), + 'PATTERN_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::PATTERN_SEPARATOR_SYMBOL), + 'PERCENT_SYMBOL' => $c->getSymbol(\NumberFormatter::PERCENT_SYMBOL), + 'ZERO_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::ZERO_DIGIT_SYMBOL), + 'DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::DIGIT_SYMBOL), + 'MINUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::MINUS_SIGN_SYMBOL), + 'PLUS_SIGN_SYMBOL' => $c->getSymbol(\NumberFormatter::PLUS_SIGN_SYMBOL), + 'CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::CURRENCY_SYMBOL), + 'INTL_CURRENCY_SYMBOL' => $c->getSymbol(\NumberFormatter::INTL_CURRENCY_SYMBOL), + 'MONETARY_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_SEPARATOR_SYMBOL), + 'EXPONENTIAL_SYMBOL' => $c->getSymbol(\NumberFormatter::EXPONENTIAL_SYMBOL), + 'PERMILL_SYMBOL' => $c->getSymbol(\NumberFormatter::PERMILL_SYMBOL), + 'PAD_ESCAPE_SYMBOL' => $c->getSymbol(\NumberFormatter::PAD_ESCAPE_SYMBOL), + 'INFINITY_SYMBOL' => $c->getSymbol(\NumberFormatter::INFINITY_SYMBOL), + 'NAN_SYMBOL' => $c->getSymbol(\NumberFormatter::NAN_SYMBOL), + 'SIGNIFICANT_DIGIT_SYMBOL' => $c->getSymbol(\NumberFormatter::SIGNIFICANT_DIGIT_SYMBOL), + 'MONETARY_GROUPING_SEPARATOR_SYMBOL' => $c->getSymbol(\NumberFormatter::MONETARY_GROUPING_SEPARATOR_SYMBOL), + ] + ), + ]; + + return self::castError($c, $a); + } + + public static function castIntlTimeZone(\IntlTimeZone $c, array $a, Stub $stub, bool $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'display_name' => $c->getDisplayName(), + Caster::PREFIX_VIRTUAL.'id' => $c->getID(), + Caster::PREFIX_VIRTUAL.'raw_offset' => $c->getRawOffset(), + ]; + + if ($c->useDaylightTime()) { + $a += [ + Caster::PREFIX_VIRTUAL.'dst_savings' => $c->getDSTSavings(), + ]; + } + + return self::castError($c, $a); + } + + public static function castIntlCalendar(\IntlCalendar $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $a += [ + Caster::PREFIX_VIRTUAL.'type' => $c->getType(), + Caster::PREFIX_VIRTUAL.'first_day_of_week' => $c->getFirstDayOfWeek(), + Caster::PREFIX_VIRTUAL.'minimal_days_in_first_week' => $c->getMinimalDaysInFirstWeek(), + Caster::PREFIX_VIRTUAL.'repeated_wall_time_option' => $c->getRepeatedWallTimeOption(), + Caster::PREFIX_VIRTUAL.'skipped_wall_time_option' => $c->getSkippedWallTimeOption(), + Caster::PREFIX_VIRTUAL.'time' => $c->getTime(), + Caster::PREFIX_VIRTUAL.'in_daylight_time' => $c->inDaylightTime(), + Caster::PREFIX_VIRTUAL.'is_lenient' => $c->isLenient(), + Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), + ]; + + return self::castError($c, $a); + } + + public static function castIntlDateFormatter(\IntlDateFormatter $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $a += [ + Caster::PREFIX_VIRTUAL.'locale' => $c->getLocale(), + Caster::PREFIX_VIRTUAL.'pattern' => $c->getPattern(), + Caster::PREFIX_VIRTUAL.'calendar' => $c->getCalendar(), + Caster::PREFIX_VIRTUAL.'time_zone_id' => $c->getTimeZoneId(), + Caster::PREFIX_VIRTUAL.'time_type' => $c->getTimeType(), + Caster::PREFIX_VIRTUAL.'date_type' => $c->getDateType(), + Caster::PREFIX_VIRTUAL.'calendar_object' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getCalendarObject()) : $c->getCalendarObject(), + Caster::PREFIX_VIRTUAL.'time_zone' => ($filter & Caster::EXCLUDE_VERBOSE) ? new CutStub($c->getTimeZone()) : $c->getTimeZone(), + ]; + + return self::castError($c, $a); + } + + private static function castError(object $c, array $a): array + { + if ($errorCode = $c->getErrorCode()) { + $a += [ + Caster::PREFIX_VIRTUAL.'error_code' => $errorCode, + Caster::PREFIX_VIRTUAL.'error_message' => $c->getErrorMessage(), + ]; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/LinkStub.php b/vendor/symfony/var-dumper/Caster/LinkStub.php new file mode 100644 index 00000000..7e078033 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/LinkStub.php @@ -0,0 +1,108 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +/** + * Represents a file or a URL. + * + * @author Nicolas Grekas + */ +class LinkStub extends ConstStub +{ + public $inVendor = false; + + private static $vendorRoots; + private static $composerRoots; + + public function __construct(string $label, int $line = 0, string $href = null) + { + $this->value = $label; + + if (null === $href) { + $href = $label; + } + if (!\is_string($href)) { + return; + } + if (str_starts_with($href, 'file://')) { + if ($href === $label) { + $label = substr($label, 7); + } + $href = substr($href, 7); + } elseif (str_contains($href, '://')) { + $this->attr['href'] = $href; + + return; + } + if (!is_file($href)) { + return; + } + if ($line) { + $this->attr['line'] = $line; + } + if ($label !== $this->attr['file'] = realpath($href) ?: $href) { + return; + } + if ($composerRoot = $this->getComposerRoot($href, $this->inVendor)) { + $this->attr['ellipsis'] = \strlen($href) - \strlen($composerRoot) + 1; + $this->attr['ellipsis-type'] = 'path'; + $this->attr['ellipsis-tail'] = 1 + ($this->inVendor ? 2 + \strlen(implode('', \array_slice(explode(\DIRECTORY_SEPARATOR, substr($href, 1 - $this->attr['ellipsis'])), 0, 2))) : 0); + } elseif (3 < \count($ellipsis = explode(\DIRECTORY_SEPARATOR, $href))) { + $this->attr['ellipsis'] = 2 + \strlen(implode('', \array_slice($ellipsis, -2))); + $this->attr['ellipsis-type'] = 'path'; + $this->attr['ellipsis-tail'] = 1; + } + } + + private function getComposerRoot(string $file, bool &$inVendor) + { + if (null === self::$vendorRoots) { + self::$vendorRoots = []; + + foreach (get_declared_classes() as $class) { + if ('C' === $class[0] && str_starts_with($class, 'ComposerAutoloaderInit')) { + $r = new \ReflectionClass($class); + $v = \dirname($r->getFileName(), 2); + if (is_file($v.'/composer/installed.json')) { + self::$vendorRoots[] = $v.\DIRECTORY_SEPARATOR; + } + } + } + } + $inVendor = false; + + if (isset(self::$composerRoots[$dir = \dirname($file)])) { + return self::$composerRoots[$dir]; + } + + foreach (self::$vendorRoots as $root) { + if ($inVendor = str_starts_with($file, $root)) { + return $root; + } + } + + $parent = $dir; + while (!@is_file($parent.'/composer.json')) { + if (!@file_exists($parent)) { + // open_basedir restriction in effect + break; + } + if ($parent === \dirname($parent)) { + return self::$composerRoots[$dir] = false; + } + + $parent = \dirname($parent); + } + + return self::$composerRoots[$dir] = $parent.\DIRECTORY_SEPARATOR; + } +} diff --git a/vendor/symfony/var-dumper/Caster/MemcachedCaster.php b/vendor/symfony/var-dumper/Caster/MemcachedCaster.php new file mode 100644 index 00000000..cfef19ac --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/MemcachedCaster.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Jan Schädlich + * + * @final + */ +class MemcachedCaster +{ + private static $optionConstants; + private static $defaultOptions; + + public static function castMemcached(\Memcached $c, array $a, Stub $stub, bool $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'servers' => $c->getServerList(), + Caster::PREFIX_VIRTUAL.'options' => new EnumStub( + self::getNonDefaultOptions($c) + ), + ]; + + return $a; + } + + private static function getNonDefaultOptions(\Memcached $c): array + { + self::$defaultOptions = self::$defaultOptions ?? self::discoverDefaultOptions(); + self::$optionConstants = self::$optionConstants ?? self::getOptionConstants(); + + $nonDefaultOptions = []; + foreach (self::$optionConstants as $constantKey => $value) { + if (self::$defaultOptions[$constantKey] !== $option = $c->getOption($value)) { + $nonDefaultOptions[$constantKey] = $option; + } + } + + return $nonDefaultOptions; + } + + private static function discoverDefaultOptions(): array + { + $defaultMemcached = new \Memcached(); + $defaultMemcached->addServer('127.0.0.1', 11211); + + $defaultOptions = []; + self::$optionConstants = self::$optionConstants ?? self::getOptionConstants(); + + foreach (self::$optionConstants as $constantKey => $value) { + $defaultOptions[$constantKey] = $defaultMemcached->getOption($value); + } + + return $defaultOptions; + } + + private static function getOptionConstants(): array + { + $reflectedMemcached = new \ReflectionClass(\Memcached::class); + + $optionConstants = []; + foreach ($reflectedMemcached->getConstants() as $constantKey => $value) { + if (str_starts_with($constantKey, 'OPT_')) { + $optionConstants[$constantKey] = $value; + } + } + + return $optionConstants; + } +} diff --git a/vendor/symfony/var-dumper/Caster/MysqliCaster.php b/vendor/symfony/var-dumper/Caster/MysqliCaster.php new file mode 100644 index 00000000..bfe6f082 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/MysqliCaster.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @internal + */ +final class MysqliCaster +{ + public static function castMysqliDriver(\mysqli_driver $c, array $a, Stub $stub, bool $isNested): array + { + foreach ($a as $k => $v) { + if (isset($c->$k)) { + $a[$k] = $c->$k; + } + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/PdoCaster.php b/vendor/symfony/var-dumper/Caster/PdoCaster.php new file mode 100644 index 00000000..140473b5 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/PdoCaster.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts PDO related classes to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class PdoCaster +{ + private const PDO_ATTRIBUTES = [ + 'CASE' => [ + \PDO::CASE_LOWER => 'LOWER', + \PDO::CASE_NATURAL => 'NATURAL', + \PDO::CASE_UPPER => 'UPPER', + ], + 'ERRMODE' => [ + \PDO::ERRMODE_SILENT => 'SILENT', + \PDO::ERRMODE_WARNING => 'WARNING', + \PDO::ERRMODE_EXCEPTION => 'EXCEPTION', + ], + 'TIMEOUT', + 'PREFETCH', + 'AUTOCOMMIT', + 'PERSISTENT', + 'DRIVER_NAME', + 'SERVER_INFO', + 'ORACLE_NULLS' => [ + \PDO::NULL_NATURAL => 'NATURAL', + \PDO::NULL_EMPTY_STRING => 'EMPTY_STRING', + \PDO::NULL_TO_STRING => 'TO_STRING', + ], + 'CLIENT_VERSION', + 'SERVER_VERSION', + 'STATEMENT_CLASS', + 'EMULATE_PREPARES', + 'CONNECTION_STATUS', + 'STRINGIFY_FETCHES', + 'DEFAULT_FETCH_MODE' => [ + \PDO::FETCH_ASSOC => 'ASSOC', + \PDO::FETCH_BOTH => 'BOTH', + \PDO::FETCH_LAZY => 'LAZY', + \PDO::FETCH_NUM => 'NUM', + \PDO::FETCH_OBJ => 'OBJ', + ], + ]; + + public static function castPdo(\PDO $c, array $a, Stub $stub, bool $isNested) + { + $attr = []; + $errmode = $c->getAttribute(\PDO::ATTR_ERRMODE); + $c->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); + + foreach (self::PDO_ATTRIBUTES as $k => $v) { + if (!isset($k[0])) { + $k = $v; + $v = []; + } + + try { + $attr[$k] = 'ERRMODE' === $k ? $errmode : $c->getAttribute(\constant('PDO::ATTR_'.$k)); + if ($v && isset($v[$attr[$k]])) { + $attr[$k] = new ConstStub($v[$attr[$k]], $attr[$k]); + } + } catch (\Exception $e) { + } + } + if (isset($attr[$k = 'STATEMENT_CLASS'][1])) { + if ($attr[$k][1]) { + $attr[$k][1] = new ArgsStub($attr[$k][1], '__construct', $attr[$k][0]); + } + $attr[$k][0] = new ClassStub($attr[$k][0]); + } + + $prefix = Caster::PREFIX_VIRTUAL; + $a += [ + $prefix.'inTransaction' => method_exists($c, 'inTransaction'), + $prefix.'errorInfo' => $c->errorInfo(), + $prefix.'attributes' => new EnumStub($attr), + ]; + + if ($a[$prefix.'inTransaction']) { + $a[$prefix.'inTransaction'] = $c->inTransaction(); + } else { + unset($a[$prefix.'inTransaction']); + } + + if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { + unset($a[$prefix.'errorInfo']); + } + + $c->setAttribute(\PDO::ATTR_ERRMODE, $errmode); + + return $a; + } + + public static function castPdoStatement(\PDOStatement $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + $a[$prefix.'errorInfo'] = $c->errorInfo(); + + if (!isset($a[$prefix.'errorInfo'][1], $a[$prefix.'errorInfo'][2])) { + unset($a[$prefix.'errorInfo']); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/PgSqlCaster.php b/vendor/symfony/var-dumper/Caster/PgSqlCaster.php new file mode 100644 index 00000000..d8e5b525 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/PgSqlCaster.php @@ -0,0 +1,156 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts pqsql resources to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class PgSqlCaster +{ + private const PARAM_CODES = [ + 'server_encoding', + 'client_encoding', + 'is_superuser', + 'session_authorization', + 'DateStyle', + 'TimeZone', + 'IntervalStyle', + 'integer_datetimes', + 'application_name', + 'standard_conforming_strings', + ]; + + private const TRANSACTION_STATUS = [ + \PGSQL_TRANSACTION_IDLE => 'PGSQL_TRANSACTION_IDLE', + \PGSQL_TRANSACTION_ACTIVE => 'PGSQL_TRANSACTION_ACTIVE', + \PGSQL_TRANSACTION_INTRANS => 'PGSQL_TRANSACTION_INTRANS', + \PGSQL_TRANSACTION_INERROR => 'PGSQL_TRANSACTION_INERROR', + \PGSQL_TRANSACTION_UNKNOWN => 'PGSQL_TRANSACTION_UNKNOWN', + ]; + + private const RESULT_STATUS = [ + \PGSQL_EMPTY_QUERY => 'PGSQL_EMPTY_QUERY', + \PGSQL_COMMAND_OK => 'PGSQL_COMMAND_OK', + \PGSQL_TUPLES_OK => 'PGSQL_TUPLES_OK', + \PGSQL_COPY_OUT => 'PGSQL_COPY_OUT', + \PGSQL_COPY_IN => 'PGSQL_COPY_IN', + \PGSQL_BAD_RESPONSE => 'PGSQL_BAD_RESPONSE', + \PGSQL_NONFATAL_ERROR => 'PGSQL_NONFATAL_ERROR', + \PGSQL_FATAL_ERROR => 'PGSQL_FATAL_ERROR', + ]; + + private const DIAG_CODES = [ + 'severity' => \PGSQL_DIAG_SEVERITY, + 'sqlstate' => \PGSQL_DIAG_SQLSTATE, + 'message' => \PGSQL_DIAG_MESSAGE_PRIMARY, + 'detail' => \PGSQL_DIAG_MESSAGE_DETAIL, + 'hint' => \PGSQL_DIAG_MESSAGE_HINT, + 'statement position' => \PGSQL_DIAG_STATEMENT_POSITION, + 'internal position' => \PGSQL_DIAG_INTERNAL_POSITION, + 'internal query' => \PGSQL_DIAG_INTERNAL_QUERY, + 'context' => \PGSQL_DIAG_CONTEXT, + 'file' => \PGSQL_DIAG_SOURCE_FILE, + 'line' => \PGSQL_DIAG_SOURCE_LINE, + 'function' => \PGSQL_DIAG_SOURCE_FUNCTION, + ]; + + public static function castLargeObject($lo, array $a, Stub $stub, bool $isNested) + { + $a['seek position'] = pg_lo_tell($lo); + + return $a; + } + + public static function castLink($link, array $a, Stub $stub, bool $isNested) + { + $a['status'] = pg_connection_status($link); + $a['status'] = new ConstStub(\PGSQL_CONNECTION_OK === $a['status'] ? 'PGSQL_CONNECTION_OK' : 'PGSQL_CONNECTION_BAD', $a['status']); + $a['busy'] = pg_connection_busy($link); + + $a['transaction'] = pg_transaction_status($link); + if (isset(self::TRANSACTION_STATUS[$a['transaction']])) { + $a['transaction'] = new ConstStub(self::TRANSACTION_STATUS[$a['transaction']], $a['transaction']); + } + + $a['pid'] = pg_get_pid($link); + $a['last error'] = pg_last_error($link); + $a['last notice'] = pg_last_notice($link); + $a['host'] = pg_host($link); + $a['port'] = pg_port($link); + $a['dbname'] = pg_dbname($link); + $a['options'] = pg_options($link); + $a['version'] = pg_version($link); + + foreach (self::PARAM_CODES as $v) { + if (false !== $s = pg_parameter_status($link, $v)) { + $a['param'][$v] = $s; + } + } + + $a['param']['client_encoding'] = pg_client_encoding($link); + $a['param'] = new EnumStub($a['param']); + + return $a; + } + + public static function castResult($result, array $a, Stub $stub, bool $isNested) + { + $a['num rows'] = pg_num_rows($result); + $a['status'] = pg_result_status($result); + if (isset(self::RESULT_STATUS[$a['status']])) { + $a['status'] = new ConstStub(self::RESULT_STATUS[$a['status']], $a['status']); + } + $a['command-completion tag'] = pg_result_status($result, \PGSQL_STATUS_STRING); + + if (-1 === $a['num rows']) { + foreach (self::DIAG_CODES as $k => $v) { + $a['error'][$k] = pg_result_error_field($result, $v); + } + } + + $a['affected rows'] = pg_affected_rows($result); + $a['last OID'] = pg_last_oid($result); + + $fields = pg_num_fields($result); + + for ($i = 0; $i < $fields; ++$i) { + $field = [ + 'name' => pg_field_name($result, $i), + 'table' => sprintf('%s (OID: %s)', pg_field_table($result, $i), pg_field_table($result, $i, true)), + 'type' => sprintf('%s (OID: %s)', pg_field_type($result, $i), pg_field_type_oid($result, $i)), + 'nullable' => (bool) pg_field_is_null($result, $i), + 'storage' => pg_field_size($result, $i).' bytes', + 'display' => pg_field_prtlen($result, $i).' chars', + ]; + if (' (OID: )' === $field['table']) { + $field['table'] = null; + } + if ('-1 bytes' === $field['storage']) { + $field['storage'] = 'variable size'; + } elseif ('1 bytes' === $field['storage']) { + $field['storage'] = '1 byte'; + } + if ('1 chars' === $field['display']) { + $field['display'] = '1 char'; + } + $a['fields'][] = new EnumStub($field); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php b/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php new file mode 100644 index 00000000..e7120191 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ProxyManagerCaster.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use ProxyManager\Proxy\ProxyInterface; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Nicolas Grekas + * + * @final + */ +class ProxyManagerCaster +{ + public static function castProxy(ProxyInterface $c, array $a, Stub $stub, bool $isNested) + { + if ($parent = get_parent_class($c)) { + $stub->class .= ' - '.$parent; + } + $stub->class .= '@proxy'; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php b/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php new file mode 100644 index 00000000..db4bba8d --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/RdKafkaCaster.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use RdKafka\Conf; +use RdKafka\Exception as RdKafkaException; +use RdKafka\KafkaConsumer; +use RdKafka\Message; +use RdKafka\Metadata\Broker as BrokerMetadata; +use RdKafka\Metadata\Collection as CollectionMetadata; +use RdKafka\Metadata\Partition as PartitionMetadata; +use RdKafka\Metadata\Topic as TopicMetadata; +use RdKafka\Topic; +use RdKafka\TopicConf; +use RdKafka\TopicPartition; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts RdKafka related classes to array representation. + * + * @author Romain Neutron + */ +class RdKafkaCaster +{ + public static function castKafkaConsumer(KafkaConsumer $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + try { + $assignment = $c->getAssignment(); + } catch (RdKafkaException $e) { + $assignment = []; + } + + $a += [ + $prefix.'subscription' => $c->getSubscription(), + $prefix.'assignment' => $assignment, + ]; + + $a += self::extractMetadata($c); + + return $a; + } + + public static function castTopic(Topic $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'name' => $c->getName(), + ]; + + return $a; + } + + public static function castTopicPartition(TopicPartition $c, array $a) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'offset' => $c->getOffset(), + $prefix.'partition' => $c->getPartition(), + $prefix.'topic' => $c->getTopic(), + ]; + + return $a; + } + + public static function castMessage(Message $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'errstr' => $c->errstr(), + ]; + + return $a; + } + + public static function castConf(Conf $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + foreach ($c->dump() as $key => $value) { + $a[$prefix.$key] = $value; + } + + return $a; + } + + public static function castTopicConf(TopicConf $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + foreach ($c->dump() as $key => $value) { + $a[$prefix.$key] = $value; + } + + return $a; + } + + public static function castRdKafka(\RdKafka $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'out_q_len' => $c->getOutQLen(), + ]; + + $a += self::extractMetadata($c); + + return $a; + } + + public static function castCollectionMetadata(CollectionMetadata $c, array $a, Stub $stub, bool $isNested) + { + $a += iterator_to_array($c); + + return $a; + } + + public static function castTopicMetadata(TopicMetadata $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'name' => $c->getTopic(), + $prefix.'partitions' => $c->getPartitions(), + ]; + + return $a; + } + + public static function castPartitionMetadata(PartitionMetadata $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'id' => $c->getId(), + $prefix.'err' => $c->getErr(), + $prefix.'leader' => $c->getLeader(), + ]; + + return $a; + } + + public static function castBrokerMetadata(BrokerMetadata $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + $a += [ + $prefix.'id' => $c->getId(), + $prefix.'host' => $c->getHost(), + $prefix.'port' => $c->getPort(), + ]; + + return $a; + } + + private static function extractMetadata($c) + { + $prefix = Caster::PREFIX_VIRTUAL; + + try { + $m = $c->getMetadata(true, null, 500); + } catch (RdKafkaException $e) { + return []; + } + + return [ + $prefix.'orig_broker_id' => $m->getOrigBrokerId(), + $prefix.'orig_broker_name' => $m->getOrigBrokerName(), + $prefix.'brokers' => $m->getBrokers(), + $prefix.'topics' => $m->getTopics(), + ]; + } +} diff --git a/vendor/symfony/var-dumper/Caster/RedisCaster.php b/vendor/symfony/var-dumper/Caster/RedisCaster.php new file mode 100644 index 00000000..8f97eaad --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/RedisCaster.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Redis class from ext-redis to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class RedisCaster +{ + private const SERIALIZERS = [ + \Redis::SERIALIZER_NONE => 'NONE', + \Redis::SERIALIZER_PHP => 'PHP', + 2 => 'IGBINARY', // Optional Redis::SERIALIZER_IGBINARY + ]; + + private const MODES = [ + \Redis::ATOMIC => 'ATOMIC', + \Redis::MULTI => 'MULTI', + \Redis::PIPELINE => 'PIPELINE', + ]; + + private const COMPRESSION_MODES = [ + 0 => 'NONE', // Redis::COMPRESSION_NONE + 1 => 'LZF', // Redis::COMPRESSION_LZF + ]; + + private const FAILOVER_OPTIONS = [ + \RedisCluster::FAILOVER_NONE => 'NONE', + \RedisCluster::FAILOVER_ERROR => 'ERROR', + \RedisCluster::FAILOVER_DISTRIBUTE => 'DISTRIBUTE', + \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES => 'DISTRIBUTE_SLAVES', + ]; + + public static function castRedis(\Redis $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if (!$connected = $c->isConnected()) { + return $a + [ + $prefix.'isConnected' => $connected, + ]; + } + + $mode = $c->getMode(); + + return $a + [ + $prefix.'isConnected' => $connected, + $prefix.'host' => $c->getHost(), + $prefix.'port' => $c->getPort(), + $prefix.'auth' => $c->getAuth(), + $prefix.'mode' => isset(self::MODES[$mode]) ? new ConstStub(self::MODES[$mode], $mode) : $mode, + $prefix.'dbNum' => $c->getDbNum(), + $prefix.'timeout' => $c->getTimeout(), + $prefix.'lastError' => $c->getLastError(), + $prefix.'persistentId' => $c->getPersistentID(), + $prefix.'options' => self::getRedisOptions($c), + ]; + } + + public static function castRedisArray(\RedisArray $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + return $a + [ + $prefix.'hosts' => $c->_hosts(), + $prefix.'function' => ClassStub::wrapCallable($c->_function()), + $prefix.'lastError' => $c->getLastError(), + $prefix.'options' => self::getRedisOptions($c), + ]; + } + + public static function castRedisCluster(\RedisCluster $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + $failover = $c->getOption(\RedisCluster::OPT_SLAVE_FAILOVER); + + $a += [ + $prefix.'_masters' => $c->_masters(), + $prefix.'_redir' => $c->_redir(), + $prefix.'mode' => new ConstStub($c->getMode() ? 'MULTI' : 'ATOMIC', $c->getMode()), + $prefix.'lastError' => $c->getLastError(), + $prefix.'options' => self::getRedisOptions($c, [ + 'SLAVE_FAILOVER' => isset(self::FAILOVER_OPTIONS[$failover]) ? new ConstStub(self::FAILOVER_OPTIONS[$failover], $failover) : $failover, + ]), + ]; + + return $a; + } + + /** + * @param \Redis|\RedisArray|\RedisCluster $redis + */ + private static function getRedisOptions($redis, array $options = []): EnumStub + { + $serializer = $redis->getOption(\Redis::OPT_SERIALIZER); + if (\is_array($serializer)) { + foreach ($serializer as &$v) { + if (isset(self::SERIALIZERS[$v])) { + $v = new ConstStub(self::SERIALIZERS[$v], $v); + } + } + } elseif (isset(self::SERIALIZERS[$serializer])) { + $serializer = new ConstStub(self::SERIALIZERS[$serializer], $serializer); + } + + $compression = \defined('Redis::OPT_COMPRESSION') ? $redis->getOption(\Redis::OPT_COMPRESSION) : 0; + if (\is_array($compression)) { + foreach ($compression as &$v) { + if (isset(self::COMPRESSION_MODES[$v])) { + $v = new ConstStub(self::COMPRESSION_MODES[$v], $v); + } + } + } elseif (isset(self::COMPRESSION_MODES[$compression])) { + $compression = new ConstStub(self::COMPRESSION_MODES[$compression], $compression); + } + + $retry = \defined('Redis::OPT_SCAN') ? $redis->getOption(\Redis::OPT_SCAN) : 0; + if (\is_array($retry)) { + foreach ($retry as &$v) { + $v = new ConstStub($v ? 'RETRY' : 'NORETRY', $v); + } + } else { + $retry = new ConstStub($retry ? 'RETRY' : 'NORETRY', $retry); + } + + $options += [ + 'TCP_KEEPALIVE' => \defined('Redis::OPT_TCP_KEEPALIVE') ? $redis->getOption(\Redis::OPT_TCP_KEEPALIVE) : 0, + 'READ_TIMEOUT' => $redis->getOption(\Redis::OPT_READ_TIMEOUT), + 'COMPRESSION' => $compression, + 'SERIALIZER' => $serializer, + 'PREFIX' => $redis->getOption(\Redis::OPT_PREFIX), + 'SCAN' => $retry, + ]; + + return new EnumStub($options); + } +} diff --git a/vendor/symfony/var-dumper/Caster/ReflectionCaster.php b/vendor/symfony/var-dumper/Caster/ReflectionCaster.php new file mode 100644 index 00000000..ef6a85ef --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ReflectionCaster.php @@ -0,0 +1,442 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts Reflector related classes to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class ReflectionCaster +{ + public const UNSET_CLOSURE_FILE_INFO = ['Closure' => __CLASS__.'::unsetClosureFileInfo']; + + private const EXTRA_MAP = [ + 'docComment' => 'getDocComment', + 'extension' => 'getExtensionName', + 'isDisabled' => 'isDisabled', + 'isDeprecated' => 'isDeprecated', + 'isInternal' => 'isInternal', + 'isUserDefined' => 'isUserDefined', + 'isGenerator' => 'isGenerator', + 'isVariadic' => 'isVariadic', + ]; + + public static function castClosure(\Closure $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + $c = new \ReflectionFunction($c); + + $a = static::castFunctionAbstract($c, $a, $stub, $isNested, $filter); + + if (!str_contains($c->name, '{closure}')) { + $stub->class = isset($a[$prefix.'class']) ? $a[$prefix.'class']->value.'::'.$c->name : $c->name; + unset($a[$prefix.'class']); + } + unset($a[$prefix.'extra']); + + $stub->class .= self::getSignature($a); + + if ($f = $c->getFileName()) { + $stub->attr['file'] = $f; + $stub->attr['line'] = $c->getStartLine(); + } + + unset($a[$prefix.'parameters']); + + if ($filter & Caster::EXCLUDE_VERBOSE) { + $stub->cut += ($c->getFileName() ? 2 : 0) + \count($a); + + return []; + } + + if ($f) { + $a[$prefix.'file'] = new LinkStub($f, $c->getStartLine()); + $a[$prefix.'line'] = $c->getStartLine().' to '.$c->getEndLine(); + } + + return $a; + } + + public static function unsetClosureFileInfo(\Closure $c, array $a) + { + unset($a[Caster::PREFIX_VIRTUAL.'file'], $a[Caster::PREFIX_VIRTUAL.'line']); + + return $a; + } + + public static function castGenerator(\Generator $c, array $a, Stub $stub, bool $isNested) + { + // Cannot create ReflectionGenerator based on a terminated Generator + try { + $reflectionGenerator = new \ReflectionGenerator($c); + } catch (\Exception $e) { + $a[Caster::PREFIX_VIRTUAL.'closed'] = true; + + return $a; + } + + return self::castReflectionGenerator($reflectionGenerator, $a, $stub, $isNested); + } + + public static function castType(\ReflectionType $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($c instanceof \ReflectionNamedType || \PHP_VERSION_ID < 80000) { + $a += [ + $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, + $prefix.'allowsNull' => $c->allowsNull(), + $prefix.'isBuiltin' => $c->isBuiltin(), + ]; + } elseif ($c instanceof \ReflectionUnionType || $c instanceof \ReflectionIntersectionType) { + $a[$prefix.'allowsNull'] = $c->allowsNull(); + self::addMap($a, $c, [ + 'types' => 'getTypes', + ]); + } else { + $a[$prefix.'allowsNull'] = $c->allowsNull(); + } + + return $a; + } + + public static function castAttribute(\ReflectionAttribute $c, array $a, Stub $stub, bool $isNested) + { + self::addMap($a, $c, [ + 'name' => 'getName', + 'arguments' => 'getArguments', + ]); + + return $a; + } + + public static function castReflectionGenerator(\ReflectionGenerator $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($c->getThis()) { + $a[$prefix.'this'] = new CutStub($c->getThis()); + } + $function = $c->getFunction(); + $frame = [ + 'class' => $function->class ?? null, + 'type' => isset($function->class) ? ($function->isStatic() ? '::' : '->') : null, + 'function' => $function->name, + 'file' => $c->getExecutingFile(), + 'line' => $c->getExecutingLine(), + ]; + if ($trace = $c->getTrace(\DEBUG_BACKTRACE_IGNORE_ARGS)) { + $function = new \ReflectionGenerator($c->getExecutingGenerator()); + array_unshift($trace, [ + 'function' => 'yield', + 'file' => $function->getExecutingFile(), + 'line' => $function->getExecutingLine() - (int) (\PHP_VERSION_ID < 80100), + ]); + $trace[] = $frame; + $a[$prefix.'trace'] = new TraceStub($trace, false, 0, -1, -1); + } else { + $function = new FrameStub($frame, false, true); + $function = ExceptionCaster::castFrameStub($function, [], $function, true); + $a[$prefix.'executing'] = $function[$prefix.'src']; + } + + $a[Caster::PREFIX_VIRTUAL.'closed'] = false; + + return $a; + } + + public static function castClass(\ReflectionClass $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + if ($n = \Reflection::getModifierNames($c->getModifiers())) { + $a[$prefix.'modifiers'] = implode(' ', $n); + } + + self::addMap($a, $c, [ + 'extends' => 'getParentClass', + 'implements' => 'getInterfaceNames', + 'constants' => 'getReflectionConstants', + ]); + + foreach ($c->getProperties() as $n) { + $a[$prefix.'properties'][$n->name] = $n; + } + + foreach ($c->getMethods() as $n) { + $a[$prefix.'methods'][$n->name] = $n; + } + + self::addAttributes($a, $c, $prefix); + + if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { + self::addExtra($a, $c); + } + + return $a; + } + + public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, array $a, Stub $stub, bool $isNested, int $filter = 0) + { + $prefix = Caster::PREFIX_VIRTUAL; + + self::addMap($a, $c, [ + 'returnsReference' => 'returnsReference', + 'returnType' => 'getReturnType', + 'class' => \PHP_VERSION_ID >= 80111 ? 'getClosureCalledClass' : 'getClosureScopeClass', + 'this' => 'getClosureThis', + ]); + + if (isset($a[$prefix.'returnType'])) { + $v = $a[$prefix.'returnType']; + $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; + $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType'] instanceof \ReflectionNamedType && $a[$prefix.'returnType']->allowsNull() && 'mixed' !== $v ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + } + if (isset($a[$prefix.'class'])) { + $a[$prefix.'class'] = new ClassStub($a[$prefix.'class']); + } + if (isset($a[$prefix.'this'])) { + $a[$prefix.'this'] = new CutStub($a[$prefix.'this']); + } + + foreach ($c->getParameters() as $v) { + $k = '$'.$v->name; + if ($v->isVariadic()) { + $k = '...'.$k; + } + if ($v->isPassedByReference()) { + $k = '&'.$k; + } + $a[$prefix.'parameters'][$k] = $v; + } + if (isset($a[$prefix.'parameters'])) { + $a[$prefix.'parameters'] = new EnumStub($a[$prefix.'parameters']); + } + + self::addAttributes($a, $c, $prefix); + + if (!($filter & Caster::EXCLUDE_VERBOSE) && $v = $c->getStaticVariables()) { + foreach ($v as $k => &$v) { + if (\is_object($v)) { + $a[$prefix.'use']['$'.$k] = new CutStub($v); + } else { + $a[$prefix.'use']['$'.$k] = &$v; + } + } + unset($v); + $a[$prefix.'use'] = new EnumStub($a[$prefix.'use']); + } + + if (!($filter & Caster::EXCLUDE_VERBOSE) && !$isNested) { + self::addExtra($a, $c); + } + + return $a; + } + + public static function castClassConstant(\ReflectionClassConstant $c, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); + $a[Caster::PREFIX_VIRTUAL.'value'] = $c->getValue(); + + self::addAttributes($a, $c); + + return $a; + } + + public static function castMethod(\ReflectionMethod $c, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); + + return $a; + } + + public static function castParameter(\ReflectionParameter $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + + self::addMap($a, $c, [ + 'position' => 'getPosition', + 'isVariadic' => 'isVariadic', + 'byReference' => 'isPassedByReference', + 'allowsNull' => 'allowsNull', + ]); + + self::addAttributes($a, $c, $prefix); + + if ($v = $c->getType()) { + $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; + } + + if (isset($a[$prefix.'typeHint'])) { + $v = $a[$prefix.'typeHint']; + $a[$prefix.'typeHint'] = new ClassStub($v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); + } else { + unset($a[$prefix.'allowsNull']); + } + + if ($c->isOptional()) { + try { + $a[$prefix.'default'] = $v = $c->getDefaultValue(); + if ($c->isDefaultValueConstant() && !\is_object($v)) { + $a[$prefix.'default'] = new ConstStub($c->getDefaultValueConstantName(), $v); + } + if (null === $v) { + unset($a[$prefix.'allowsNull']); + } + } catch (\ReflectionException $e) { + } + } + + return $a; + } + + public static function castProperty(\ReflectionProperty $c, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'modifiers'] = implode(' ', \Reflection::getModifierNames($c->getModifiers())); + + self::addAttributes($a, $c); + self::addExtra($a, $c); + + return $a; + } + + public static function castReference(\ReflectionReference $c, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'id'] = $c->getId(); + + return $a; + } + + public static function castExtension(\ReflectionExtension $c, array $a, Stub $stub, bool $isNested) + { + self::addMap($a, $c, [ + 'version' => 'getVersion', + 'dependencies' => 'getDependencies', + 'iniEntries' => 'getIniEntries', + 'isPersistent' => 'isPersistent', + 'isTemporary' => 'isTemporary', + 'constants' => 'getConstants', + 'functions' => 'getFunctions', + 'classes' => 'getClasses', + ]); + + return $a; + } + + public static function castZendExtension(\ReflectionZendExtension $c, array $a, Stub $stub, bool $isNested) + { + self::addMap($a, $c, [ + 'version' => 'getVersion', + 'author' => 'getAuthor', + 'copyright' => 'getCopyright', + 'url' => 'getURL', + ]); + + return $a; + } + + public static function getSignature(array $a) + { + $prefix = Caster::PREFIX_VIRTUAL; + $signature = ''; + + if (isset($a[$prefix.'parameters'])) { + foreach ($a[$prefix.'parameters']->value as $k => $param) { + $signature .= ', '; + if ($type = $param->getType()) { + if (!$type instanceof \ReflectionNamedType) { + $signature .= $type.' '; + } else { + if (!$param->isOptional() && $param->allowsNull() && 'mixed' !== $type->getName()) { + $signature .= '?'; + } + $signature .= substr(strrchr('\\'.$type->getName(), '\\'), 1).' '; + } + } + $signature .= $k; + + if (!$param->isDefaultValueAvailable()) { + continue; + } + $v = $param->getDefaultValue(); + $signature .= ' = '; + + if ($param->isDefaultValueConstant()) { + $signature .= substr(strrchr('\\'.$param->getDefaultValueConstantName(), '\\'), 1); + } elseif (null === $v) { + $signature .= 'null'; + } elseif (\is_array($v)) { + $signature .= $v ? '[…'.\count($v).']' : '[]'; + } elseif (\is_string($v)) { + $signature .= 10 > \strlen($v) && !str_contains($v, '\\') ? "'{$v}'" : "'…".\strlen($v)."'"; + } elseif (\is_bool($v)) { + $signature .= $v ? 'true' : 'false'; + } elseif (\is_object($v)) { + $signature .= 'new '.substr(strrchr('\\'.get_debug_type($v), '\\'), 1); + } else { + $signature .= $v; + } + } + } + $signature = (empty($a[$prefix.'returnsReference']) ? '' : '&').'('.substr($signature, 2).')'; + + if (isset($a[$prefix.'returnType'])) { + $signature .= ': '.substr(strrchr('\\'.$a[$prefix.'returnType'], '\\'), 1); + } + + return $signature; + } + + private static function addExtra(array &$a, \Reflector $c) + { + $x = isset($a[Caster::PREFIX_VIRTUAL.'extra']) ? $a[Caster::PREFIX_VIRTUAL.'extra']->value : []; + + if (method_exists($c, 'getFileName') && $m = $c->getFileName()) { + $x['file'] = new LinkStub($m, $c->getStartLine()); + $x['line'] = $c->getStartLine().' to '.$c->getEndLine(); + } + + self::addMap($x, $c, self::EXTRA_MAP, ''); + + if ($x) { + $a[Caster::PREFIX_VIRTUAL.'extra'] = new EnumStub($x); + } + } + + private static function addMap(array &$a, object $c, array $map, string $prefix = Caster::PREFIX_VIRTUAL) + { + foreach ($map as $k => $m) { + if (\PHP_VERSION_ID >= 80000 && 'isDisabled' === $k) { + continue; + } + + if (method_exists($c, $m) && false !== ($m = $c->$m()) && null !== $m) { + $a[$prefix.$k] = $m instanceof \Reflector ? $m->name : $m; + } + } + } + + private static function addAttributes(array &$a, \Reflector $c, string $prefix = Caster::PREFIX_VIRTUAL): void + { + if (\PHP_VERSION_ID >= 80000) { + foreach ($c->getAttributes() as $n) { + $a[$prefix.'attributes'][] = $n; + } + } + } +} diff --git a/vendor/symfony/var-dumper/Caster/ResourceCaster.php b/vendor/symfony/var-dumper/Caster/ResourceCaster.php new file mode 100644 index 00000000..2c34ca91 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/ResourceCaster.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts common resource types to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class ResourceCaster +{ + /** + * @param \CurlHandle|resource $h + */ + public static function castCurl($h, array $a, Stub $stub, bool $isNested): array + { + return curl_getinfo($h); + } + + public static function castDba($dba, array $a, Stub $stub, bool $isNested) + { + $list = dba_list(); + $a['file'] = $list[(int) $dba]; + + return $a; + } + + public static function castProcess($process, array $a, Stub $stub, bool $isNested) + { + return proc_get_status($process); + } + + public static function castStream($stream, array $a, Stub $stub, bool $isNested) + { + $a = stream_get_meta_data($stream) + static::castStreamContext($stream, $a, $stub, $isNested); + if ($a['uri'] ?? false) { + $a['uri'] = new LinkStub($a['uri']); + } + + return $a; + } + + public static function castStreamContext($stream, array $a, Stub $stub, bool $isNested) + { + return @stream_context_get_params($stream) ?: $a; + } + + public static function castGd($gd, array $a, Stub $stub, bool $isNested) + { + $a['size'] = imagesx($gd).'x'.imagesy($gd); + $a['trueColor'] = imageistruecolor($gd); + + return $a; + } + + public static function castMysqlLink($h, array $a, Stub $stub, bool $isNested) + { + $a['host'] = mysql_get_host_info($h); + $a['protocol'] = mysql_get_proto_info($h); + $a['server'] = mysql_get_server_info($h); + + return $a; + } + + public static function castOpensslX509($h, array $a, Stub $stub, bool $isNested) + { + $stub->cut = -1; + $info = openssl_x509_parse($h, false); + + $pin = openssl_pkey_get_public($h); + $pin = openssl_pkey_get_details($pin)['key']; + $pin = \array_slice(explode("\n", $pin), 1, -2); + $pin = base64_decode(implode('', $pin)); + $pin = base64_encode(hash('sha256', $pin, true)); + + $a += [ + 'subject' => new EnumStub(array_intersect_key($info['subject'], ['organizationName' => true, 'commonName' => true])), + 'issuer' => new EnumStub(array_intersect_key($info['issuer'], ['organizationName' => true, 'commonName' => true])), + 'expiry' => new ConstStub(date(\DateTime::ISO8601, $info['validTo_time_t']), $info['validTo_time_t']), + 'fingerprint' => new EnumStub([ + 'md5' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'md5')), 2, ':', true)), + 'sha1' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha1')), 2, ':', true)), + 'sha256' => new ConstStub(wordwrap(strtoupper(openssl_x509_fingerprint($h, 'sha256')), 2, ':', true)), + 'pin-sha256' => new ConstStub($pin), + ]), + ]; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/SplCaster.php b/vendor/symfony/var-dumper/Caster/SplCaster.php new file mode 100644 index 00000000..d7db8f89 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/SplCaster.php @@ -0,0 +1,246 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts SPL related classes to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class SplCaster +{ + private const SPL_FILE_OBJECT_FLAGS = [ + \SplFileObject::DROP_NEW_LINE => 'DROP_NEW_LINE', + \SplFileObject::READ_AHEAD => 'READ_AHEAD', + \SplFileObject::SKIP_EMPTY => 'SKIP_EMPTY', + \SplFileObject::READ_CSV => 'READ_CSV', + ]; + + public static function castArrayObject(\ArrayObject $c, array $a, Stub $stub, bool $isNested) + { + return self::castSplArray($c, $a, $stub, $isNested); + } + + public static function castArrayIterator(\ArrayIterator $c, array $a, Stub $stub, bool $isNested) + { + return self::castSplArray($c, $a, $stub, $isNested); + } + + public static function castHeap(\Iterator $c, array $a, Stub $stub, bool $isNested) + { + $a += [ + Caster::PREFIX_VIRTUAL.'heap' => iterator_to_array(clone $c), + ]; + + return $a; + } + + public static function castDoublyLinkedList(\SplDoublyLinkedList $c, array $a, Stub $stub, bool $isNested) + { + $prefix = Caster::PREFIX_VIRTUAL; + $mode = $c->getIteratorMode(); + $c->setIteratorMode(\SplDoublyLinkedList::IT_MODE_KEEP | $mode & ~\SplDoublyLinkedList::IT_MODE_DELETE); + + $a += [ + $prefix.'mode' => new ConstStub((($mode & \SplDoublyLinkedList::IT_MODE_LIFO) ? 'IT_MODE_LIFO' : 'IT_MODE_FIFO').' | '.(($mode & \SplDoublyLinkedList::IT_MODE_DELETE) ? 'IT_MODE_DELETE' : 'IT_MODE_KEEP'), $mode), + $prefix.'dllist' => iterator_to_array($c), + ]; + $c->setIteratorMode($mode); + + return $a; + } + + public static function castFileInfo(\SplFileInfo $c, array $a, Stub $stub, bool $isNested) + { + static $map = [ + 'path' => 'getPath', + 'filename' => 'getFilename', + 'basename' => 'getBasename', + 'pathname' => 'getPathname', + 'extension' => 'getExtension', + 'realPath' => 'getRealPath', + 'aTime' => 'getATime', + 'mTime' => 'getMTime', + 'cTime' => 'getCTime', + 'inode' => 'getInode', + 'size' => 'getSize', + 'perms' => 'getPerms', + 'owner' => 'getOwner', + 'group' => 'getGroup', + 'type' => 'getType', + 'writable' => 'isWritable', + 'readable' => 'isReadable', + 'executable' => 'isExecutable', + 'file' => 'isFile', + 'dir' => 'isDir', + 'link' => 'isLink', + 'linkTarget' => 'getLinkTarget', + ]; + + $prefix = Caster::PREFIX_VIRTUAL; + unset($a["\0SplFileInfo\0fileName"]); + unset($a["\0SplFileInfo\0pathName"]); + + if (\PHP_VERSION_ID < 80000) { + if (false === $c->getPathname()) { + $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; + + return $a; + } + } else { + try { + $c->isReadable(); + } catch (\RuntimeException $e) { + if ('Object not initialized' !== $e->getMessage()) { + throw $e; + } + + $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; + + return $a; + } catch (\Error $e) { + if ('Object not initialized' !== $e->getMessage()) { + throw $e; + } + + $a[$prefix.'⚠'] = 'The parent constructor was not called: the object is in an invalid state'; + + return $a; + } + } + + foreach ($map as $key => $accessor) { + try { + $a[$prefix.$key] = $c->$accessor(); + } catch (\Exception $e) { + } + } + + if ($a[$prefix.'realPath'] ?? false) { + $a[$prefix.'realPath'] = new LinkStub($a[$prefix.'realPath']); + } + + if (isset($a[$prefix.'perms'])) { + $a[$prefix.'perms'] = new ConstStub(sprintf('0%o', $a[$prefix.'perms']), $a[$prefix.'perms']); + } + + static $mapDate = ['aTime', 'mTime', 'cTime']; + foreach ($mapDate as $key) { + if (isset($a[$prefix.$key])) { + $a[$prefix.$key] = new ConstStub(date('Y-m-d H:i:s', $a[$prefix.$key]), $a[$prefix.$key]); + } + } + + return $a; + } + + public static function castFileObject(\SplFileObject $c, array $a, Stub $stub, bool $isNested) + { + static $map = [ + 'csvControl' => 'getCsvControl', + 'flags' => 'getFlags', + 'maxLineLen' => 'getMaxLineLen', + 'fstat' => 'fstat', + 'eof' => 'eof', + 'key' => 'key', + ]; + + $prefix = Caster::PREFIX_VIRTUAL; + + foreach ($map as $key => $accessor) { + try { + $a[$prefix.$key] = $c->$accessor(); + } catch (\Exception $e) { + } + } + + if (isset($a[$prefix.'flags'])) { + $flagsArray = []; + foreach (self::SPL_FILE_OBJECT_FLAGS as $value => $name) { + if ($a[$prefix.'flags'] & $value) { + $flagsArray[] = $name; + } + } + $a[$prefix.'flags'] = new ConstStub(implode('|', $flagsArray), $a[$prefix.'flags']); + } + + if (isset($a[$prefix.'fstat'])) { + $a[$prefix.'fstat'] = new CutArrayStub($a[$prefix.'fstat'], ['dev', 'ino', 'nlink', 'rdev', 'blksize', 'blocks']); + } + + return $a; + } + + public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $stub, bool $isNested) + { + $storage = []; + unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967 + unset($a["\0SplObjectStorage\0storage"]); + + $clone = clone $c; + foreach ($clone as $obj) { + $storage[] = [ + 'object' => $obj, + 'info' => $clone->getInfo(), + ]; + } + + $a += [ + Caster::PREFIX_VIRTUAL.'storage' => $storage, + ]; + + return $a; + } + + public static function castOuterIterator(\OuterIterator $c, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'innerIterator'] = $c->getInnerIterator(); + + return $a; + } + + public static function castWeakReference(\WeakReference $c, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'object'] = $c->get(); + + return $a; + } + + private static function castSplArray($c, array $a, Stub $stub, bool $isNested): array + { + $prefix = Caster::PREFIX_VIRTUAL; + $flags = $c->getFlags(); + + if (!($flags & \ArrayObject::STD_PROP_LIST)) { + $c->setFlags(\ArrayObject::STD_PROP_LIST); + $a = Caster::castObject($c, \get_class($c), method_exists($c, '__debugInfo'), $stub->class); + $c->setFlags($flags); + } + + unset($a["\0ArrayObject\0storage"], $a["\0ArrayIterator\0storage"]); + + $a += [ + $prefix.'storage' => $c->getArrayCopy(), + $prefix.'flag::STD_PROP_LIST' => (bool) ($flags & \ArrayObject::STD_PROP_LIST), + $prefix.'flag::ARRAY_AS_PROPS' => (bool) ($flags & \ArrayObject::ARRAY_AS_PROPS), + ]; + if ($c instanceof \ArrayObject) { + $a[$prefix.'iteratorClass'] = new ClassStub($c->getIteratorClass()); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/StubCaster.php b/vendor/symfony/var-dumper/Caster/StubCaster.php new file mode 100644 index 00000000..32ead7c2 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/StubCaster.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts a caster's Stub. + * + * @author Nicolas Grekas + * + * @final + */ +class StubCaster +{ + public static function castStub(Stub $c, array $a, Stub $stub, bool $isNested) + { + if ($isNested) { + $stub->type = $c->type; + $stub->class = $c->class; + $stub->value = $c->value; + $stub->handle = $c->handle; + $stub->cut = $c->cut; + $stub->attr = $c->attr; + + if (Stub::TYPE_REF === $c->type && !$c->class && \is_string($c->value) && !preg_match('//u', $c->value)) { + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_BINARY; + } + + $a = []; + } + + return $a; + } + + public static function castCutArray(CutArrayStub $c, array $a, Stub $stub, bool $isNested) + { + return $isNested ? $c->preservedSubset : $a; + } + + public static function cutInternals($obj, array $a, Stub $stub, bool $isNested) + { + if ($isNested) { + $stub->cut += \count($a); + + return []; + } + + return $a; + } + + public static function castEnum(EnumStub $c, array $a, Stub $stub, bool $isNested) + { + if ($isNested) { + $stub->class = $c->dumpKeys ? '' : null; + $stub->handle = 0; + $stub->value = null; + $stub->cut = $c->cut; + $stub->attr = $c->attr; + + $a = []; + + if ($c->value) { + foreach (array_keys($c->value) as $k) { + $keys[] = !isset($k[0]) || "\0" !== $k[0] ? Caster::PREFIX_VIRTUAL.$k : $k; + } + // Preserve references with array_combine() + $a = array_combine($keys, $c->value); + } + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/SymfonyCaster.php b/vendor/symfony/var-dumper/Caster/SymfonyCaster.php new file mode 100644 index 00000000..08428b92 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/SymfonyCaster.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Uid\Ulid; +use Symfony\Component\Uid\Uuid; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @final + */ +class SymfonyCaster +{ + private const REQUEST_GETTERS = [ + 'pathInfo' => 'getPathInfo', + 'requestUri' => 'getRequestUri', + 'baseUrl' => 'getBaseUrl', + 'basePath' => 'getBasePath', + 'method' => 'getMethod', + 'format' => 'getRequestFormat', + ]; + + public static function castRequest(Request $request, array $a, Stub $stub, bool $isNested) + { + $clone = null; + + foreach (self::REQUEST_GETTERS as $prop => $getter) { + $key = Caster::PREFIX_PROTECTED.$prop; + if (\array_key_exists($key, $a) && null === $a[$key]) { + if (null === $clone) { + $clone = clone $request; + } + $a[Caster::PREFIX_VIRTUAL.$prop] = $clone->{$getter}(); + } + } + + return $a; + } + + public static function castHttpClient($client, array $a, Stub $stub, bool $isNested) + { + $multiKey = sprintf("\0%s\0multi", \get_class($client)); + if (isset($a[$multiKey])) { + $a[$multiKey] = new CutStub($a[$multiKey]); + } + + return $a; + } + + public static function castHttpClientResponse($response, array $a, Stub $stub, bool $isNested) + { + $stub->cut += \count($a); + $a = []; + + foreach ($response->getInfo() as $k => $v) { + $a[Caster::PREFIX_VIRTUAL.$k] = $v; + } + + return $a; + } + + public static function castUuid(Uuid $uuid, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $uuid->toBase58(); + $a[Caster::PREFIX_VIRTUAL.'toBase32'] = $uuid->toBase32(); + + // symfony/uid >= 5.3 + if (method_exists($uuid, 'getDateTime')) { + $a[Caster::PREFIX_VIRTUAL.'time'] = $uuid->getDateTime()->format('Y-m-d H:i:s.u \U\T\C'); + } + + return $a; + } + + public static function castUlid(Ulid $ulid, array $a, Stub $stub, bool $isNested) + { + $a[Caster::PREFIX_VIRTUAL.'toBase58'] = $ulid->toBase58(); + $a[Caster::PREFIX_VIRTUAL.'toRfc4122'] = $ulid->toRfc4122(); + + // symfony/uid >= 5.3 + if (method_exists($ulid, 'getDateTime')) { + $a[Caster::PREFIX_VIRTUAL.'time'] = $ulid->getDateTime()->format('Y-m-d H:i:s.v \U\T\C'); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/TraceStub.php b/vendor/symfony/var-dumper/Caster/TraceStub.php new file mode 100644 index 00000000..5eea1c87 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/TraceStub.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Represents a backtrace as returned by debug_backtrace() or Exception->getTrace(). + * + * @author Nicolas Grekas + */ +class TraceStub extends Stub +{ + public $keepArgs; + public $sliceOffset; + public $sliceLength; + public $numberingOffset; + + public function __construct(array $trace, bool $keepArgs = true, int $sliceOffset = 0, int $sliceLength = null, int $numberingOffset = 0) + { + $this->value = $trace; + $this->keepArgs = $keepArgs; + $this->sliceOffset = $sliceOffset; + $this->sliceLength = $sliceLength; + $this->numberingOffset = $numberingOffset; + } +} diff --git a/vendor/symfony/var-dumper/Caster/UuidCaster.php b/vendor/symfony/var-dumper/Caster/UuidCaster.php new file mode 100644 index 00000000..b1027745 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/UuidCaster.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Ramsey\Uuid\UuidInterface; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * @author Grégoire Pineau + */ +final class UuidCaster +{ + public static function castRamseyUuid(UuidInterface $c, array $a, Stub $stub, bool $isNested): array + { + $a += [ + Caster::PREFIX_VIRTUAL.'uuid' => (string) $c, + ]; + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php b/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php new file mode 100644 index 00000000..5b455651 --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/XmlReaderCaster.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts XmlReader class to array representation. + * + * @author Baptiste Clavié + * + * @final + */ +class XmlReaderCaster +{ + private const NODE_TYPES = [ + \XMLReader::NONE => 'NONE', + \XMLReader::ELEMENT => 'ELEMENT', + \XMLReader::ATTRIBUTE => 'ATTRIBUTE', + \XMLReader::TEXT => 'TEXT', + \XMLReader::CDATA => 'CDATA', + \XMLReader::ENTITY_REF => 'ENTITY_REF', + \XMLReader::ENTITY => 'ENTITY', + \XMLReader::PI => 'PI (Processing Instruction)', + \XMLReader::COMMENT => 'COMMENT', + \XMLReader::DOC => 'DOC', + \XMLReader::DOC_TYPE => 'DOC_TYPE', + \XMLReader::DOC_FRAGMENT => 'DOC_FRAGMENT', + \XMLReader::NOTATION => 'NOTATION', + \XMLReader::WHITESPACE => 'WHITESPACE', + \XMLReader::SIGNIFICANT_WHITESPACE => 'SIGNIFICANT_WHITESPACE', + \XMLReader::END_ELEMENT => 'END_ELEMENT', + \XMLReader::END_ENTITY => 'END_ENTITY', + \XMLReader::XML_DECLARATION => 'XML_DECLARATION', + ]; + + public static function castXmlReader(\XMLReader $reader, array $a, Stub $stub, bool $isNested) + { + try { + $properties = [ + 'LOADDTD' => @$reader->getParserProperty(\XMLReader::LOADDTD), + 'DEFAULTATTRS' => @$reader->getParserProperty(\XMLReader::DEFAULTATTRS), + 'VALIDATE' => @$reader->getParserProperty(\XMLReader::VALIDATE), + 'SUBST_ENTITIES' => @$reader->getParserProperty(\XMLReader::SUBST_ENTITIES), + ]; + } catch (\Error $e) { + $properties = [ + 'LOADDTD' => false, + 'DEFAULTATTRS' => false, + 'VALIDATE' => false, + 'SUBST_ENTITIES' => false, + ]; + } + + $props = Caster::PREFIX_VIRTUAL.'parserProperties'; + $info = [ + 'localName' => $reader->localName, + 'prefix' => $reader->prefix, + 'nodeType' => new ConstStub(self::NODE_TYPES[$reader->nodeType], $reader->nodeType), + 'depth' => $reader->depth, + 'isDefault' => $reader->isDefault, + 'isEmptyElement' => \XMLReader::NONE === $reader->nodeType ? null : $reader->isEmptyElement, + 'xmlLang' => $reader->xmlLang, + 'attributeCount' => $reader->attributeCount, + 'value' => $reader->value, + 'namespaceURI' => $reader->namespaceURI, + 'baseURI' => $reader->baseURI ? new LinkStub($reader->baseURI) : $reader->baseURI, + $props => $properties, + ]; + + if ($info[$props] = Caster::filter($info[$props], Caster::EXCLUDE_EMPTY, [], $count)) { + $info[$props] = new EnumStub($info[$props]); + $info[$props]->cut = $count; + } + + $info = Caster::filter($info, Caster::EXCLUDE_EMPTY, [], $count); + // +2 because hasValue and hasAttributes are always filtered + $stub->cut += $count + 2; + + return $a + $info; + } +} diff --git a/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php b/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php new file mode 100644 index 00000000..ba55fced --- /dev/null +++ b/vendor/symfony/var-dumper/Caster/XmlResourceCaster.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Caster; + +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * Casts XML resources to array representation. + * + * @author Nicolas Grekas + * + * @final + */ +class XmlResourceCaster +{ + private const XML_ERRORS = [ + \XML_ERROR_NONE => 'XML_ERROR_NONE', + \XML_ERROR_NO_MEMORY => 'XML_ERROR_NO_MEMORY', + \XML_ERROR_SYNTAX => 'XML_ERROR_SYNTAX', + \XML_ERROR_NO_ELEMENTS => 'XML_ERROR_NO_ELEMENTS', + \XML_ERROR_INVALID_TOKEN => 'XML_ERROR_INVALID_TOKEN', + \XML_ERROR_UNCLOSED_TOKEN => 'XML_ERROR_UNCLOSED_TOKEN', + \XML_ERROR_PARTIAL_CHAR => 'XML_ERROR_PARTIAL_CHAR', + \XML_ERROR_TAG_MISMATCH => 'XML_ERROR_TAG_MISMATCH', + \XML_ERROR_DUPLICATE_ATTRIBUTE => 'XML_ERROR_DUPLICATE_ATTRIBUTE', + \XML_ERROR_JUNK_AFTER_DOC_ELEMENT => 'XML_ERROR_JUNK_AFTER_DOC_ELEMENT', + \XML_ERROR_PARAM_ENTITY_REF => 'XML_ERROR_PARAM_ENTITY_REF', + \XML_ERROR_UNDEFINED_ENTITY => 'XML_ERROR_UNDEFINED_ENTITY', + \XML_ERROR_RECURSIVE_ENTITY_REF => 'XML_ERROR_RECURSIVE_ENTITY_REF', + \XML_ERROR_ASYNC_ENTITY => 'XML_ERROR_ASYNC_ENTITY', + \XML_ERROR_BAD_CHAR_REF => 'XML_ERROR_BAD_CHAR_REF', + \XML_ERROR_BINARY_ENTITY_REF => 'XML_ERROR_BINARY_ENTITY_REF', + \XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF => 'XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF', + \XML_ERROR_MISPLACED_XML_PI => 'XML_ERROR_MISPLACED_XML_PI', + \XML_ERROR_UNKNOWN_ENCODING => 'XML_ERROR_UNKNOWN_ENCODING', + \XML_ERROR_INCORRECT_ENCODING => 'XML_ERROR_INCORRECT_ENCODING', + \XML_ERROR_UNCLOSED_CDATA_SECTION => 'XML_ERROR_UNCLOSED_CDATA_SECTION', + \XML_ERROR_EXTERNAL_ENTITY_HANDLING => 'XML_ERROR_EXTERNAL_ENTITY_HANDLING', + ]; + + public static function castXml($h, array $a, Stub $stub, bool $isNested) + { + $a['current_byte_index'] = xml_get_current_byte_index($h); + $a['current_column_number'] = xml_get_current_column_number($h); + $a['current_line_number'] = xml_get_current_line_number($h); + $a['error_code'] = xml_get_error_code($h); + + if (isset(self::XML_ERRORS[$a['error_code']])) { + $a['error_code'] = new ConstStub(self::XML_ERRORS[$a['error_code']], $a['error_code']); + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/AbstractCloner.php b/vendor/symfony/var-dumper/Cloner/AbstractCloner.php new file mode 100644 index 00000000..f74a61d7 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/AbstractCloner.php @@ -0,0 +1,400 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +use Symfony\Component\VarDumper\Caster\Caster; +use Symfony\Component\VarDumper\Exception\ThrowingCasterException; + +/** + * AbstractCloner implements a generic caster mechanism for objects and resources. + * + * @author Nicolas Grekas + */ +abstract class AbstractCloner implements ClonerInterface +{ + public static $defaultCasters = [ + '__PHP_Incomplete_Class' => ['Symfony\Component\VarDumper\Caster\Caster', 'castPhpIncompleteClass'], + + 'Symfony\Component\VarDumper\Caster\CutStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], + 'Symfony\Component\VarDumper\Caster\CutArrayStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castCutArray'], + 'Symfony\Component\VarDumper\Caster\ConstStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castStub'], + 'Symfony\Component\VarDumper\Caster\EnumStub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'castEnum'], + + 'Fiber' => ['Symfony\Component\VarDumper\Caster\FiberCaster', 'castFiber'], + + 'Closure' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClosure'], + 'Generator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castGenerator'], + 'ReflectionType' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castType'], + 'ReflectionAttribute' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castAttribute'], + 'ReflectionGenerator' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReflectionGenerator'], + 'ReflectionClass' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClass'], + 'ReflectionClassConstant' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castClassConstant'], + 'ReflectionFunctionAbstract' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castFunctionAbstract'], + 'ReflectionMethod' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castMethod'], + 'ReflectionParameter' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castParameter'], + 'ReflectionProperty' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castProperty'], + 'ReflectionReference' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castReference'], + 'ReflectionExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castExtension'], + 'ReflectionZendExtension' => ['Symfony\Component\VarDumper\Caster\ReflectionCaster', 'castZendExtension'], + + 'Doctrine\Common\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'], + 'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'], + 'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'], + 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + + 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], + 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNameList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMImplementation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castImplementation'], + 'DOMImplementationList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNode'], + 'DOMNameSpaceNode' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNameSpaceNode'], + 'DOMDocument' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocument'], + 'DOMNodeList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMNamedNodeMap' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], + 'DOMCharacterData' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castCharacterData'], + 'DOMAttr' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castAttr'], + 'DOMElement' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castElement'], + 'DOMText' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castText'], + 'DOMTypeinfo' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castTypeinfo'], + 'DOMDomError' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDomError'], + 'DOMLocator' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLocator'], + 'DOMDocumentType' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castDocumentType'], + 'DOMNotation' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castNotation'], + 'DOMEntity' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castEntity'], + 'DOMProcessingInstruction' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castProcessingInstruction'], + 'DOMXPath' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castXPath'], + + 'XMLReader' => ['Symfony\Component\VarDumper\Caster\XmlReaderCaster', 'castXmlReader'], + + 'ErrorException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castErrorException'], + 'Exception' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castException'], + 'Error' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castError'], + 'Symfony\Bridge\Monolog\Logger' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\DependencyInjection\ContainerInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\EventDispatcher\EventDispatcherInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\HttpClient\AmpHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\CurlHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\NativeHttpClient' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClient'], + 'Symfony\Component\HttpClient\Response\AmpResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\CurlResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpClient\Response\NativeResponse' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castHttpClientResponse'], + 'Symfony\Component\HttpFoundation\Request' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castRequest'], + 'Symfony\Component\Uid\Ulid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUlid'], + 'Symfony\Component\Uid\Uuid' => ['Symfony\Component\VarDumper\Caster\SymfonyCaster', 'castUuid'], + 'Symfony\Component\VarDumper\Exception\ThrowingCasterException' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castThrowingCasterException'], + 'Symfony\Component\VarDumper\Caster\TraceStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castTraceStub'], + 'Symfony\Component\VarDumper\Caster\FrameStub' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castFrameStub'], + 'Symfony\Component\VarDumper\Cloner\AbstractCloner' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Symfony\Component\ErrorHandler\Exception\SilencedErrorContext' => ['Symfony\Component\VarDumper\Caster\ExceptionCaster', 'castSilencedErrorContext'], + + 'Imagine\Image\ImageInterface' => ['Symfony\Component\VarDumper\Caster\ImagineCaster', 'castImage'], + + 'Ramsey\Uuid\UuidInterface' => ['Symfony\Component\VarDumper\Caster\UuidCaster', 'castRamseyUuid'], + + 'ProxyManager\Proxy\ProxyInterface' => ['Symfony\Component\VarDumper\Caster\ProxyManagerCaster', 'castProxy'], + 'PHPUnit_Framework_MockObject_MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'PHPUnit\Framework\MockObject\MockObject' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'PHPUnit\Framework\MockObject\Stub' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Prophecy\Prophecy\ProphecySubjectInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + 'Mockery\MockInterface' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], + + 'PDO' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdo'], + 'PDOStatement' => ['Symfony\Component\VarDumper\Caster\PdoCaster', 'castPdoStatement'], + + 'AMQPConnection' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castConnection'], + 'AMQPChannel' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castChannel'], + 'AMQPQueue' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castQueue'], + 'AMQPExchange' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castExchange'], + 'AMQPEnvelope' => ['Symfony\Component\VarDumper\Caster\AmqpCaster', 'castEnvelope'], + + 'ArrayObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayObject'], + 'ArrayIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castArrayIterator'], + 'SplDoublyLinkedList' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castDoublyLinkedList'], + 'SplFileInfo' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileInfo'], + 'SplFileObject' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castFileObject'], + 'SplHeap' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], + 'SplObjectStorage' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castObjectStorage'], + 'SplPriorityQueue' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castHeap'], + 'OuterIterator' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castOuterIterator'], + 'WeakReference' => ['Symfony\Component\VarDumper\Caster\SplCaster', 'castWeakReference'], + + 'Redis' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedis'], + 'RedisArray' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisArray'], + 'RedisCluster' => ['Symfony\Component\VarDumper\Caster\RedisCaster', 'castRedisCluster'], + + 'DateTimeInterface' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castDateTime'], + 'DateInterval' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castInterval'], + 'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'], + 'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'], + + 'GMP' => ['Symfony\Component\VarDumper\Caster\GmpCaster', 'castGmp'], + + 'MessageFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castMessageFormatter'], + 'NumberFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castNumberFormatter'], + 'IntlTimeZone' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlTimeZone'], + 'IntlCalendar' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlCalendar'], + 'IntlDateFormatter' => ['Symfony\Component\VarDumper\Caster\IntlCaster', 'castIntlDateFormatter'], + + 'Memcached' => ['Symfony\Component\VarDumper\Caster\MemcachedCaster', 'castMemcached'], + + 'Ds\Collection' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castCollection'], + 'Ds\Map' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castMap'], + 'Ds\Pair' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPair'], + 'Symfony\Component\VarDumper\Caster\DsPairStub' => ['Symfony\Component\VarDumper\Caster\DsCaster', 'castPairStub'], + + 'mysqli_driver' => ['Symfony\Component\VarDumper\Caster\MysqliCaster', 'castMysqliDriver'], + + 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + + ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], + ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], + + 'GdImage' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], + ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], + + ':mysql link' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castMysqlLink'], + ':pgsql large object' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLargeObject'], + ':pgsql link' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + ':pgsql link persistent' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castLink'], + ':pgsql result' => ['Symfony\Component\VarDumper\Caster\PgSqlCaster', 'castResult'], + ':process' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castProcess'], + ':stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], + + 'OpenSSLCertificate' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + ':OpenSSL X.509' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castOpensslX509'], + + ':persistent stream' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStream'], + ':stream-context' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castStreamContext'], + + 'XmlParser' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], + ':xml' => ['Symfony\Component\VarDumper\Caster\XmlResourceCaster', 'castXml'], + + 'RdKafka' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castRdKafka'], + 'RdKafka\Conf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castConf'], + 'RdKafka\KafkaConsumer' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castKafkaConsumer'], + 'RdKafka\Metadata\Broker' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castBrokerMetadata'], + 'RdKafka\Metadata\Collection' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castCollectionMetadata'], + 'RdKafka\Metadata\Partition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castPartitionMetadata'], + 'RdKafka\Metadata\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicMetadata'], + 'RdKafka\Message' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castMessage'], + 'RdKafka\Topic' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopic'], + 'RdKafka\TopicPartition' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicPartition'], + 'RdKafka\TopicConf' => ['Symfony\Component\VarDumper\Caster\RdKafkaCaster', 'castTopicConf'], + ]; + + protected $maxItems = 2500; + protected $maxString = -1; + protected $minDepth = 1; + + /** + * @var array> + */ + private $casters = []; + + /** + * @var callable|null + */ + private $prevErrorHandler; + + private $classInfo = []; + private $filter = 0; + + /** + * @param callable[]|null $casters A map of casters + * + * @see addCasters + */ + public function __construct(array $casters = null) + { + if (null === $casters) { + $casters = static::$defaultCasters; + } + $this->addCasters($casters); + } + + /** + * Adds casters for resources and objects. + * + * Maps resources or objects types to a callback. + * Types are in the key, with a callable caster for value. + * Resource types are to be prefixed with a `:`, + * see e.g. static::$defaultCasters. + * + * @param callable[] $casters A map of casters + */ + public function addCasters(array $casters) + { + foreach ($casters as $type => $callback) { + $this->casters[$type][] = $callback; + } + } + + /** + * Sets the maximum number of items to clone past the minimum depth in nested structures. + */ + public function setMaxItems(int $maxItems) + { + $this->maxItems = $maxItems; + } + + /** + * Sets the maximum cloned length for strings. + */ + public function setMaxString(int $maxString) + { + $this->maxString = $maxString; + } + + /** + * Sets the minimum tree depth where we are guaranteed to clone all the items. After this + * depth is reached, only setMaxItems items will be cloned. + */ + public function setMinDepth(int $minDepth) + { + $this->minDepth = $minDepth; + } + + /** + * Clones a PHP variable. + * + * @param mixed $var Any PHP variable + * @param int $filter A bit field of Caster::EXCLUDE_* constants + * + * @return Data + */ + public function cloneVar($var, int $filter = 0) + { + $this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) { + if (\E_RECOVERABLE_ERROR === $type || \E_USER_ERROR === $type) { + // Cloner never dies + throw new \ErrorException($msg, 0, $type, $file, $line); + } + + if ($this->prevErrorHandler) { + return ($this->prevErrorHandler)($type, $msg, $file, $line, $context); + } + + return false; + }); + $this->filter = $filter; + + if ($gc = gc_enabled()) { + gc_disable(); + } + try { + return new Data($this->doClone($var)); + } finally { + if ($gc) { + gc_enable(); + } + restore_error_handler(); + $this->prevErrorHandler = null; + } + } + + /** + * Effectively clones the PHP variable. + * + * @param mixed $var Any PHP variable + * + * @return array + */ + abstract protected function doClone($var); + + /** + * Casts an object to an array representation. + * + * @param bool $isNested True if the object is nested in the dumped structure + * + * @return array + */ + protected function castObject(Stub $stub, bool $isNested) + { + $obj = $stub->value; + $class = $stub->class; + + if (\PHP_VERSION_ID < 80000 ? "\0" === ($class[15] ?? null) : str_contains($class, "@anonymous\0")) { + $stub->class = get_debug_type($obj); + } + if (isset($this->classInfo[$class])) { + [$i, $parents, $hasDebugInfo, $fileInfo] = $this->classInfo[$class]; + } else { + $i = 2; + $parents = [$class]; + $hasDebugInfo = method_exists($class, '__debugInfo'); + + foreach (class_parents($class) as $p) { + $parents[] = $p; + ++$i; + } + foreach (class_implements($class) as $p) { + $parents[] = $p; + ++$i; + } + $parents[] = '*'; + + $r = new \ReflectionClass($class); + $fileInfo = $r->isInternal() || $r->isSubclassOf(Stub::class) ? [] : [ + 'file' => $r->getFileName(), + 'line' => $r->getStartLine(), + ]; + + $this->classInfo[$class] = [$i, $parents, $hasDebugInfo, $fileInfo]; + } + + $stub->attr += $fileInfo; + $a = Caster::castObject($obj, $class, $hasDebugInfo, $stub->class); + + try { + while ($i--) { + if (!empty($this->casters[$p = $parents[$i]])) { + foreach ($this->casters[$p] as $callback) { + $a = $callback($obj, $a, $stub, $isNested, $this->filter); + } + } + } + } catch (\Exception $e) { + $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; + } + + return $a; + } + + /** + * Casts a resource to an array representation. + * + * @param bool $isNested True if the object is nested in the dumped structure + * + * @return array + */ + protected function castResource(Stub $stub, bool $isNested) + { + $a = []; + $res = $stub->value; + $type = $stub->class; + + try { + if (!empty($this->casters[':'.$type])) { + foreach ($this->casters[':'.$type] as $callback) { + $a = $callback($res, $a, $stub, $isNested, $this->filter); + } + } + } catch (\Exception $e) { + $a = [(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)] + $a; + } + + return $a; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/ClonerInterface.php b/vendor/symfony/var-dumper/Cloner/ClonerInterface.php new file mode 100644 index 00000000..90b14953 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/ClonerInterface.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * @author Nicolas Grekas + */ +interface ClonerInterface +{ + /** + * Clones a PHP variable. + * + * @param mixed $var Any PHP variable + * + * @return Data + */ + public function cloneVar($var); +} diff --git a/vendor/symfony/var-dumper/Cloner/Cursor.php b/vendor/symfony/var-dumper/Cloner/Cursor.php new file mode 100644 index 00000000..1fd796d6 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/Cursor.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * Represents the current state of a dumper while dumping. + * + * @author Nicolas Grekas + */ +class Cursor +{ + public const HASH_INDEXED = Stub::ARRAY_INDEXED; + public const HASH_ASSOC = Stub::ARRAY_ASSOC; + public const HASH_OBJECT = Stub::TYPE_OBJECT; + public const HASH_RESOURCE = Stub::TYPE_RESOURCE; + + public $depth = 0; + public $refIndex = 0; + public $softRefTo = 0; + public $softRefCount = 0; + public $softRefHandle = 0; + public $hardRefTo = 0; + public $hardRefCount = 0; + public $hardRefHandle = 0; + public $hashType; + public $hashKey; + public $hashKeyIsBinary; + public $hashIndex = 0; + public $hashLength = 0; + public $hashCut = 0; + public $stop = false; + public $attr = []; + public $skipChildren = false; +} diff --git a/vendor/symfony/var-dumper/Cloner/Data.php b/vendor/symfony/var-dumper/Cloner/Data.php new file mode 100644 index 00000000..ea8f0f33 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/Data.php @@ -0,0 +1,468 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +use Symfony\Component\VarDumper\Caster\Caster; +use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; + +/** + * @author Nicolas Grekas + */ +class Data implements \ArrayAccess, \Countable, \IteratorAggregate +{ + private $data; + private $position = 0; + private $key = 0; + private $maxDepth = 20; + private $maxItemsPerDepth = -1; + private $useRefHandles = -1; + private $context = []; + + /** + * @param array $data An array as returned by ClonerInterface::cloneVar() + */ + public function __construct(array $data) + { + $this->data = $data; + } + + /** + * @return string|null + */ + public function getType() + { + $item = $this->data[$this->position][$this->key]; + + if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { + $item = $item->value; + } + if (!$item instanceof Stub) { + return \gettype($item); + } + if (Stub::TYPE_STRING === $item->type) { + return 'string'; + } + if (Stub::TYPE_ARRAY === $item->type) { + return 'array'; + } + if (Stub::TYPE_OBJECT === $item->type) { + return $item->class; + } + if (Stub::TYPE_RESOURCE === $item->type) { + return $item->class.' resource'; + } + + return null; + } + + /** + * Returns a native representation of the original value. + * + * @param array|bool $recursive Whether values should be resolved recursively or not + * + * @return string|int|float|bool|array|Data[]|null + */ + public function getValue($recursive = false) + { + $item = $this->data[$this->position][$this->key]; + + if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { + $item = $item->value; + } + if (!($item = $this->getStub($item)) instanceof Stub) { + return $item; + } + if (Stub::TYPE_STRING === $item->type) { + return $item->value; + } + + $children = $item->position ? $this->data[$item->position] : []; + + foreach ($children as $k => $v) { + if ($recursive && !($v = $this->getStub($v)) instanceof Stub) { + continue; + } + $children[$k] = clone $this; + $children[$k]->key = $k; + $children[$k]->position = $item->position; + + if ($recursive) { + if (Stub::TYPE_REF === $v->type && ($v = $this->getStub($v->value)) instanceof Stub) { + $recursive = (array) $recursive; + if (isset($recursive[$v->position])) { + continue; + } + $recursive[$v->position] = true; + } + $children[$k] = $children[$k]->getValue($recursive); + } + } + + return $children; + } + + /** + * @return int + */ + #[\ReturnTypeWillChange] + public function count() + { + return \count($this->getValue()); + } + + /** + * @return \Traversable + */ + #[\ReturnTypeWillChange] + public function getIterator() + { + if (!\is_array($value = $this->getValue())) { + throw new \LogicException(sprintf('"%s" object holds non-iterable type "%s".', self::class, get_debug_type($value))); + } + + yield from $value; + } + + public function __get(string $key) + { + if (null !== $data = $this->seek($key)) { + $item = $this->getStub($data->data[$data->position][$data->key]); + + return $item instanceof Stub || [] === $item ? $data : $item; + } + + return null; + } + + /** + * @return bool + */ + public function __isset(string $key) + { + return null !== $this->seek($key); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($key) + { + return $this->__isset($key); + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->__get($key); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($key, $value) + { + throw new \BadMethodCallException(self::class.' objects are immutable.'); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($key) + { + throw new \BadMethodCallException(self::class.' objects are immutable.'); + } + + /** + * @return string + */ + public function __toString() + { + $value = $this->getValue(); + + if (!\is_array($value)) { + return (string) $value; + } + + return sprintf('%s (count=%d)', $this->getType(), \count($value)); + } + + /** + * Returns a depth limited clone of $this. + * + * @return static + */ + public function withMaxDepth(int $maxDepth) + { + $data = clone $this; + $data->maxDepth = $maxDepth; + + return $data; + } + + /** + * Limits the number of elements per depth level. + * + * @return static + */ + public function withMaxItemsPerDepth(int $maxItemsPerDepth) + { + $data = clone $this; + $data->maxItemsPerDepth = $maxItemsPerDepth; + + return $data; + } + + /** + * Enables/disables objects' identifiers tracking. + * + * @param bool $useRefHandles False to hide global ref. handles + * + * @return static + */ + public function withRefHandles(bool $useRefHandles) + { + $data = clone $this; + $data->useRefHandles = $useRefHandles ? -1 : 0; + + return $data; + } + + /** + * @return static + */ + public function withContext(array $context) + { + $data = clone $this; + $data->context = $context; + + return $data; + } + + /** + * Seeks to a specific key in nested data structures. + * + * @param string|int $key The key to seek to + * + * @return static|null + */ + public function seek($key) + { + $item = $this->data[$this->position][$this->key]; + + if ($item instanceof Stub && Stub::TYPE_REF === $item->type && !$item->position) { + $item = $item->value; + } + if (!($item = $this->getStub($item)) instanceof Stub || !$item->position) { + return null; + } + $keys = [$key]; + + switch ($item->type) { + case Stub::TYPE_OBJECT: + $keys[] = Caster::PREFIX_DYNAMIC.$key; + $keys[] = Caster::PREFIX_PROTECTED.$key; + $keys[] = Caster::PREFIX_VIRTUAL.$key; + $keys[] = "\0$item->class\0$key"; + // no break + case Stub::TYPE_ARRAY: + case Stub::TYPE_RESOURCE: + break; + default: + return null; + } + + $data = null; + $children = $this->data[$item->position]; + + foreach ($keys as $key) { + if (isset($children[$key]) || \array_key_exists($key, $children)) { + $data = clone $this; + $data->key = $key; + $data->position = $item->position; + break; + } + } + + return $data; + } + + /** + * Dumps data with a DumperInterface dumper. + */ + public function dump(DumperInterface $dumper) + { + $refs = [0]; + $cursor = new Cursor(); + + if ($cursor->attr = $this->context[SourceContextProvider::class] ?? []) { + $cursor->attr['if_links'] = true; + $cursor->hashType = -1; + $dumper->dumpScalar($cursor, 'default', '^'); + $cursor->attr = ['if_links' => true]; + $dumper->dumpScalar($cursor, 'default', ' '); + $cursor->hashType = 0; + } + + $this->dumpItem($dumper, $cursor, $refs, $this->data[$this->position][$this->key]); + } + + /** + * Depth-first dumping of items. + * + * @param mixed $item A Stub object or the original value being dumped + */ + private function dumpItem(DumperInterface $dumper, Cursor $cursor, array &$refs, $item) + { + $cursor->refIndex = 0; + $cursor->softRefTo = $cursor->softRefHandle = $cursor->softRefCount = 0; + $cursor->hardRefTo = $cursor->hardRefHandle = $cursor->hardRefCount = 0; + $firstSeen = true; + + if (!$item instanceof Stub) { + $cursor->attr = []; + $type = \gettype($item); + if ($item && 'array' === $type) { + $item = $this->getStub($item); + } + } elseif (Stub::TYPE_REF === $item->type) { + if ($item->handle) { + if (!isset($refs[$r = $item->handle - (\PHP_INT_MAX >> 1)])) { + $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0]; + } else { + $firstSeen = false; + } + $cursor->hardRefTo = $refs[$r]; + $cursor->hardRefHandle = $this->useRefHandles & $item->handle; + $cursor->hardRefCount = 0 < $item->handle ? $item->refCount : 0; + } + $cursor->attr = $item->attr; + $type = $item->class ?: \gettype($item->value); + $item = $this->getStub($item->value); + } + if ($item instanceof Stub) { + if ($item->refCount) { + if (!isset($refs[$r = $item->handle])) { + $cursor->refIndex = $refs[$r] = $cursor->refIndex ?: ++$refs[0]; + } else { + $firstSeen = false; + } + $cursor->softRefTo = $refs[$r]; + } + $cursor->softRefHandle = $this->useRefHandles & $item->handle; + $cursor->softRefCount = $item->refCount; + $cursor->attr = $item->attr; + $cut = $item->cut; + + if ($item->position && $firstSeen) { + $children = $this->data[$item->position]; + + if ($cursor->stop) { + if ($cut >= 0) { + $cut += \count($children); + } + $children = []; + } + } else { + $children = []; + } + switch ($item->type) { + case Stub::TYPE_STRING: + $dumper->dumpString($cursor, $item->value, Stub::STRING_BINARY === $item->class, $cut); + break; + + case Stub::TYPE_ARRAY: + $item = clone $item; + $item->type = $item->class; + $item->class = $item->value; + // no break + case Stub::TYPE_OBJECT: + case Stub::TYPE_RESOURCE: + $withChildren = $children && $cursor->depth !== $this->maxDepth && $this->maxItemsPerDepth; + $dumper->enterHash($cursor, $item->type, $item->class, $withChildren); + if ($withChildren) { + if ($cursor->skipChildren) { + $withChildren = false; + $cut = -1; + } else { + $cut = $this->dumpChildren($dumper, $cursor, $refs, $children, $cut, $item->type, null !== $item->class); + } + } elseif ($children && 0 <= $cut) { + $cut += \count($children); + } + $cursor->skipChildren = false; + $dumper->leaveHash($cursor, $item->type, $item->class, $withChildren, $cut); + break; + + default: + throw new \RuntimeException(sprintf('Unexpected Stub type: "%s".', $item->type)); + } + } elseif ('array' === $type) { + $dumper->enterHash($cursor, Cursor::HASH_INDEXED, 0, false); + $dumper->leaveHash($cursor, Cursor::HASH_INDEXED, 0, false, 0); + } elseif ('string' === $type) { + $dumper->dumpString($cursor, $item, false, 0); + } else { + $dumper->dumpScalar($cursor, $type, $item); + } + } + + /** + * Dumps children of hash structures. + * + * @return int The final number of removed items + */ + private function dumpChildren(DumperInterface $dumper, Cursor $parentCursor, array &$refs, array $children, int $hashCut, int $hashType, bool $dumpKeys): int + { + $cursor = clone $parentCursor; + ++$cursor->depth; + $cursor->hashType = $hashType; + $cursor->hashIndex = 0; + $cursor->hashLength = \count($children); + $cursor->hashCut = $hashCut; + foreach ($children as $key => $child) { + $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key); + $cursor->hashKey = $dumpKeys ? $key : null; + $this->dumpItem($dumper, $cursor, $refs, $child); + if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) { + $parentCursor->stop = true; + + return $hashCut >= 0 ? $hashCut + $cursor->hashLength - $cursor->hashIndex : $hashCut; + } + } + + return $hashCut; + } + + private function getStub($item) + { + if (!$item || !\is_array($item)) { + return $item; + } + + $stub = new Stub(); + $stub->type = Stub::TYPE_ARRAY; + foreach ($item as $stub->class => $stub->position) { + } + if (isset($item[0])) { + $stub->cut = $item[0]; + } + $stub->value = $stub->cut + ($stub->position ? \count($this->data[$stub->position]) : 0); + + return $stub; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/DumperInterface.php b/vendor/symfony/var-dumper/Cloner/DumperInterface.php new file mode 100644 index 00000000..6d60b723 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/DumperInterface.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * DumperInterface used by Data objects. + * + * @author Nicolas Grekas + */ +interface DumperInterface +{ + /** + * Dumps a scalar value. + * + * @param string $type The PHP type of the value being dumped + * @param string|int|float|bool $value The scalar value being dumped + */ + public function dumpScalar(Cursor $cursor, string $type, $value); + + /** + * Dumps a string. + * + * @param string $str The string being dumped + * @param bool $bin Whether $str is UTF-8 or binary encoded + * @param int $cut The number of characters $str has been cut by + */ + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut); + + /** + * Dumps while entering an hash. + * + * @param int $type A Cursor::HASH_* const for the type of hash + * @param string|int $class The object class, resource type or array count + * @param bool $hasChild When the dump of the hash has child item + */ + public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild); + + /** + * Dumps while leaving an hash. + * + * @param int $type A Cursor::HASH_* const for the type of hash + * @param string|int $class The object class, resource type or array count + * @param bool $hasChild When the dump of the hash has child item + * @param int $cut The number of items the hash has been cut by + */ + public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut); +} diff --git a/vendor/symfony/var-dumper/Cloner/Stub.php b/vendor/symfony/var-dumper/Cloner/Stub.php new file mode 100644 index 00000000..073c56ef --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/Stub.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * Represents the main properties of a PHP variable. + * + * @author Nicolas Grekas + */ +class Stub +{ + public const TYPE_REF = 1; + public const TYPE_STRING = 2; + public const TYPE_ARRAY = 3; + public const TYPE_OBJECT = 4; + public const TYPE_RESOURCE = 5; + + public const STRING_BINARY = 1; + public const STRING_UTF8 = 2; + + public const ARRAY_ASSOC = 1; + public const ARRAY_INDEXED = 2; + + public $type = self::TYPE_REF; + public $class = ''; + public $value; + public $cut = 0; + public $handle = 0; + public $refCount = 0; + public $position = 0; + public $attr = []; + + private static $defaultProperties = []; + + /** + * @internal + */ + public function __sleep(): array + { + $properties = []; + + if (!isset(self::$defaultProperties[$c = static::class])) { + self::$defaultProperties[$c] = get_class_vars($c); + + foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) { + unset(self::$defaultProperties[$c][$k]); + } + } + + foreach (self::$defaultProperties[$c] as $k => $v) { + if ($this->$k !== $v) { + $properties[] = $k; + } + } + + return $properties; + } +} diff --git a/vendor/symfony/var-dumper/Cloner/VarCloner.php b/vendor/symfony/var-dumper/Cloner/VarCloner.php new file mode 100644 index 00000000..80c4a2f8 --- /dev/null +++ b/vendor/symfony/var-dumper/Cloner/VarCloner.php @@ -0,0 +1,311 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Cloner; + +/** + * @author Nicolas Grekas + */ +class VarCloner extends AbstractCloner +{ + private static $gid; + private static $arrayCache = []; + + /** + * {@inheritdoc} + */ + protected function doClone($var) + { + $len = 1; // Length of $queue + $pos = 0; // Number of cloned items past the minimum depth + $refsCounter = 0; // Hard references counter + $queue = [[$var]]; // This breadth-first queue is the return value + $hardRefs = []; // Map of original zval ids to stub objects + $objRefs = []; // Map of original object handles to their stub object counterpart + $objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning + $resRefs = []; // Map of original resource handles to their stub object counterpart + $values = []; // Map of stub objects' ids to original values + $maxItems = $this->maxItems; + $maxString = $this->maxString; + $minDepth = $this->minDepth; + $currentDepth = 0; // Current tree depth + $currentDepthFinalIndex = 0; // Final $queue index for current tree depth + $minimumDepthReached = 0 === $minDepth; // Becomes true when minimum tree depth has been reached + $cookie = (object) []; // Unique object used to detect hard references + $a = null; // Array cast for nested structures + $stub = null; // Stub capturing the main properties of an original item value + // or null if the original value is used directly + + if (!$gid = self::$gid) { + $gid = self::$gid = md5(random_bytes(6)); // Unique string used to detect the special $GLOBALS variable + } + $arrayStub = new Stub(); + $arrayStub->type = Stub::TYPE_ARRAY; + $fromObjCast = false; + + for ($i = 0; $i < $len; ++$i) { + // Detect when we move on to the next tree depth + if ($i > $currentDepthFinalIndex) { + ++$currentDepth; + $currentDepthFinalIndex = $len - 1; + if ($currentDepth >= $minDepth) { + $minimumDepthReached = true; + } + } + + $refs = $vals = $queue[$i]; + foreach ($vals as $k => $v) { + // $v is the original value or a stub object in case of hard references + + if (\PHP_VERSION_ID >= 70400) { + $zvalRef = ($r = \ReflectionReference::fromArrayElement($vals, $k)) ? $r->getId() : null; + } else { + $refs[$k] = $cookie; + $zvalRef = $vals[$k] === $cookie; + } + + if ($zvalRef) { + $vals[$k] = &$stub; // Break hard references to make $queue completely + unset($stub); // independent from the original structure + if (\PHP_VERSION_ID >= 70400 ? null !== $vals[$k] = $hardRefs[$zvalRef] ?? null : $v instanceof Stub && isset($hardRefs[spl_object_id($v)])) { + if (\PHP_VERSION_ID >= 70400) { + $v = $vals[$k]; + } else { + $refs[$k] = $vals[$k] = $v; + } + if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { + ++$v->value->refCount; + } + ++$v->refCount; + continue; + } + $vals[$k] = new Stub(); + $vals[$k]->value = $v; + $vals[$k]->handle = ++$refsCounter; + + if (\PHP_VERSION_ID >= 70400) { + $hardRefs[$zvalRef] = $vals[$k]; + } else { + $refs[$k] = $vals[$k]; + $h = spl_object_id($refs[$k]); + $hardRefs[$h] = &$refs[$k]; + $values[$h] = $v; + } + } + // Create $stub when the original value $v cannot be used directly + // If $v is a nested structure, put that structure in array $a + switch (true) { + case null === $v: + case \is_bool($v): + case \is_int($v): + case \is_float($v): + continue 2; + case \is_string($v): + if ('' === $v) { + continue 2; + } + if (!preg_match('//u', $v)) { + $stub = new Stub(); + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_BINARY; + if (0 <= $maxString && 0 < $cut = \strlen($v) - $maxString) { + $stub->cut = $cut; + $stub->value = substr($v, 0, -$cut); + } else { + $stub->value = $v; + } + } elseif (0 <= $maxString && isset($v[1 + ($maxString >> 2)]) && 0 < $cut = mb_strlen($v, 'UTF-8') - $maxString) { + $stub = new Stub(); + $stub->type = Stub::TYPE_STRING; + $stub->class = Stub::STRING_UTF8; + $stub->cut = $cut; + $stub->value = mb_substr($v, 0, $maxString, 'UTF-8'); + } else { + continue 2; + } + $a = null; + break; + + case \is_array($v): + if (!$v) { + continue 2; + } + $stub = $arrayStub; + + if (\PHP_VERSION_ID >= 80100) { + $stub->class = array_is_list($v) ? Stub::ARRAY_INDEXED : Stub::ARRAY_ASSOC; + $a = $v; + break; + } + + $stub->class = Stub::ARRAY_INDEXED; + + $j = -1; + foreach ($v as $gk => $gv) { + if ($gk !== ++$j) { + $stub->class = Stub::ARRAY_ASSOC; + $a = $v; + $a[$gid] = true; + break; + } + } + + // Copies of $GLOBALS have very strange behavior, + // let's detect them with some black magic + if (isset($v[$gid])) { + unset($v[$gid]); + $a = []; + foreach ($v as $gk => &$gv) { + if ($v === $gv && (\PHP_VERSION_ID < 70400 || !isset($hardRefs[\ReflectionReference::fromArrayElement($v, $gk)->getId()]))) { + unset($v); + $v = new Stub(); + $v->value = [$v->cut = \count($gv), Stub::TYPE_ARRAY => 0]; + $v->handle = -1; + if (\PHP_VERSION_ID >= 70400) { + $gv = &$a[$gk]; + $hardRefs[\ReflectionReference::fromArrayElement($a, $gk)->getId()] = &$gv; + } else { + $gv = &$hardRefs[spl_object_id($v)]; + } + $gv = $v; + } + + $a[$gk] = &$gv; + } + unset($gv); + } else { + $a = $v; + } + break; + + case \is_object($v): + if (empty($objRefs[$h = spl_object_id($v)])) { + $stub = new Stub(); + $stub->type = Stub::TYPE_OBJECT; + $stub->class = \get_class($v); + $stub->value = $v; + $stub->handle = $h; + $a = $this->castObject($stub, 0 < $i); + if ($v !== $stub->value) { + if (Stub::TYPE_OBJECT !== $stub->type || null === $stub->value) { + break; + } + $stub->handle = $h = spl_object_id($stub->value); + } + $stub->value = null; + if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) { + $stub->cut = \count($a); + $a = null; + } + } + if (empty($objRefs[$h])) { + $objRefs[$h] = $stub; + $objects[] = $v; + } else { + $stub = $objRefs[$h]; + ++$stub->refCount; + $a = null; + } + break; + + default: // resource + if (empty($resRefs[$h = (int) $v])) { + $stub = new Stub(); + $stub->type = Stub::TYPE_RESOURCE; + if ('Unknown' === $stub->class = @get_resource_type($v)) { + $stub->class = 'Closed'; + } + $stub->value = $v; + $stub->handle = $h; + $a = $this->castResource($stub, 0 < $i); + $stub->value = null; + if (0 <= $maxItems && $maxItems <= $pos && $minimumDepthReached) { + $stub->cut = \count($a); + $a = null; + } + } + if (empty($resRefs[$h])) { + $resRefs[$h] = $stub; + } else { + $stub = $resRefs[$h]; + ++$stub->refCount; + $a = null; + } + break; + } + + if ($a) { + if (!$minimumDepthReached || 0 > $maxItems) { + $queue[$len] = $a; + $stub->position = $len++; + } elseif ($pos < $maxItems) { + if ($maxItems < $pos += \count($a)) { + $a = \array_slice($a, 0, $maxItems - $pos, true); + if ($stub->cut >= 0) { + $stub->cut += $pos - $maxItems; + } + } + $queue[$len] = $a; + $stub->position = $len++; + } elseif ($stub->cut >= 0) { + $stub->cut += \count($a); + $stub->position = 0; + } + } + + if ($arrayStub === $stub) { + if ($arrayStub->cut) { + $stub = [$arrayStub->cut, $arrayStub->class => $arrayStub->position]; + $arrayStub->cut = 0; + } elseif (isset(self::$arrayCache[$arrayStub->class][$arrayStub->position])) { + $stub = self::$arrayCache[$arrayStub->class][$arrayStub->position]; + } else { + self::$arrayCache[$arrayStub->class][$arrayStub->position] = $stub = [$arrayStub->class => $arrayStub->position]; + } + } + + if (!$zvalRef) { + $vals[$k] = $stub; + } elseif (\PHP_VERSION_ID >= 70400) { + $hardRefs[$zvalRef]->value = $stub; + } else { + $refs[$k]->value = $stub; + } + } + + if ($fromObjCast) { + $fromObjCast = false; + $refs = $vals; + $vals = []; + $j = -1; + foreach ($queue[$i] as $k => $v) { + foreach ([$k => true] as $gk => $gv) { + } + if ($gk !== $k) { + $vals = (object) $vals; + $vals->{$k} = $refs[++$j]; + $vals = (array) $vals; + } else { + $vals[$k] = $refs[++$j]; + } + } + } + + $queue[$i] = $vals; + } + + foreach ($values as $h => $v) { + $hardRefs[$h] = $v; + } + + return $queue; + } +} diff --git a/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php b/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php new file mode 100644 index 00000000..2afaa7bf --- /dev/null +++ b/vendor/symfony/var-dumper/Command/Descriptor/CliDescriptor.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command\Descriptor; + +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * Describe collected data clones for cli output. + * + * @author Maxime Steinhausser + * + * @final + */ +class CliDescriptor implements DumpDescriptorInterface +{ + private $dumper; + private $lastIdentifier; + + public function __construct(CliDumper $dumper) + { + $this->dumper = $dumper; + } + + public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void + { + $io = $output instanceof SymfonyStyle ? $output : new SymfonyStyle(new ArrayInput([]), $output); + $this->dumper->setColors($output->isDecorated()); + + $rows = [['date', date('r', (int) $context['timestamp'])]]; + $lastIdentifier = $this->lastIdentifier; + $this->lastIdentifier = $clientId; + + $section = "Received from client #$clientId"; + if (isset($context['request'])) { + $request = $context['request']; + $this->lastIdentifier = $request['identifier']; + $section = sprintf('%s %s', $request['method'], $request['uri']); + if ($controller = $request['controller']) { + $rows[] = ['controller', rtrim($this->dumper->dump($controller, true), "\n")]; + } + } elseif (isset($context['cli'])) { + $this->lastIdentifier = $context['cli']['identifier']; + $section = '$ '.$context['cli']['command_line']; + } + + if ($this->lastIdentifier !== $lastIdentifier) { + $io->section($section); + } + + if (isset($context['source'])) { + $source = $context['source']; + $sourceInfo = sprintf('%s on line %d', $source['name'], $source['line']); + if ($fileLink = $source['file_link'] ?? null) { + $sourceInfo = sprintf('%s', $fileLink, $sourceInfo); + } + $rows[] = ['source', $sourceInfo]; + $file = $source['file_relative'] ?? $source['file']; + $rows[] = ['file', $file]; + } + + $io->table([], $rows); + + $this->dumper->dump($data); + $io->newLine(); + } +} diff --git a/vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php b/vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php new file mode 100644 index 00000000..267d27bf --- /dev/null +++ b/vendor/symfony/var-dumper/Command/Descriptor/DumpDescriptorInterface.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command\Descriptor; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * @author Maxime Steinhausser + */ +interface DumpDescriptorInterface +{ + public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void; +} diff --git a/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php b/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php new file mode 100644 index 00000000..636b6182 --- /dev/null +++ b/vendor/symfony/var-dumper/Command/Descriptor/HtmlDescriptor.php @@ -0,0 +1,119 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command\Descriptor; + +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; + +/** + * Describe collected data clones for html output. + * + * @author Maxime Steinhausser + * + * @final + */ +class HtmlDescriptor implements DumpDescriptorInterface +{ + private $dumper; + private $initialized = false; + + public function __construct(HtmlDumper $dumper) + { + $this->dumper = $dumper; + } + + public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void + { + if (!$this->initialized) { + $styles = file_get_contents(__DIR__.'/../../Resources/css/htmlDescriptor.css'); + $scripts = file_get_contents(__DIR__.'/../../Resources/js/htmlDescriptor.js'); + $output->writeln(""); + $this->initialized = true; + } + + $title = '-'; + if (isset($context['request'])) { + $request = $context['request']; + $controller = "{$this->dumper->dump($request['controller'], true, ['maxDepth' => 0])}"; + $title = sprintf('%s %s', $request['method'], $uri = $request['uri'], $uri); + $dedupIdentifier = $request['identifier']; + } elseif (isset($context['cli'])) { + $title = '$ '.$context['cli']['command_line']; + $dedupIdentifier = $context['cli']['identifier']; + } else { + $dedupIdentifier = uniqid('', true); + } + + $sourceDescription = ''; + if (isset($context['source'])) { + $source = $context['source']; + $projectDir = $source['project_dir'] ?? null; + $sourceDescription = sprintf('%s on line %d', $source['name'], $source['line']); + if (isset($source['file_link'])) { + $sourceDescription = sprintf('%s', $source['file_link'], $sourceDescription); + } + } + + $isoDate = $this->extractDate($context, 'c'); + $tags = array_filter([ + 'controller' => $controller ?? null, + 'project dir' => $projectDir ?? null, + ]); + + $output->writeln(<< +
    +
    +

    $title

    + +
    + {$this->renderTags($tags)} +
    +
    +

    + $sourceDescription +

    + {$this->dumper->dump($data, true)} +
    + +HTML + ); + } + + private function extractDate(array $context, string $format = 'r'): string + { + return date($format, (int) $context['timestamp']); + } + + private function renderTags(array $tags): string + { + if (!$tags) { + return ''; + } + + $renderedTags = ''; + foreach ($tags as $key => $value) { + $renderedTags .= sprintf('
  • %s%s
  • ', $key, $value); + } + + return << +
      + $renderedTags +
    +
    +HTML; + } +} diff --git a/vendor/symfony/var-dumper/Command/ServerDumpCommand.php b/vendor/symfony/var-dumper/Command/ServerDumpCommand.php new file mode 100644 index 00000000..3a695952 --- /dev/null +++ b/vendor/symfony/var-dumper/Command/ServerDumpCommand.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Completion\CompletionInput; +use Symfony\Component\Console\Completion\CompletionSuggestions; +use Symfony\Component\Console\Exception\InvalidArgumentException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Command\Descriptor\CliDescriptor; +use Symfony\Component\VarDumper\Command\Descriptor\DumpDescriptorInterface; +use Symfony\Component\VarDumper\Command\Descriptor\HtmlDescriptor; +use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\Server\DumpServer; + +/** + * Starts a dump server to collect and output dumps on a single place with multiple formats support. + * + * @author Maxime Steinhausser + * + * @final + */ +class ServerDumpCommand extends Command +{ + protected static $defaultName = 'server:dump'; + protected static $defaultDescription = 'Start a dump server that collects and displays dumps in a single place'; + + private $server; + + /** @var DumpDescriptorInterface[] */ + private $descriptors; + + public function __construct(DumpServer $server, array $descriptors = []) + { + $this->server = $server; + $this->descriptors = $descriptors + [ + 'cli' => new CliDescriptor(new CliDumper()), + 'html' => new HtmlDescriptor(new HtmlDumper()), + ]; + + parent::__construct(); + } + + protected function configure() + { + $this + ->addOption('format', null, InputOption::VALUE_REQUIRED, sprintf('The output format (%s)', implode(', ', $this->getAvailableFormats())), 'cli') + ->setDescription(self::$defaultDescription) + ->setHelp(<<<'EOF' +%command.name% starts a dump server that collects and displays +dumps in a single place for debugging you application: + + php %command.full_name% + +You can consult dumped data in HTML format in your browser by providing the --format=html option +and redirecting the output to a file: + + php %command.full_name% --format="html" > dump.html + +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $format = $input->getOption('format'); + + if (!$descriptor = $this->descriptors[$format] ?? null) { + throw new InvalidArgumentException(sprintf('Unsupported format "%s".', $format)); + } + + $errorIo = $io->getErrorStyle(); + $errorIo->title('Symfony Var Dumper Server'); + + $this->server->start(); + + $errorIo->success(sprintf('Server listening on %s', $this->server->getHost())); + $errorIo->comment('Quit the server with CONTROL-C.'); + + $this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) { + $descriptor->describe($io, $data, $context, $clientId); + }); + + return 0; + } + + public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void + { + if ($input->mustSuggestOptionValuesFor('format')) { + $suggestions->suggestValues($this->getAvailableFormats()); + } + } + + private function getAvailableFormats(): array + { + return array_keys($this->descriptors); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/AbstractDumper.php b/vendor/symfony/var-dumper/Dumper/AbstractDumper.php new file mode 100644 index 00000000..ae19faf6 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/AbstractDumper.php @@ -0,0 +1,202 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Cloner\DumperInterface; + +/** + * Abstract mechanism for dumping a Data object. + * + * @author Nicolas Grekas + */ +abstract class AbstractDumper implements DataDumperInterface, DumperInterface +{ + public const DUMP_LIGHT_ARRAY = 1; + public const DUMP_STRING_LENGTH = 2; + public const DUMP_COMMA_SEPARATOR = 4; + public const DUMP_TRAILING_COMMA = 8; + + public static $defaultOutput = 'php://output'; + + protected $line = ''; + protected $lineDumper; + protected $outputStream; + protected $decimalPoint; // This is locale dependent + protected $indentPad = ' '; + protected $flags; + + private $charset = ''; + + /** + * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput + * @param string|null $charset The default character encoding to use for non-UTF8 strings + * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation + */ + public function __construct($output = null, string $charset = null, int $flags = 0) + { + $this->flags = $flags; + $this->setCharset($charset ?: \ini_get('php.output_encoding') ?: \ini_get('default_charset') ?: 'UTF-8'); + $this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point']; + $this->setOutput($output ?: static::$defaultOutput); + if (!$output && \is_string(static::$defaultOutput)) { + static::$defaultOutput = $this->outputStream; + } + } + + /** + * Sets the output destination of the dumps. + * + * @param callable|resource|string $output A line dumper callable, an opened stream or an output path + * + * @return callable|resource|string The previous output destination + */ + public function setOutput($output) + { + $prev = $this->outputStream ?? $this->lineDumper; + + if (\is_callable($output)) { + $this->outputStream = null; + $this->lineDumper = $output; + } else { + if (\is_string($output)) { + $output = fopen($output, 'w'); + } + $this->outputStream = $output; + $this->lineDumper = [$this, 'echoLine']; + } + + return $prev; + } + + /** + * Sets the default character encoding to use for non-UTF8 strings. + * + * @return string The previous charset + */ + public function setCharset(string $charset) + { + $prev = $this->charset; + + $charset = strtoupper($charset); + $charset = null === $charset || 'UTF-8' === $charset || 'UTF8' === $charset ? 'CP1252' : $charset; + + $this->charset = $charset; + + return $prev; + } + + /** + * Sets the indentation pad string. + * + * @param string $pad A string that will be prepended to dumped lines, repeated by nesting level + * + * @return string The previous indent pad + */ + public function setIndentPad(string $pad) + { + $prev = $this->indentPad; + $this->indentPad = $pad; + + return $prev; + } + + /** + * Dumps a Data object. + * + * @param callable|resource|string|true|null $output A line dumper callable, an opened stream, an output path or true to return the dump + * + * @return string|null The dump as string when $output is true + */ + public function dump(Data $data, $output = null) + { + $this->decimalPoint = \PHP_VERSION_ID >= 80000 ? '.' : localeconv()['decimal_point']; + + if ($locale = $this->flags & (self::DUMP_COMMA_SEPARATOR | self::DUMP_TRAILING_COMMA) ? setlocale(\LC_NUMERIC, 0) : null) { + setlocale(\LC_NUMERIC, 'C'); + } + + if ($returnDump = true === $output) { + $output = fopen('php://memory', 'r+'); + } + if ($output) { + $prevOutput = $this->setOutput($output); + } + try { + $data->dump($this); + $this->dumpLine(-1); + + if ($returnDump) { + $result = stream_get_contents($output, -1, 0); + fclose($output); + + return $result; + } + } finally { + if ($output) { + $this->setOutput($prevOutput); + } + if ($locale) { + setlocale(\LC_NUMERIC, $locale); + } + } + + return null; + } + + /** + * Dumps the current line. + * + * @param int $depth The recursive depth in the dumped structure for the line being dumped, + * or -1 to signal the end-of-dump to the line dumper callable + */ + protected function dumpLine(int $depth) + { + ($this->lineDumper)($this->line, $depth, $this->indentPad); + $this->line = ''; + } + + /** + * Generic line dumper callback. + */ + protected function echoLine(string $line, int $depth, string $indentPad) + { + if (-1 !== $depth) { + fwrite($this->outputStream, str_repeat($indentPad, $depth).$line."\n"); + } + } + + /** + * Converts a non-UTF-8 string to UTF-8. + * + * @return string|null + */ + protected function utf8Encode(?string $s) + { + if (null === $s || preg_match('//u', $s)) { + return $s; + } + + if (!\function_exists('iconv')) { + throw new \RuntimeException('Unable to convert a non-UTF-8 string to UTF-8: required function iconv() does not exist. You should install ext-iconv or symfony/polyfill-iconv.'); + } + + if (false !== $c = @iconv($this->charset, 'UTF-8', $s)) { + return $c; + } + if ('CP1252' !== $this->charset && false !== $c = @iconv('CP1252', 'UTF-8', $s)) { + return $c; + } + + return iconv('CP850', 'UTF-8', $s); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/CliDumper.php b/vendor/symfony/var-dumper/Dumper/CliDumper.php new file mode 100644 index 00000000..690f6d01 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/CliDumper.php @@ -0,0 +1,659 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Cursor; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * CliDumper dumps variables for command line output. + * + * @author Nicolas Grekas + */ +class CliDumper extends AbstractDumper +{ + public static $defaultColors; + public static $defaultOutput = 'php://stdout'; + + protected $colors; + protected $maxStringWidth = 0; + protected $styles = [ + // See http://en.wikipedia.org/wiki/ANSI_escape_code#graphics + 'default' => '0;38;5;208', + 'num' => '1;38;5;38', + 'const' => '1;38;5;208', + 'str' => '1;38;5;113', + 'note' => '38;5;38', + 'ref' => '38;5;247', + 'public' => '', + 'protected' => '', + 'private' => '', + 'meta' => '38;5;170', + 'key' => '38;5;113', + 'index' => '38;5;38', + ]; + + protected static $controlCharsRx = '/[\x00-\x1F\x7F]+/'; + protected static $controlCharsMap = [ + "\t" => '\t', + "\n" => '\n', + "\v" => '\v', + "\f" => '\f', + "\r" => '\r', + "\033" => '\e', + ]; + + protected $collapseNextHash = false; + protected $expandNextHash = false; + + private $displayOptions = [ + 'fileLinkFormat' => null, + ]; + + private $handlesHrefGracefully; + + /** + * {@inheritdoc} + */ + public function __construct($output = null, string $charset = null, int $flags = 0) + { + parent::__construct($output, $charset, $flags); + + if ('\\' === \DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) { + // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI + $this->setStyles([ + 'default' => '31', + 'num' => '1;34', + 'const' => '1;31', + 'str' => '1;32', + 'note' => '34', + 'ref' => '1;30', + 'meta' => '35', + 'key' => '32', + 'index' => '34', + ]); + } + + $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format') ?: 'file://%f#L%l'; + } + + /** + * Enables/disables colored output. + */ + public function setColors(bool $colors) + { + $this->colors = $colors; + } + + /** + * Sets the maximum number of characters per line for dumped strings. + */ + public function setMaxStringWidth(int $maxStringWidth) + { + $this->maxStringWidth = $maxStringWidth; + } + + /** + * Configures styles. + * + * @param array $styles A map of style names to style definitions + */ + public function setStyles(array $styles) + { + $this->styles = $styles + $this->styles; + } + + /** + * Configures display options. + * + * @param array $displayOptions A map of display options to customize the behavior + */ + public function setDisplayOptions(array $displayOptions) + { + $this->displayOptions = $displayOptions + $this->displayOptions; + } + + /** + * {@inheritdoc} + */ + public function dumpScalar(Cursor $cursor, string $type, $value) + { + $this->dumpKey($cursor); + $this->collapseNextHash = $this->expandNextHash = false; + + $style = 'const'; + $attr = $cursor->attr; + + switch ($type) { + case 'default': + $style = 'default'; + break; + + case 'integer': + $style = 'num'; + + if (isset($this->styles['integer'])) { + $style = 'integer'; + } + + break; + + case 'double': + $style = 'num'; + + if (isset($this->styles['float'])) { + $style = 'float'; + } + + switch (true) { + case \INF === $value: $value = 'INF'; break; + case -\INF === $value: $value = '-INF'; break; + case is_nan($value): $value = 'NAN'; break; + default: + $value = (string) $value; + if (!str_contains($value, $this->decimalPoint)) { + $value .= $this->decimalPoint.'0'; + } + break; + } + break; + + case 'NULL': + $value = 'null'; + break; + + case 'boolean': + $value = $value ? 'true' : 'false'; + break; + + default: + $attr += ['value' => $this->utf8Encode($value)]; + $value = $this->utf8Encode($type); + break; + } + + $this->line .= $this->style($style, $value, $attr); + + $this->endValue($cursor); + } + + /** + * {@inheritdoc} + */ + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) + { + $this->dumpKey($cursor); + $this->collapseNextHash = $this->expandNextHash = false; + $attr = $cursor->attr; + + if ($bin) { + $str = $this->utf8Encode($str); + } + if ('' === $str) { + $this->line .= '""'; + if ($cut) { + $this->line .= '…'.$cut; + } + $this->endValue($cursor); + } else { + $attr += [ + 'length' => 0 <= $cut ? mb_strlen($str, 'UTF-8') + $cut : 0, + 'binary' => $bin, + ]; + $str = $bin && false !== strpos($str, "\0") ? [$str] : explode("\n", $str); + if (isset($str[1]) && !isset($str[2]) && !isset($str[1][0])) { + unset($str[1]); + $str[0] .= "\n"; + } + $m = \count($str) - 1; + $i = $lineCut = 0; + + if (self::DUMP_STRING_LENGTH & $this->flags) { + $this->line .= '('.$attr['length'].') '; + } + if ($bin) { + $this->line .= 'b'; + } + + if ($m) { + $this->line .= '"""'; + $this->dumpLine($cursor->depth); + } else { + $this->line .= '"'; + } + + foreach ($str as $str) { + if ($i < $m) { + $str .= "\n"; + } + if (0 < $this->maxStringWidth && $this->maxStringWidth < $len = mb_strlen($str, 'UTF-8')) { + $str = mb_substr($str, 0, $this->maxStringWidth, 'UTF-8'); + $lineCut = $len - $this->maxStringWidth; + } + if ($m && 0 < $cursor->depth) { + $this->line .= $this->indentPad; + } + if ('' !== $str) { + $this->line .= $this->style('str', $str, $attr); + } + if ($i++ == $m) { + if ($m) { + if ('' !== $str) { + $this->dumpLine($cursor->depth); + if (0 < $cursor->depth) { + $this->line .= $this->indentPad; + } + } + $this->line .= '"""'; + } else { + $this->line .= '"'; + } + if ($cut < 0) { + $this->line .= '…'; + $lineCut = 0; + } elseif ($cut) { + $lineCut += $cut; + } + } + if ($lineCut) { + $this->line .= '…'.$lineCut; + $lineCut = 0; + } + + if ($i > $m) { + $this->endValue($cursor); + } else { + $this->dumpLine($cursor->depth); + } + } + } + } + + /** + * {@inheritdoc} + */ + public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild) + { + if (null === $this->colors) { + $this->colors = $this->supportsColors(); + } + + $this->dumpKey($cursor); + $this->expandNextHash = false; + $attr = $cursor->attr; + + if ($this->collapseNextHash) { + $cursor->skipChildren = true; + $this->collapseNextHash = $hasChild = false; + } + + $class = $this->utf8Encode($class); + if (Cursor::HASH_OBJECT === $type) { + $prefix = $class && 'stdClass' !== $class ? $this->style('note', $class, $attr).(empty($attr['cut_hash']) ? ' {' : '') : '{'; + } elseif (Cursor::HASH_RESOURCE === $type) { + $prefix = $this->style('note', $class.' resource', $attr).($hasChild ? ' {' : ' '); + } else { + $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; + } + + if (($cursor->softRefCount || 0 < $cursor->softRefHandle) && empty($attr['cut_hash'])) { + $prefix .= $this->style('ref', (Cursor::HASH_RESOURCE === $type ? '@' : '#').(0 < $cursor->softRefHandle ? $cursor->softRefHandle : $cursor->softRefTo), ['count' => $cursor->softRefCount]); + } elseif ($cursor->hardRefTo && !$cursor->refIndex && $class) { + $prefix .= $this->style('ref', '&'.$cursor->hardRefTo, ['count' => $cursor->hardRefCount]); + } elseif (!$hasChild && Cursor::HASH_RESOURCE === $type) { + $prefix = substr($prefix, 0, -1); + } + + $this->line .= $prefix; + + if ($hasChild) { + $this->dumpLine($cursor->depth); + } + } + + /** + * {@inheritdoc} + */ + public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut) + { + if (empty($cursor->attr['cut_hash'])) { + $this->dumpEllipsis($cursor, $hasChild, $cut); + $this->line .= Cursor::HASH_OBJECT === $type ? '}' : (Cursor::HASH_RESOURCE !== $type ? ']' : ($hasChild ? '}' : '')); + } + + $this->endValue($cursor); + } + + /** + * Dumps an ellipsis for cut children. + * + * @param bool $hasChild When the dump of the hash has child item + * @param int $cut The number of items the hash has been cut by + */ + protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) + { + if ($cut) { + $this->line .= ' …'; + if (0 < $cut) { + $this->line .= $cut; + } + if ($hasChild) { + $this->dumpLine($cursor->depth + 1); + } + } + } + + /** + * Dumps a key in a hash structure. + */ + protected function dumpKey(Cursor $cursor) + { + if (null !== $key = $cursor->hashKey) { + if ($cursor->hashKeyIsBinary) { + $key = $this->utf8Encode($key); + } + $attr = ['binary' => $cursor->hashKeyIsBinary]; + $bin = $cursor->hashKeyIsBinary ? 'b' : ''; + $style = 'key'; + switch ($cursor->hashType) { + default: + case Cursor::HASH_INDEXED: + if (self::DUMP_LIGHT_ARRAY & $this->flags) { + break; + } + $style = 'index'; + // no break + case Cursor::HASH_ASSOC: + if (\is_int($key)) { + $this->line .= $this->style($style, $key).' => '; + } else { + $this->line .= $bin.'"'.$this->style($style, $key).'" => '; + } + break; + + case Cursor::HASH_RESOURCE: + $key = "\0~\0".$key; + // no break + case Cursor::HASH_OBJECT: + if (!isset($key[0]) || "\0" !== $key[0]) { + $this->line .= '+'.$bin.$this->style('public', $key).': '; + } elseif (0 < strpos($key, "\0", 1)) { + $key = explode("\0", substr($key, 1), 2); + + switch ($key[0][0]) { + case '+': // User inserted keys + $attr['dynamic'] = true; + $this->line .= '+'.$bin.'"'.$this->style('public', $key[1], $attr).'": '; + break 2; + case '~': + $style = 'meta'; + if (isset($key[0][1])) { + parse_str(substr($key[0], 1), $attr); + $attr += ['binary' => $cursor->hashKeyIsBinary]; + } + break; + case '*': + $style = 'protected'; + $bin = '#'.$bin; + break; + default: + $attr['class'] = $key[0]; + $style = 'private'; + $bin = '-'.$bin; + break; + } + + if (isset($attr['collapse'])) { + if ($attr['collapse']) { + $this->collapseNextHash = true; + } else { + $this->expandNextHash = true; + } + } + + $this->line .= $bin.$this->style($style, $key[1], $attr).($attr['separator'] ?? ': '); + } else { + // This case should not happen + $this->line .= '-'.$bin.'"'.$this->style('private', $key, ['class' => '']).'": '; + } + break; + } + + if ($cursor->hardRefTo) { + $this->line .= $this->style('ref', '&'.($cursor->hardRefCount ? $cursor->hardRefTo : ''), ['count' => $cursor->hardRefCount]).' '; + } + } + } + + /** + * Decorates a value with some style. + * + * @param string $style The type of style being applied + * @param string $value The value being styled + * @param array $attr Optional context information + * + * @return string + */ + protected function style(string $style, string $value, array $attr = []) + { + if (null === $this->colors) { + $this->colors = $this->supportsColors(); + } + + if (null === $this->handlesHrefGracefully) { + $this->handlesHrefGracefully = 'JetBrains-JediTerm' !== getenv('TERMINAL_EMULATOR') + && (!getenv('KONSOLE_VERSION') || (int) getenv('KONSOLE_VERSION') > 201100) + && !isset($_SERVER['IDEA_INITIAL_DIRECTORY']); + } + + if (isset($attr['ellipsis'], $attr['ellipsis-type'])) { + $prefix = substr($value, 0, -$attr['ellipsis']); + if ('cli' === \PHP_SAPI && 'path' === $attr['ellipsis-type'] && isset($_SERVER[$pwd = '\\' === \DIRECTORY_SEPARATOR ? 'CD' : 'PWD']) && str_starts_with($prefix, $_SERVER[$pwd])) { + $prefix = '.'.substr($prefix, \strlen($_SERVER[$pwd])); + } + if (!empty($attr['ellipsis-tail'])) { + $prefix .= substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']); + $value = substr($value, -$attr['ellipsis'] + $attr['ellipsis-tail']); + } else { + $value = substr($value, -$attr['ellipsis']); + } + + $value = $this->style('default', $prefix).$this->style($style, $value); + + goto href; + } + + $map = static::$controlCharsMap; + $startCchr = $this->colors ? "\033[m\033[{$this->styles['default']}m" : ''; + $endCchr = $this->colors ? "\033[m\033[{$this->styles[$style]}m" : ''; + $value = preg_replace_callback(static::$controlCharsRx, function ($c) use ($map, $startCchr, $endCchr) { + $s = $startCchr; + $c = $c[$i = 0]; + do { + $s .= $map[$c[$i]] ?? sprintf('\x%02X', \ord($c[$i])); + } while (isset($c[++$i])); + + return $s.$endCchr; + }, $value, -1, $cchrCount); + + if ($this->colors) { + if ($cchrCount && "\033" === $value[0]) { + $value = substr($value, \strlen($startCchr)); + } else { + $value = "\033[{$this->styles[$style]}m".$value; + } + if ($cchrCount && str_ends_with($value, $endCchr)) { + $value = substr($value, 0, -\strlen($endCchr)); + } else { + $value .= "\033[{$this->styles['default']}m"; + } + } + + href: + if ($this->colors && $this->handlesHrefGracefully) { + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { + if ('note' === $style) { + $value .= "\033]8;;{$href}\033\\^\033]8;;\033\\"; + } else { + $attr['href'] = $href; + } + } + if (isset($attr['href'])) { + $value = "\033]8;;{$attr['href']}\033\\{$value}\033]8;;\033\\"; + } + } elseif ($attr['if_links'] ?? false) { + return ''; + } + + return $value; + } + + /** + * @return bool + */ + protected function supportsColors() + { + if ($this->outputStream !== static::$defaultOutput) { + return $this->hasColorSupport($this->outputStream); + } + if (null !== static::$defaultColors) { + return static::$defaultColors; + } + if (isset($_SERVER['argv'][1])) { + $colors = $_SERVER['argv']; + $i = \count($colors); + while (--$i > 0) { + if (isset($colors[$i][5])) { + switch ($colors[$i]) { + case '--ansi': + case '--color': + case '--color=yes': + case '--color=force': + case '--color=always': + case '--colors=always': + return static::$defaultColors = true; + + case '--no-ansi': + case '--color=no': + case '--color=none': + case '--color=never': + case '--colors=never': + return static::$defaultColors = false; + } + } + } + } + + $h = stream_get_meta_data($this->outputStream) + ['wrapper_type' => null]; + $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'w') : $this->outputStream; + + return static::$defaultColors = $this->hasColorSupport($h); + } + + /** + * {@inheritdoc} + */ + protected function dumpLine(int $depth, bool $endOfValue = false) + { + if ($this->colors) { + $this->line = sprintf("\033[%sm%s\033[m", $this->styles['default'], $this->line); + } + parent::dumpLine($depth); + } + + protected function endValue(Cursor $cursor) + { + if (-1 === $cursor->hashType) { + return; + } + + if (Stub::ARRAY_INDEXED === $cursor->hashType || Stub::ARRAY_ASSOC === $cursor->hashType) { + if (self::DUMP_TRAILING_COMMA & $this->flags && 0 < $cursor->depth) { + $this->line .= ','; + } elseif (self::DUMP_COMMA_SEPARATOR & $this->flags && 1 < $cursor->hashLength - $cursor->hashIndex) { + $this->line .= ','; + } + } + + $this->dumpLine($cursor->depth, true); + } + + /** + * Returns true if the stream supports colorization. + * + * Reference: Composer\XdebugHandler\Process::supportsColor + * https://github.com/composer/xdebug-handler + * + * @param mixed $stream A CLI output stream + */ + private function hasColorSupport($stream): bool + { + if (!\is_resource($stream) || 'stream' !== get_resource_type($stream)) { + return false; + } + + // Follow https://no-color.org/ + if (isset($_SERVER['NO_COLOR']) || false !== getenv('NO_COLOR')) { + return false; + } + + if ('Hyper' === getenv('TERM_PROGRAM')) { + return true; + } + + if (\DIRECTORY_SEPARATOR === '\\') { + return (\function_exists('sapi_windows_vt100_support') + && @sapi_windows_vt100_support($stream)) + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM'); + } + + return stream_isatty($stream); + } + + /** + * Returns true if the Windows terminal supports true color. + * + * Note that this does not check an output stream, but relies on environment + * variables from known implementations, or a PHP and Windows version that + * supports true color. + */ + private function isWindowsTrueColor(): bool + { + $result = 183 <= getenv('ANSICON_VER') + || 'ON' === getenv('ConEmuANSI') + || 'xterm' === getenv('TERM') + || 'Hyper' === getenv('TERM_PROGRAM'); + + if (!$result) { + $version = sprintf( + '%s.%s.%s', + PHP_WINDOWS_VERSION_MAJOR, + PHP_WINDOWS_VERSION_MINOR, + PHP_WINDOWS_VERSION_BUILD + ); + $result = $version >= '10.0.15063'; + } + + return $result; + } + + private function getSourceLink(string $file, int $line) + { + if ($fmt = $this->displayOptions['fileLinkFormat']) { + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : ($fmt->format($file, $line) ?: 'file://'.$file.'#L'.$line); + } + + return false; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php new file mode 100644 index 00000000..38f87897 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/CliContextProvider.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +/** + * Tries to provide context on CLI. + * + * @author Maxime Steinhausser + */ +final class CliContextProvider implements ContextProviderInterface +{ + public function getContext(): ?array + { + if ('cli' !== \PHP_SAPI) { + return null; + } + + return [ + 'command_line' => $commandLine = implode(' ', $_SERVER['argv'] ?? []), + 'identifier' => hash('crc32b', $commandLine.$_SERVER['REQUEST_TIME_FLOAT']), + ]; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php new file mode 100644 index 00000000..532aa0f9 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/ContextProviderInterface.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +/** + * Interface to provide contextual data about dump data clones sent to a server. + * + * @author Maxime Steinhausser + */ +interface ContextProviderInterface +{ + public function getContext(): ?array; +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php new file mode 100644 index 00000000..3684a475 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/RequestContextProvider.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; +use Symfony\Component\VarDumper\Cloner\VarCloner; + +/** + * Tries to provide context from a request. + * + * @author Maxime Steinhausser + */ +final class RequestContextProvider implements ContextProviderInterface +{ + private $requestStack; + private $cloner; + + public function __construct(RequestStack $requestStack) + { + $this->requestStack = $requestStack; + $this->cloner = new VarCloner(); + $this->cloner->setMaxItems(0); + $this->cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); + } + + public function getContext(): ?array + { + if (null === $request = $this->requestStack->getCurrentRequest()) { + return null; + } + + $controller = $request->attributes->get('_controller'); + + return [ + 'uri' => $request->getUri(), + 'method' => $request->getMethod(), + 'controller' => $controller ? $this->cloner->cloneVar($controller) : $controller, + 'identifier' => spl_object_hash($request), + ]; + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php b/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php new file mode 100644 index 00000000..520f9c46 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextProvider/SourceContextProvider.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper\ContextProvider; + +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\VarDumper; +use Twig\Template; + +/** + * Tries to provide context from sources (class name, file, line, code excerpt, ...). + * + * @author Nicolas Grekas + * @author Maxime Steinhausser + */ +final class SourceContextProvider implements ContextProviderInterface +{ + private $limit; + private $charset; + private $projectDir; + private $fileLinkFormatter; + + public function __construct(string $charset = null, string $projectDir = null, FileLinkFormatter $fileLinkFormatter = null, int $limit = 9) + { + $this->charset = $charset; + $this->projectDir = $projectDir; + $this->fileLinkFormatter = $fileLinkFormatter; + $this->limit = $limit; + } + + public function getContext(): ?array + { + $trace = debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS, $this->limit); + + $file = $trace[1]['file']; + $line = $trace[1]['line']; + $name = '-' === $file || 'Standard input code' === $file ? 'Standard input code' : false; + $fileExcerpt = false; + + for ($i = 2; $i < $this->limit; ++$i) { + if (isset($trace[$i]['class'], $trace[$i]['function']) + && 'dump' === $trace[$i]['function'] + && VarDumper::class === $trace[$i]['class'] + ) { + $file = $trace[$i]['file'] ?? $file; + $line = $trace[$i]['line'] ?? $line; + + while (++$i < $this->limit) { + if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && !str_starts_with($trace[$i]['function'], 'call_user_func')) { + $file = $trace[$i]['file']; + $line = $trace[$i]['line']; + + break; + } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof Template) { + $template = $trace[$i]['object']; + $name = $template->getTemplateName(); + $src = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : false); + $info = $template->getDebugInfo(); + if (isset($info[$trace[$i - 1]['line']])) { + $line = $info[$trace[$i - 1]['line']]; + $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; + + if ($src) { + $src = explode("\n", $src); + $fileExcerpt = []; + + for ($i = max($line - 3, 1), $max = min($line + 3, \count($src)); $i <= $max; ++$i) { + $fileExcerpt[] = ''.$this->htmlEncode($src[$i - 1]).''; + } + + $fileExcerpt = '
      '.implode("\n", $fileExcerpt).'
    '; + } + } + break; + } + } + break; + } + } + + if (false === $name) { + $name = str_replace('\\', '/', $file); + $name = substr($name, strrpos($name, '/') + 1); + } + + $context = ['name' => $name, 'file' => $file, 'line' => $line]; + $context['file_excerpt'] = $fileExcerpt; + + if (null !== $this->projectDir) { + $context['project_dir'] = $this->projectDir; + if (str_starts_with($file, $this->projectDir)) { + $context['file_relative'] = ltrim(substr($file, \strlen($this->projectDir)), \DIRECTORY_SEPARATOR); + } + } + + if ($this->fileLinkFormatter && $fileLink = $this->fileLinkFormatter->format($context['file'], $context['line'])) { + $context['file_link'] = $fileLink; + } + + return $context; + } + + private function htmlEncode(string $s): string + { + $html = ''; + + $dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset); + $dumper->setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + + $cloner = new VarCloner(); + $dumper->dump($cloner->cloneVar($s)); + + return substr(strip_tags($html), 1, -1); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php b/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php new file mode 100644 index 00000000..76384176 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ContextualizedDumper.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; + +/** + * @author Kévin Thérage + */ +class ContextualizedDumper implements DataDumperInterface +{ + private $wrappedDumper; + private $contextProviders; + + /** + * @param ContextProviderInterface[] $contextProviders + */ + public function __construct(DataDumperInterface $wrappedDumper, array $contextProviders) + { + $this->wrappedDumper = $wrappedDumper; + $this->contextProviders = $contextProviders; + } + + public function dump(Data $data) + { + $context = []; + foreach ($this->contextProviders as $contextProvider) { + $context[\get_class($contextProvider)] = $contextProvider->getContext(); + } + + $this->wrappedDumper->dump($data->withContext($context)); + } +} diff --git a/vendor/symfony/var-dumper/Dumper/DataDumperInterface.php b/vendor/symfony/var-dumper/Dumper/DataDumperInterface.php new file mode 100644 index 00000000..b173bccf --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/DataDumperInterface.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * DataDumperInterface for dumping Data objects. + * + * @author Nicolas Grekas + */ +interface DataDumperInterface +{ + public function dump(Data $data); +} diff --git a/vendor/symfony/var-dumper/Dumper/HtmlDumper.php b/vendor/symfony/var-dumper/Dumper/HtmlDumper.php new file mode 100644 index 00000000..75cbe2fc --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/HtmlDumper.php @@ -0,0 +1,986 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Cursor; +use Symfony\Component\VarDumper\Cloner\Data; + +/** + * HtmlDumper dumps variables as HTML. + * + * @author Nicolas Grekas + */ +class HtmlDumper extends CliDumper +{ + public static $defaultOutput = 'php://output'; + + protected static $themes = [ + 'dark' => [ + 'default' => 'background-color:#18171B; color:#FF8400; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', + 'num' => 'font-weight:bold; color:#1299DA', + 'const' => 'font-weight:bold', + 'str' => 'font-weight:bold; color:#56DB3A', + 'note' => 'color:#1299DA', + 'ref' => 'color:#A0A0A0', + 'public' => 'color:#FFFFFF', + 'protected' => 'color:#FFFFFF', + 'private' => 'color:#FFFFFF', + 'meta' => 'color:#B729D9', + 'key' => 'color:#56DB3A', + 'index' => 'color:#1299DA', + 'ellipsis' => 'color:#FF8400', + 'ns' => 'user-select:none;', + ], + 'light' => [ + 'default' => 'background:none; color:#CC7832; line-height:1.2em; font:12px Menlo, Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: break-all', + 'num' => 'font-weight:bold; color:#1299DA', + 'const' => 'font-weight:bold', + 'str' => 'font-weight:bold; color:#629755;', + 'note' => 'color:#6897BB', + 'ref' => 'color:#6E6E6E', + 'public' => 'color:#262626', + 'protected' => 'color:#262626', + 'private' => 'color:#262626', + 'meta' => 'color:#B729D9', + 'key' => 'color:#789339', + 'index' => 'color:#1299DA', + 'ellipsis' => 'color:#CC7832', + 'ns' => 'user-select:none;', + ], + ]; + + protected $dumpHeader; + protected $dumpPrefix = '
    ';
    +    protected $dumpSuffix = '
    '; + protected $dumpId = 'sf-dump'; + protected $colors = true; + protected $headerIsDumped = false; + protected $lastDepth = -1; + protected $styles; + + private $displayOptions = [ + 'maxDepth' => 1, + 'maxStringLength' => 160, + 'fileLinkFormat' => null, + ]; + private $extraDisplayOptions = []; + + /** + * {@inheritdoc} + */ + public function __construct($output = null, string $charset = null, int $flags = 0) + { + AbstractDumper::__construct($output, $charset, $flags); + $this->dumpId = 'sf-dump-'.mt_rand(); + $this->displayOptions['fileLinkFormat'] = \ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); + $this->styles = static::$themes['dark'] ?? self::$themes['dark']; + } + + /** + * {@inheritdoc} + */ + public function setStyles(array $styles) + { + $this->headerIsDumped = false; + $this->styles = $styles + $this->styles; + } + + public function setTheme(string $themeName) + { + if (!isset(static::$themes[$themeName])) { + throw new \InvalidArgumentException(sprintf('Theme "%s" does not exist in class "%s".', $themeName, static::class)); + } + + $this->setStyles(static::$themes[$themeName]); + } + + /** + * Configures display options. + * + * @param array $displayOptions A map of display options to customize the behavior + */ + public function setDisplayOptions(array $displayOptions) + { + $this->headerIsDumped = false; + $this->displayOptions = $displayOptions + $this->displayOptions; + } + + /** + * Sets an HTML header that will be dumped once in the output stream. + */ + public function setDumpHeader(?string $header) + { + $this->dumpHeader = $header; + } + + /** + * Sets an HTML prefix and suffix that will encapse every single dump. + */ + public function setDumpBoundaries(string $prefix, string $suffix) + { + $this->dumpPrefix = $prefix; + $this->dumpSuffix = $suffix; + } + + /** + * {@inheritdoc} + */ + public function dump(Data $data, $output = null, array $extraDisplayOptions = []) + { + $this->extraDisplayOptions = $extraDisplayOptions; + $result = parent::dump($data, $output); + $this->dumpId = 'sf-dump-'.mt_rand(); + + return $result; + } + + /** + * Dumps the HTML header. + */ + protected function getDumpHeader() + { + $this->headerIsDumped = $this->outputStream ?? $this->lineDumper; + + if (null !== $this->dumpHeader) { + return $this->dumpHeader; + } + + $line = str_replace('{$options}', json_encode($this->displayOptions, \JSON_FORCE_OBJECT), <<<'EOHTML' +'.$this->dumpHeader; + } + + /** + * {@inheritdoc} + */ + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) + { + if ('' === $str && isset($cursor->attr['img-data'], $cursor->attr['content-type'])) { + $this->dumpKey($cursor); + $this->line .= $this->style('default', $cursor->attr['img-size'] ?? '', []); + $this->line .= $cursor->depth >= $this->displayOptions['maxDepth'] ? ' ' : ' '; + $this->endValue($cursor); + $this->line .= $this->indentPad; + $this->line .= sprintf('', $cursor->attr['content-type'], base64_encode($cursor->attr['img-data'])); + $this->endValue($cursor); + } else { + parent::dumpString($cursor, $str, $bin, $cut); + } + } + + /** + * {@inheritdoc} + */ + public function enterHash(Cursor $cursor, int $type, $class, bool $hasChild) + { + if (Cursor::HASH_OBJECT === $type) { + $cursor->attr['depth'] = $cursor->depth; + } + parent::enterHash($cursor, $type, $class, false); + + if ($cursor->skipChildren || $cursor->depth >= $this->displayOptions['maxDepth']) { + $cursor->skipChildren = false; + $eol = ' class=sf-dump-compact>'; + } else { + $this->expandNextHash = false; + $eol = ' class=sf-dump-expanded>'; + } + + if ($hasChild) { + $this->line .= 'dumpId, $r); + } + $this->line .= $eol; + $this->dumpLine($cursor->depth); + } + } + + /** + * {@inheritdoc} + */ + public function leaveHash(Cursor $cursor, int $type, $class, bool $hasChild, int $cut) + { + $this->dumpEllipsis($cursor, $hasChild, $cut); + if ($hasChild) { + $this->line .= ''; + } + parent::leaveHash($cursor, $type, $class, $hasChild, 0); + } + + /** + * {@inheritdoc} + */ + protected function style(string $style, string $value, array $attr = []) + { + if ('' === $value) { + return ''; + } + + $v = esc($value); + + if ('ref' === $style) { + if (empty($attr['count'])) { + return sprintf('%s', $v); + } + $r = ('#' !== $v[0] ? 1 - ('@' !== $v[0]) : 2).substr($value, 1); + + return sprintf('%s', $this->dumpId, $r, 1 + $attr['count'], $v); + } + + if ('const' === $style && isset($attr['value'])) { + $style .= sprintf(' title="%s"', esc(\is_scalar($attr['value']) ? $attr['value'] : json_encode($attr['value']))); + } elseif ('public' === $style) { + $style .= sprintf(' title="%s"', empty($attr['dynamic']) ? 'Public property' : 'Runtime added dynamic property'); + } elseif ('str' === $style && 1 < $attr['length']) { + $style .= sprintf(' title="%d%s characters"', $attr['length'], $attr['binary'] ? ' binary or non-UTF-8' : ''); + } elseif ('note' === $style && 0 < ($attr['depth'] ?? 0) && false !== $c = strrpos($value, '\\')) { + $style .= ' title=""'; + $attr += [ + 'ellipsis' => \strlen($value) - $c, + 'ellipsis-type' => 'note', + 'ellipsis-tail' => 1, + ]; + } elseif ('protected' === $style) { + $style .= ' title="Protected property"'; + } elseif ('meta' === $style && isset($attr['title'])) { + $style .= sprintf(' title="%s"', esc($this->utf8Encode($attr['title']))); + } elseif ('private' === $style) { + $style .= sprintf(' title="Private property defined in class: `%s`"', esc($this->utf8Encode($attr['class']))); + } + $map = static::$controlCharsMap; + + if (isset($attr['ellipsis'])) { + $class = 'sf-dump-ellipsis'; + if (isset($attr['ellipsis-type'])) { + $class = sprintf('"%s sf-dump-ellipsis-%s"', $class, $attr['ellipsis-type']); + } + $label = esc(substr($value, -$attr['ellipsis'])); + $style = str_replace(' title="', " title=\"$v\n", $style); + $v = sprintf('%s', $class, substr($v, 0, -\strlen($label))); + + if (!empty($attr['ellipsis-tail'])) { + $tail = \strlen(esc(substr($value, -$attr['ellipsis'], $attr['ellipsis-tail']))); + $v .= sprintf('%s%s', $class, substr($label, 0, $tail), substr($label, $tail)); + } else { + $v .= $label; + } + } + + $v = "".preg_replace_callback(static::$controlCharsRx, function ($c) use ($map) { + $s = $b = ''; + }, $v).''; + + if (isset($attr['file']) && $href = $this->getSourceLink($attr['file'], $attr['line'] ?? 0)) { + $attr['href'] = $href; + } + if (isset($attr['href'])) { + $target = isset($attr['file']) ? '' : ' target="_blank"'; + $v = sprintf('%s', esc($this->utf8Encode($attr['href'])), $target, $v); + } + if (isset($attr['lang'])) { + $v = sprintf('%s', esc($attr['lang']), $v); + } + + return $v; + } + + /** + * {@inheritdoc} + */ + protected function dumpLine(int $depth, bool $endOfValue = false) + { + if (-1 === $this->lastDepth) { + $this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; + } + if ($this->headerIsDumped !== ($this->outputStream ?? $this->lineDumper)) { + $this->line = $this->getDumpHeader().$this->line; + } + + if (-1 === $depth) { + $args = ['"'.$this->dumpId.'"']; + if ($this->extraDisplayOptions) { + $args[] = json_encode($this->extraDisplayOptions, \JSON_FORCE_OBJECT); + } + // Replace is for BC + $this->line .= sprintf(str_replace('"%s"', '%s', $this->dumpSuffix), implode(', ', $args)); + } + $this->lastDepth = $depth; + + $this->line = mb_encode_numericentity($this->line, [0x80, 0x10FFFF, 0, 0x1FFFFF], 'UTF-8'); + + if (-1 === $depth) { + AbstractDumper::dumpLine(0); + } + AbstractDumper::dumpLine($depth); + } + + private function getSourceLink(string $file, int $line) + { + $options = $this->extraDisplayOptions + $this->displayOptions; + + if ($fmt = $options['fileLinkFormat']) { + return \is_string($fmt) ? strtr($fmt, ['%f' => $file, '%l' => $line]) : $fmt->format($file, $line); + } + + return false; + } +} + +function esc(string $str) +{ + return htmlspecialchars($str, \ENT_QUOTES, 'UTF-8'); +} diff --git a/vendor/symfony/var-dumper/Dumper/ServerDumper.php b/vendor/symfony/var-dumper/Dumper/ServerDumper.php new file mode 100644 index 00000000..94795bf6 --- /dev/null +++ b/vendor/symfony/var-dumper/Dumper/ServerDumper.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Dumper; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; +use Symfony\Component\VarDumper\Server\Connection; + +/** + * ServerDumper forwards serialized Data clones to a server. + * + * @author Maxime Steinhausser + */ +class ServerDumper implements DataDumperInterface +{ + private $connection; + private $wrappedDumper; + + /** + * @param string $host The server host + * @param DataDumperInterface|null $wrappedDumper A wrapped instance used whenever we failed contacting the server + * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name + */ + public function __construct(string $host, DataDumperInterface $wrappedDumper = null, array $contextProviders = []) + { + $this->connection = new Connection($host, $contextProviders); + $this->wrappedDumper = $wrappedDumper; + } + + public function getContextProviders(): array + { + return $this->connection->getContextProviders(); + } + + /** + * {@inheritdoc} + */ + public function dump(Data $data) + { + if (!$this->connection->write($data) && $this->wrappedDumper) { + $this->wrappedDumper->dump($data); + } + } +} diff --git a/vendor/symfony/var-dumper/Exception/ThrowingCasterException.php b/vendor/symfony/var-dumper/Exception/ThrowingCasterException.php new file mode 100644 index 00000000..122f0d35 --- /dev/null +++ b/vendor/symfony/var-dumper/Exception/ThrowingCasterException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Exception; + +/** + * @author Nicolas Grekas + */ +class ThrowingCasterException extends \Exception +{ + /** + * @param \Throwable $prev The exception thrown from the caster + */ + public function __construct(\Throwable $prev) + { + parent::__construct('Unexpected '.\get_class($prev).' thrown from a caster: '.$prev->getMessage(), 0, $prev); + } +} diff --git a/vendor/symfony/var-dumper/LICENSE b/vendor/symfony/var-dumper/LICENSE new file mode 100644 index 00000000..29f72d5e --- /dev/null +++ b/vendor/symfony/var-dumper/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/var-dumper/README.md b/vendor/symfony/var-dumper/README.md new file mode 100644 index 00000000..a0da8c9a --- /dev/null +++ b/vendor/symfony/var-dumper/README.md @@ -0,0 +1,15 @@ +VarDumper Component +=================== + +The VarDumper component provides mechanisms for walking through any arbitrary +PHP variable. It provides a better `dump()` function that you can use instead +of `var_dump()`. + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/var_dumper/introduction.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/var-dumper/Resources/bin/var-dump-server b/vendor/symfony/var-dumper/Resources/bin/var-dump-server new file mode 100755 index 00000000..f398fcef --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/bin/var-dump-server @@ -0,0 +1,67 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if ('cli' !== PHP_SAPI) { + throw new Exception('This script must be run from the command line.'); +} + +/** + * Starts a dump server to collect and output dumps on a single place with multiple formats support. + * + * @author Maxime Steinhausser + */ + +use Psr\Log\LoggerInterface; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Input\ArgvInput; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Logger\ConsoleLogger; +use Symfony\Component\Console\Output\ConsoleOutput; +use Symfony\Component\VarDumper\Command\ServerDumpCommand; +use Symfony\Component\VarDumper\Server\DumpServer; + +function includeIfExists(string $file): bool +{ + return file_exists($file) && include $file; +} + +if ( + !includeIfExists(__DIR__ . '/../../../../autoload.php') && + !includeIfExists(__DIR__ . '/../../vendor/autoload.php') && + !includeIfExists(__DIR__ . '/../../../../../../vendor/autoload.php') +) { + fwrite(STDERR, 'Install dependencies using Composer.'.PHP_EOL); + exit(1); +} + +if (!class_exists(Application::class)) { + fwrite(STDERR, 'You need the "symfony/console" component in order to run the VarDumper server.'.PHP_EOL); + exit(1); +} + +$input = new ArgvInput(); +$output = new ConsoleOutput(); +$defaultHost = '127.0.0.1:9912'; +$host = $input->getParameterOption(['--host'], $_SERVER['VAR_DUMPER_SERVER'] ?? $defaultHost, true); +$logger = interface_exists(LoggerInterface::class) ? new ConsoleLogger($output->getErrorOutput()) : null; + +$app = new Application(); + +$app->getDefinition()->addOption( + new InputOption('--host', null, InputOption::VALUE_REQUIRED, 'The address the server should listen to', $defaultHost) +); + +$app->add($command = new ServerDumpCommand(new DumpServer($host, $logger))) + ->getApplication() + ->setDefaultCommand($command->getName(), true) + ->run($input, $output) +; diff --git a/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css b/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css new file mode 100644 index 00000000..8f706d64 --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/css/htmlDescriptor.css @@ -0,0 +1,130 @@ +body { + display: flex; + flex-direction: column-reverse; + justify-content: flex-end; + max-width: 1140px; + margin: auto; + padding: 15px; + word-wrap: break-word; + background-color: #F9F9F9; + color: #222; + font-family: Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 1.4; +} +p { + margin: 0; +} +a { + color: #218BC3; + text-decoration: none; +} +a:hover { + text-decoration: underline; +} +.text-small { + font-size: 12px !important; +} +article { + margin: 5px; + margin-bottom: 10px; +} +article > header > .row { + display: flex; + flex-direction: row; + align-items: baseline; + margin-bottom: 10px; +} +article > header > .row > .col { + flex: 1; + display: flex; + align-items: baseline; +} +article > header > .row > h2 { + font-size: 14px; + color: #222; + font-weight: normal; + font-family: "Lucida Console", monospace, sans-serif; + word-break: break-all; + margin: 20px 5px 0 0; + user-select: all; +} +article > header > .row > h2 > code { + white-space: nowrap; + user-select: none; + color: #cc2255; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; + border-radius: 3px; + margin-right: 5px; + padding: 0 3px; +} +article > header > .row > time.col { + flex: 0; + text-align: right; + white-space: nowrap; + color: #999; + font-style: italic; +} +article > header ul.tags { + list-style: none; + padding: 0; + margin: 0; + font-size: 12px; +} +article > header ul.tags > li { + user-select: all; + margin-bottom: 2px; +} +article > header ul.tags > li > span.badge { + display: inline-block; + padding: .25em .4em; + margin-right: 5px; + border-radius: 4px; + background-color: #6c757d3b; + color: #524d4d; + font-size: 12px; + text-align: center; + font-weight: 700; + line-height: 1; + white-space: nowrap; + vertical-align: baseline; + user-select: none; +} +article > section.body { + border: 1px solid #d8d8d8; + background: #FFF; + padding: 10px; + border-radius: 3px; +} +pre.sf-dump { + border-radius: 3px; + margin-bottom: 0; +} +.hidden { + display: none !important; +} +.dumped-tag > .sf-dump { + display: inline-block; + margin: 0; + padding: 1px 5px; + line-height: 1.4; + vertical-align: top; + background-color: transparent; + user-select: auto; +} +.dumped-tag > pre.sf-dump, +.dumped-tag > .sf-dump-default { + color: #CC7832; + background: none; +} +.dumped-tag > .sf-dump .sf-dump-str { color: #629755; } +.dumped-tag > .sf-dump .sf-dump-private, +.dumped-tag > .sf-dump .sf-dump-protected, +.dumped-tag > .sf-dump .sf-dump-public { color: #262626; } +.dumped-tag > .sf-dump .sf-dump-note { color: #6897BB; } +.dumped-tag > .sf-dump .sf-dump-key { color: #789339; } +.dumped-tag > .sf-dump .sf-dump-ref { color: #6E6E6E; } +.dumped-tag > .sf-dump .sf-dump-ellipsis { color: #CC7832; max-width: 100em; } +.dumped-tag > .sf-dump .sf-dump-ellipsis-path { max-width: 5em; } +.dumped-tag > .sf-dump .sf-dump-ns { user-select: none; } diff --git a/vendor/symfony/var-dumper/Resources/functions/dump.php b/vendor/symfony/var-dumper/Resources/functions/dump.php new file mode 100644 index 00000000..f26aad5b --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/functions/dump.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Component\VarDumper\VarDumper; + +if (!function_exists('dump')) { + /** + * @author Nicolas Grekas + */ + function dump($var, ...$moreVars) + { + VarDumper::dump($var); + + foreach ($moreVars as $v) { + VarDumper::dump($v); + } + + if (1 < func_num_args()) { + return func_get_args(); + } + + return $var; + } +} + +if (!function_exists('dd')) { + /** + * @return never + */ + function dd(...$vars) + { + if (!in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && !headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + + foreach ($vars as $v) { + VarDumper::dump($v); + } + + exit(1); + } +} diff --git a/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js b/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js new file mode 100644 index 00000000..63101e57 --- /dev/null +++ b/vendor/symfony/var-dumper/Resources/js/htmlDescriptor.js @@ -0,0 +1,10 @@ +document.addEventListener('DOMContentLoaded', function() { + let prev = null; + Array.from(document.getElementsByTagName('article')).reverse().forEach(function (article) { + const dedupId = article.dataset.dedupId; + if (dedupId === prev) { + article.getElementsByTagName('header')[0].classList.add('hidden'); + } + prev = dedupId; + }); +}); diff --git a/vendor/symfony/var-dumper/Server/Connection.php b/vendor/symfony/var-dumper/Server/Connection.php new file mode 100644 index 00000000..ebfc6506 --- /dev/null +++ b/vendor/symfony/var-dumper/Server/Connection.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Server; + +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Dumper\ContextProvider\ContextProviderInterface; + +/** + * Forwards serialized Data clones to a server. + * + * @author Maxime Steinhausser + */ +class Connection +{ + private $host; + private $contextProviders; + + /** + * @var resource|null + */ + private $socket; + + /** + * @param string $host The server host + * @param ContextProviderInterface[] $contextProviders Context providers indexed by context name + */ + public function __construct(string $host, array $contextProviders = []) + { + if (!str_contains($host, '://')) { + $host = 'tcp://'.$host; + } + + $this->host = $host; + $this->contextProviders = $contextProviders; + } + + public function getContextProviders(): array + { + return $this->contextProviders; + } + + public function write(Data $data): bool + { + $socketIsFresh = !$this->socket; + if (!$this->socket = $this->socket ?: $this->createSocket()) { + return false; + } + + $context = ['timestamp' => microtime(true)]; + foreach ($this->contextProviders as $name => $provider) { + $context[$name] = $provider->getContext(); + } + $context = array_filter($context); + $encodedPayload = base64_encode(serialize([$data, $context]))."\n"; + + set_error_handler([self::class, 'nullErrorHandler']); + try { + if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { + return true; + } + if (!$socketIsFresh) { + stream_socket_shutdown($this->socket, \STREAM_SHUT_RDWR); + fclose($this->socket); + $this->socket = $this->createSocket(); + } + if (-1 !== stream_socket_sendto($this->socket, $encodedPayload)) { + return true; + } + } finally { + restore_error_handler(); + } + + return false; + } + + private static function nullErrorHandler(int $t, string $m) + { + // no-op + } + + private function createSocket() + { + set_error_handler([self::class, 'nullErrorHandler']); + try { + return stream_socket_client($this->host, $errno, $errstr, 3); + } finally { + restore_error_handler(); + } + } +} diff --git a/vendor/symfony/var-dumper/Server/DumpServer.php b/vendor/symfony/var-dumper/Server/DumpServer.php new file mode 100644 index 00000000..f9735db7 --- /dev/null +++ b/vendor/symfony/var-dumper/Server/DumpServer.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Server; + +use Psr\Log\LoggerInterface; +use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\VarDumper\Cloner\Stub; + +/** + * A server collecting Data clones sent by a ServerDumper. + * + * @author Maxime Steinhausser + * + * @final + */ +class DumpServer +{ + private $host; + private $logger; + + /** + * @var resource|null + */ + private $socket; + + public function __construct(string $host, LoggerInterface $logger = null) + { + if (!str_contains($host, '://')) { + $host = 'tcp://'.$host; + } + + $this->host = $host; + $this->logger = $logger; + } + + public function start(): void + { + if (!$this->socket = stream_socket_server($this->host, $errno, $errstr)) { + throw new \RuntimeException(sprintf('Server start failed on "%s": ', $this->host).$errstr.' '.$errno); + } + } + + public function listen(callable $callback): void + { + if (null === $this->socket) { + $this->start(); + } + + foreach ($this->getMessages() as $clientId => $message) { + if ($this->logger) { + $this->logger->info('Received a payload from client {clientId}', ['clientId' => $clientId]); + } + + $payload = @unserialize(base64_decode($message), ['allowed_classes' => [Data::class, Stub::class]]); + + // Impossible to decode the message, give up. + if (false === $payload) { + if ($this->logger) { + $this->logger->warning('Unable to decode a message from {clientId} client.', ['clientId' => $clientId]); + } + + continue; + } + + if (!\is_array($payload) || \count($payload) < 2 || !$payload[0] instanceof Data || !\is_array($payload[1])) { + if ($this->logger) { + $this->logger->warning('Invalid payload from {clientId} client. Expected an array of two elements (Data $data, array $context)', ['clientId' => $clientId]); + } + + continue; + } + + [$data, $context] = $payload; + + $callback($data, $context, $clientId); + } + } + + public function getHost(): string + { + return $this->host; + } + + private function getMessages(): iterable + { + $sockets = [(int) $this->socket => $this->socket]; + $write = []; + + while (true) { + $read = $sockets; + stream_select($read, $write, $write, null); + + foreach ($read as $stream) { + if ($this->socket === $stream) { + $stream = stream_socket_accept($this->socket); + $sockets[(int) $stream] = $stream; + } elseif (feof($stream)) { + unset($sockets[(int) $stream]); + fclose($stream); + } else { + yield (int) $stream => fgets($stream); + } + } + } + } +} diff --git a/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php b/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php new file mode 100644 index 00000000..33d60c02 --- /dev/null +++ b/vendor/symfony/var-dumper/Test/VarDumperTestTrait.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper\Test; + +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +/** + * @author Nicolas Grekas + */ +trait VarDumperTestTrait +{ + /** + * @internal + */ + private $varDumperConfig = [ + 'casters' => [], + 'flags' => null, + ]; + + protected function setUpVarDumper(array $casters, int $flags = null): void + { + $this->varDumperConfig['casters'] = $casters; + $this->varDumperConfig['flags'] = $flags; + } + + /** + * @after + */ + protected function tearDownVarDumper(): void + { + $this->varDumperConfig['casters'] = []; + $this->varDumperConfig['flags'] = null; + } + + public function assertDumpEquals($expected, $data, int $filter = 0, string $message = '') + { + $this->assertSame($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); + } + + public function assertDumpMatchesFormat($expected, $data, int $filter = 0, string $message = '') + { + $this->assertStringMatchesFormat($this->prepareExpectation($expected, $filter), $this->getDump($data, null, $filter), $message); + } + + protected function getDump($data, $key = null, int $filter = 0): ?string + { + if (null === $flags = $this->varDumperConfig['flags']) { + $flags = getenv('DUMP_LIGHT_ARRAY') ? CliDumper::DUMP_LIGHT_ARRAY : 0; + $flags |= getenv('DUMP_STRING_LENGTH') ? CliDumper::DUMP_STRING_LENGTH : 0; + $flags |= getenv('DUMP_COMMA_SEPARATOR') ? CliDumper::DUMP_COMMA_SEPARATOR : 0; + } + + $cloner = new VarCloner(); + $cloner->addCasters($this->varDumperConfig['casters']); + $cloner->setMaxItems(-1); + $dumper = new CliDumper(null, null, $flags); + $dumper->setColors(false); + $data = $cloner->cloneVar($data, $filter)->withRefHandles(false); + if (null !== $key && null === $data = $data->seek($key)) { + return null; + } + + return rtrim($dumper->dump($data, true)); + } + + private function prepareExpectation($expected, int $filter): string + { + if (!\is_string($expected)) { + $expected = $this->getDump($expected, null, $filter); + } + + return rtrim($expected); + } +} diff --git a/vendor/symfony/var-dumper/VarDumper.php b/vendor/symfony/var-dumper/VarDumper.php new file mode 100644 index 00000000..20429ac7 --- /dev/null +++ b/vendor/symfony/var-dumper/VarDumper.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarDumper; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; +use Symfony\Component\VarDumper\Caster\ReflectionCaster; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\ContextProvider\CliContextProvider; +use Symfony\Component\VarDumper\Dumper\ContextProvider\RequestContextProvider; +use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; +use Symfony\Component\VarDumper\Dumper\ContextualizedDumper; +use Symfony\Component\VarDumper\Dumper\HtmlDumper; +use Symfony\Component\VarDumper\Dumper\ServerDumper; + +// Load the global dump() function +require_once __DIR__.'/Resources/functions/dump.php'; + +/** + * @author Nicolas Grekas + */ +class VarDumper +{ + /** + * @var callable|null + */ + private static $handler; + + public static function dump($var) + { + if (null === self::$handler) { + self::register(); + } + + return (self::$handler)($var); + } + + /** + * @return callable|null + */ + public static function setHandler(callable $callable = null) + { + $prevHandler = self::$handler; + + // Prevent replacing the handler with expected format as soon as the env var was set: + if (isset($_SERVER['VAR_DUMPER_FORMAT'])) { + return $prevHandler; + } + + self::$handler = $callable; + + return $prevHandler; + } + + private static function register(): void + { + $cloner = new VarCloner(); + $cloner->addCasters(ReflectionCaster::UNSET_CLOSURE_FILE_INFO); + + $format = $_SERVER['VAR_DUMPER_FORMAT'] ?? null; + switch (true) { + case 'html' === $format: + $dumper = new HtmlDumper(); + break; + case 'cli' === $format: + $dumper = new CliDumper(); + break; + case 'server' === $format: + case $format && 'tcp' === parse_url($format, \PHP_URL_SCHEME): + $host = 'server' === $format ? $_SERVER['VAR_DUMPER_SERVER'] ?? '127.0.0.1:9912' : $format; + $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliDumper() : new HtmlDumper(); + $dumper = new ServerDumper($host, $dumper, self::getDefaultContextProviders()); + break; + default: + $dumper = \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) ? new CliDumper() : new HtmlDumper(); + } + + if (!$dumper instanceof ServerDumper) { + $dumper = new ContextualizedDumper($dumper, [new SourceContextProvider()]); + } + + self::$handler = function ($var) use ($cloner, $dumper) { + $dumper->dump($cloner->cloneVar($var)); + }; + } + + private static function getDefaultContextProviders(): array + { + $contextProviders = []; + + if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) && class_exists(Request::class)) { + $requestStack = new RequestStack(); + $requestStack->push(Request::createFromGlobals()); + $contextProviders['request'] = new RequestContextProvider($requestStack); + } + + $fileLinkFormatter = class_exists(FileLinkFormatter::class) ? new FileLinkFormatter(null, $requestStack ?? null) : null; + + return $contextProviders + [ + 'cli' => new CliContextProvider(), + 'source' => new SourceContextProvider(null, null, $fileLinkFormatter), + ]; + } +} diff --git a/vendor/symfony/var-dumper/composer.json b/vendor/symfony/var-dumper/composer.json new file mode 100644 index 00000000..ea46a72b --- /dev/null +++ b/vendor/symfony/var-dumper/composer.json @@ -0,0 +1,50 @@ +{ + "name": "symfony/var-dumper", + "type": "library", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "keywords": ["dump", "debug"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "suggest": { + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" + }, + "autoload": { + "files": [ "Resources/functions/dump.php" ], + "psr-4": { "Symfony\\Component\\VarDumper\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "minimum-stability": "dev" +} diff --git a/vendor/symfony/var-exporter/CHANGELOG.md b/vendor/symfony/var-exporter/CHANGELOG.md new file mode 100644 index 00000000..3406c30e --- /dev/null +++ b/vendor/symfony/var-exporter/CHANGELOG.md @@ -0,0 +1,12 @@ +CHANGELOG +========= + +5.1.0 +----- + + * added argument `array &$foundClasses` to `VarExporter::export()` to ease with preloading exported values + +4.2.0 +----- + + * added the component diff --git a/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php b/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php new file mode 100644 index 00000000..4cebe44b --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +class ClassNotFoundException extends \Exception implements ExceptionInterface +{ + public function __construct(string $class, \Throwable $previous = null) + { + parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous); + } +} diff --git a/vendor/symfony/var-exporter/Exception/ExceptionInterface.php b/vendor/symfony/var-exporter/Exception/ExceptionInterface.php new file mode 100644 index 00000000..adfaed47 --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/ExceptionInterface.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php b/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php new file mode 100644 index 00000000..771ee612 --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Exception; + +class NotInstantiableTypeException extends \Exception implements ExceptionInterface +{ + public function __construct(string $type, \Throwable $previous = null) + { + parent::__construct(sprintf('Type "%s" is not instantiable.', $type), 0, $previous); + } +} diff --git a/vendor/symfony/var-exporter/Instantiator.php b/vendor/symfony/var-exporter/Instantiator.php new file mode 100644 index 00000000..368c769a --- /dev/null +++ b/vendor/symfony/var-exporter/Instantiator.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\VarExporter\Exception\ExceptionInterface; +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\Registry; + +/** + * A utility class to create objects without calling their constructor. + * + * @author Nicolas Grekas + */ +final class Instantiator +{ + /** + * Creates an object and sets its properties without calling its constructor nor any other methods. + * + * For example: + * + * // creates an empty instance of Foo + * Instantiator::instantiate(Foo::class); + * + * // creates a Foo instance and sets one of its properties + * Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]); + * + * // creates a Foo instance and sets a private property defined on its parent Bar class + * Instantiator::instantiate(Foo::class, [], [ + * Bar::class => ['privateBarProperty' => $propertyValue], + * ]); + * + * Instances of ArrayObject, ArrayIterator and SplObjectStorage can be created + * by using the special "\0" property name to define their internal value: + * + * // creates an SplObjectStorage where $info1 is attached to $obj1, etc. + * Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]); + * + * // creates an ArrayObject populated with $inputArray + * Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]); + * + * @param string $class The class of the instance to create + * @param array $properties The properties to set on the instance + * @param array $privateProperties The private properties to set on the instance, + * keyed by their declaring class + * + * @throws ExceptionInterface When the instance cannot be created + */ + public static function instantiate(string $class, array $properties = [], array $privateProperties = []): object + { + $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); + + if (Registry::$cloneable[$class]) { + $wrappedInstance = [clone Registry::$prototypes[$class]]; + } elseif (Registry::$instantiableWithoutConstructor[$class]) { + $wrappedInstance = [$reflector->newInstanceWithoutConstructor()]; + } elseif (null === Registry::$prototypes[$class]) { + throw new NotInstantiableTypeException($class); + } elseif ($reflector->implementsInterface('Serializable') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize'))) { + $wrappedInstance = [unserialize('C:'.\strlen($class).':"'.$class.'":0:{}')]; + } else { + $wrappedInstance = [unserialize('O:'.\strlen($class).':"'.$class.'":0:{}')]; + } + + if ($properties) { + $privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties; + } + + foreach ($privateProperties as $class => $properties) { + if (!$properties) { + continue; + } + foreach ($properties as $name => $value) { + // because they're also used for "unserialization", hydrators + // deal with array of instances, so we need to wrap values + $properties[$name] = [$value]; + } + (Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance); + } + + return $wrappedInstance[0]; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Exporter.php b/vendor/symfony/var-exporter/Internal/Exporter.php new file mode 100644 index 00000000..b5ee88c0 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Exporter.php @@ -0,0 +1,419 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Exporter +{ + /** + * Prepares an array of values for VarExporter. + * + * For performance this method is public and has no type-hints. + * + * @param array &$values + * @param \SplObjectStorage $objectsPool + * @param array &$refsPool + * @param int &$objectsCount + * @param bool &$valuesAreStatic + * + * @throws NotInstantiableTypeException When a value cannot be serialized + */ + public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic): array + { + $refs = $values; + foreach ($values as $k => $value) { + if (\is_resource($value)) { + throw new NotInstantiableTypeException(get_resource_type($value).' resource'); + } + $refs[$k] = $objectsPool; + + if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) { + $values[$k] = &$value; // Break hard references to make $values completely + unset($value); // independent from the original structure + $refs[$k] = $value = $values[$k]; + if ($value instanceof Reference && 0 > $value->id) { + $valuesAreStatic = false; + ++$value->count; + continue; + } + $refsPool[] = [&$refs[$k], $value, &$value]; + $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value); + } + + if (\is_array($value)) { + if ($value) { + $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); + } + goto handle_value; + } elseif (!\is_object($value) || $value instanceof \UnitEnum) { + goto handle_value; + } + + $valueIsStatic = false; + if (isset($objectsPool[$value])) { + ++$objectsCount; + $value = new Reference($objectsPool[$value][0]); + goto handle_value; + } + + $class = \get_class($value); + $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); + $properties = []; + + if ($reflector->hasMethod('__serialize')) { + if (!$reflector->getMethod('__serialize')->isPublic()) { + throw new \Error(sprintf('Call to %s method "%s::__serialize()".', $reflector->getMethod('__serialize')->isProtected() ? 'protected' : 'private', $class)); + } + + if (!\is_array($serializeProperties = $value->__serialize())) { + throw new \TypeError($class.'::__serialize() must return an array'); + } + + if ($reflector->hasMethod('__unserialize')) { + $properties = $serializeProperties; + } else { + foreach ($serializeProperties as $n => $v) { + $c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass'; + $properties[$c][$n] = $v; + } + } + + goto prepare_value; + } + + $sleep = null; + $proto = Registry::$prototypes[$class]; + + if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) { + // ArrayIterator and ArrayObject need special care because their "flags" + // option changes the behavior of the (array) casting operator. + [$arrayValue, $properties] = self::getArrayObjectProperties($value, $proto); + + // populates Registry::$prototypes[$class] with a new instance + Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]); + } elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) { + // By implementing Serializable, SplObjectStorage breaks + // internal references; let's deal with it on our own. + foreach (clone $value as $v) { + $properties[] = $v; + $properties[] = $value[$v]; + } + $properties = ['SplObjectStorage' => ["\0" => $properties]]; + $arrayValue = (array) $value; + } elseif ($value instanceof \Serializable + || $value instanceof \__PHP_Incomplete_Class + || \PHP_VERSION_ID < 80200 && $value instanceof \DatePeriod + ) { + ++$objectsCount; + $objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0]; + $value = new Reference($id); + goto handle_value; + } else { + if (method_exists($class, '__sleep')) { + if (!\is_array($sleep = $value->__sleep())) { + trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE); + $value = null; + goto handle_value; + } + $sleep = array_flip($sleep); + } + + $arrayValue = (array) $value; + } + + $proto = (array) $proto; + + foreach ($arrayValue as $name => $v) { + $i = 0; + $n = (string) $name; + if ('' === $n || "\0" !== $n[0]) { + $c = \PHP_VERSION_ID >= 80100 && $reflector->hasProperty($n) && ($p = $reflector->getProperty($n))->isReadOnly() ? $p->class : 'stdClass'; + } elseif ('*' === $n[1]) { + $n = substr($n, 3); + $c = $reflector->getProperty($n)->class; + if ('Error' === $c) { + $c = 'TypeError'; + } elseif ('Exception' === $c) { + $c = 'ErrorException'; + } + } else { + $i = strpos($n, "\0", 2); + $c = substr($n, 1, $i - 1); + $n = substr($n, 1 + $i); + } + if (null !== $sleep) { + if (!isset($sleep[$n]) || ($i && $c !== $class)) { + unset($arrayValue[$name]); + continue; + } + $sleep[$n] = false; + } + if (!\array_key_exists($name, $proto) || $proto[$name] !== $v || "\x00Error\x00trace" === $name || "\x00Exception\x00trace" === $name) { + $properties[$c][$n] = $v; + } + } + if ($sleep) { + foreach ($sleep as $n => $v) { + if (false !== $v) { + trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), \E_USER_NOTICE); + } + } + } + if (method_exists($class, '__unserialize')) { + $properties = $arrayValue; + } + + prepare_value: + $objectsPool[$value] = [$id = \count($objectsPool)]; + $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); + ++$objectsCount; + $objectsPool[$value] = [$id, $class, $properties, method_exists($class, '__unserialize') ? -$objectsCount : (method_exists($class, '__wakeup') ? $objectsCount : 0)]; + + $value = new Reference($id); + + handle_value: + if ($isRef) { + unset($value); // Break the hard reference created above + } elseif (!$valueIsStatic) { + $values[$k] = $value; + } + $valuesAreStatic = $valueIsStatic && $valuesAreStatic; + } + + return $values; + } + + public static function export($value, string $indent = '') + { + switch (true) { + case \is_int($value) || \is_float($value): return var_export($value, true); + case [] === $value: return '[]'; + case false === $value: return 'false'; + case true === $value: return 'true'; + case null === $value: return 'null'; + case '' === $value: return "''"; + case $value instanceof \UnitEnum: return '\\'.ltrim(var_export($value, true), '\\'); + } + + if ($value instanceof Reference) { + if (0 <= $value->id) { + return '$o['.$value->id.']'; + } + if (!$value->count) { + return self::export($value->value, $indent); + } + $value = -$value->id; + + return '&$r['.$value.']'; + } + $subIndent = $indent.' '; + + if (\is_string($value)) { + $code = sprintf("'%s'", addcslashes($value, "'\\")); + + $code = preg_replace_callback("/((?:[\\0\\r\\n]|\u{202A}|\u{202B}|\u{202D}|\u{202E}|\u{2066}|\u{2067}|\u{2068}|\u{202C}|\u{2069})++)(.)/", function ($m) use ($subIndent) { + $m[1] = sprintf('\'."%s".\'', str_replace( + ["\0", "\r", "\n", "\u{202A}", "\u{202B}", "\u{202D}", "\u{202E}", "\u{2066}", "\u{2067}", "\u{2068}", "\u{202C}", "\u{2069}", '\n\\'], + ['\0', '\r', '\n', '\u{202A}', '\u{202B}', '\u{202D}', '\u{202E}', '\u{2066}', '\u{2067}', '\u{2068}', '\u{202C}', '\u{2069}', '\n"'."\n".$subIndent.'."\\'], + $m[1] + )); + + if ("'" === $m[2]) { + return substr($m[1], 0, -2); + } + + if ('n".\'' === substr($m[1], -4)) { + return substr_replace($m[1], "\n".$subIndent.".'".$m[2], -2); + } + + return $m[1].$m[2]; + }, $code, -1, $count); + + if ($count && str_starts_with($code, "''.")) { + $code = substr($code, 3); + } + + return $code; + } + + if (\is_array($value)) { + $j = -1; + $code = ''; + foreach ($value as $k => $v) { + $code .= $subIndent; + if (!\is_int($k) || 1 !== $k - $j) { + $code .= self::export($k, $subIndent).' => '; + } + if (\is_int($k) && $k > $j) { + $j = $k; + } + $code .= self::export($v, $subIndent).",\n"; + } + + return "[\n".$code.$indent.']'; + } + + if ($value instanceof Values) { + $code = $subIndent."\$r = [],\n"; + foreach ($value->values as $k => $v) { + $code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n"; + } + + return "[\n".$code.$indent.']'; + } + + if ($value instanceof Registry) { + return self::exportRegistry($value, $indent, $subIndent); + } + + if ($value instanceof Hydrator) { + return self::exportHydrator($value, $indent, $subIndent); + } + + throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', get_debug_type($value))); + } + + private static function exportRegistry(Registry $value, string $indent, string $subIndent): string + { + $code = ''; + $serializables = []; + $seen = []; + $prototypesAccess = 0; + $factoriesAccess = 0; + $r = '\\'.Registry::class; + $j = -1; + + foreach ($value->classes as $k => $class) { + if (':' === ($class[1] ?? null)) { + $serializables[$k] = $class; + continue; + } + if (!Registry::$instantiableWithoutConstructor[$class]) { + if (is_subclass_of($class, 'Serializable') && !method_exists($class, '__unserialize')) { + $serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}'; + } else { + $serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}'; + } + if (is_subclass_of($class, 'Throwable')) { + $eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0"; + $serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4); + } + continue; + } + $code .= $subIndent.(1 !== $k - $j ? $k.' => ' : ''); + $j = $k; + $eol = ",\n"; + $c = '['.self::export($class).']'; + + if ($seen[$class] ?? false) { + if (Registry::$cloneable[$class]) { + ++$prototypesAccess; + $code .= 'clone $p'.$c; + } else { + ++$factoriesAccess; + $code .= '$f'.$c.'()'; + } + } else { + $seen[$class] = true; + if (Registry::$cloneable[$class]) { + $code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p'; + } else { + $code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f'; + $eol = '()'.$eol; + } + $code .= '('.substr($c, 1, -1).'))'; + } + $code .= $eol; + } + + if (1 === $prototypesAccess) { + $code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code); + } + if (1 === $factoriesAccess) { + $code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code); + } + if ('' !== $code) { + $code = "\n".$code.$indent; + } + + if ($serializables) { + $code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')'; + } else { + $code = '['.$code.']'; + } + + return '$o = '.$code; + } + + private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string + { + $code = ''; + foreach ($value->properties as $class => $properties) { + $code .= $subIndent.' '.self::export($class).' => '.self::export($properties, $subIndent.' ').",\n"; + } + + $code = [ + self::export($value->registry, $subIndent), + self::export($value->values, $subIndent), + '' !== $code ? "[\n".$code.$subIndent.']' : '[]', + self::export($value->value, $subIndent), + self::export($value->wakeups, $subIndent), + ]; + + return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')'; + } + + /** + * @param \ArrayIterator|\ArrayObject $value + * @param \ArrayIterator|\ArrayObject $proto + */ + private static function getArrayObjectProperties($value, $proto): array + { + $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject'; + $reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector); + + $properties = [ + $arrayValue = (array) $value, + $reflector->getMethod('getFlags')->invoke($value), + $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator', + ]; + + $reflector = $reflector->getMethod('setFlags'); + $reflector->invoke($proto, \ArrayObject::STD_PROP_LIST); + + if ($properties[1] & \ArrayObject::STD_PROP_LIST) { + $reflector->invoke($value, 0); + $properties[0] = (array) $value; + } else { + $reflector->invoke($value, \ArrayObject::STD_PROP_LIST); + $arrayValue = (array) $value; + } + $reflector->invoke($value, $properties[1]); + + if ([[], 0, 'ArrayIterator'] === $properties) { + $properties = []; + } else { + if ('ArrayIterator' === $properties[2]) { + unset($properties[2]); + } + $properties = [$reflector->class => ["\0" => $properties]]; + } + + return [$arrayValue, $properties]; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Hydrator.php b/vendor/symfony/var-exporter/Internal/Hydrator.php new file mode 100644 index 00000000..5ed6bdc9 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Hydrator.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\ClassNotFoundException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Hydrator +{ + public static $hydrators = []; + + public $registry; + public $values; + public $properties; + public $value; + public $wakeups; + + public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups) + { + $this->registry = $registry; + $this->values = $values; + $this->properties = $properties; + $this->value = $value; + $this->wakeups = $wakeups; + } + + public static function hydrate($objects, $values, $properties, $value, $wakeups) + { + foreach ($properties as $class => $vars) { + (self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects); + } + foreach ($wakeups as $k => $v) { + if (\is_array($v)) { + $objects[-$k]->__unserialize($v); + } else { + $objects[$v]->__wakeup(); + } + } + + return $value; + } + + public static function getHydrator($class) + { + switch ($class) { + case 'stdClass': + return self::$hydrators[$class] = static function ($properties, $objects) { + foreach ($properties as $name => $values) { + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + + case 'ErrorException': + return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException { + }); + + case 'TypeError': + return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error { + }); + + case 'SplObjectStorage': + return self::$hydrators[$class] = static function ($properties, $objects) { + foreach ($properties as $name => $values) { + if ("\0" === $name) { + foreach ($values as $i => $v) { + for ($j = 0; $j < \count($v); ++$j) { + $objects[$i]->attach($v[$j], $v[++$j]); + } + } + continue; + } + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } + + if (!class_exists($class) && !interface_exists($class, false) && !trait_exists($class, false)) { + throw new ClassNotFoundException($class); + } + $classReflector = new \ReflectionClass($class); + + switch ($class) { + case 'ArrayIterator': + case 'ArrayObject': + $constructor = \Closure::fromCallable([$classReflector->getConstructor(), 'invokeArgs']); + + return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) { + foreach ($properties as $name => $values) { + if ("\0" !== $name) { + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + } + foreach ($properties["\0"] ?? [] as $i => $v) { + $constructor($objects[$i], $v); + } + }; + } + + if (!$classReflector->isInternal()) { + return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class); + } + + if ($classReflector->name !== $class) { + return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name); + } + + $propertySetters = []; + foreach ($classReflector->getProperties() as $propertyReflector) { + if (!$propertyReflector->isStatic()) { + $propertyReflector->setAccessible(true); + $propertySetters[$propertyReflector->name] = \Closure::fromCallable([$propertyReflector, 'setValue']); + } + } + + if (!$propertySetters) { + return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'); + } + + return self::$hydrators[$class] = static function ($properties, $objects) use ($propertySetters) { + foreach ($properties as $name => $values) { + if ($setValue = $propertySetters[$name] ?? null) { + foreach ($values as $i => $v) { + $setValue($objects[$i], $v); + } + continue; + } + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Reference.php b/vendor/symfony/var-exporter/Internal/Reference.php new file mode 100644 index 00000000..e371c07b --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Reference.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Reference +{ + public $id; + public $value; + public $count = 0; + + public function __construct(int $id, $value = null) + { + $this->id = $id; + $this->value = $value; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Registry.php b/vendor/symfony/var-exporter/Internal/Registry.php new file mode 100644 index 00000000..24b77b9e --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Registry.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\ClassNotFoundException; +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Registry +{ + public static $reflectors = []; + public static $prototypes = []; + public static $factories = []; + public static $cloneable = []; + public static $instantiableWithoutConstructor = []; + + public $classes = []; + + public function __construct(array $classes) + { + $this->classes = $classes; + } + + public static function unserialize($objects, $serializables) + { + $unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector'); + + try { + foreach ($serializables as $k => $v) { + $objects[$k] = unserialize($v); + } + } finally { + ini_set('unserialize_callback_func', $unserializeCallback); + } + + return $objects; + } + + public static function p($class) + { + self::getClassReflector($class, true, true); + + return self::$prototypes[$class]; + } + + public static function f($class) + { + $reflector = self::$reflectors[$class] ?? self::getClassReflector($class, true, false); + + return self::$factories[$class] = \Closure::fromCallable([$reflector, 'newInstanceWithoutConstructor']); + } + + public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null) + { + if (!($isClass = class_exists($class)) && !interface_exists($class, false) && !trait_exists($class, false)) { + throw new ClassNotFoundException($class); + } + $reflector = new \ReflectionClass($class); + + if ($instantiableWithoutConstructor) { + $proto = $reflector->newInstanceWithoutConstructor(); + } elseif (!$isClass || $reflector->isAbstract()) { + throw new NotInstantiableTypeException($class); + } elseif ($reflector->name !== $class) { + $reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, false, $cloneable); + self::$cloneable[$class] = self::$cloneable[$name]; + self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name]; + self::$prototypes[$class] = self::$prototypes[$name]; + + return self::$reflectors[$class] = $reflector; + } else { + try { + $proto = $reflector->newInstanceWithoutConstructor(); + $instantiableWithoutConstructor = true; + } catch (\ReflectionException $e) { + $proto = $reflector->implementsInterface('Serializable') && !method_exists($class, '__unserialize') ? 'C:' : 'O:'; + if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) { + $proto = null; + } else { + try { + $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}'); + } catch (\Exception $e) { + if (__FILE__ !== $e->getFile()) { + throw $e; + } + throw new NotInstantiableTypeException($class, $e); + } + if (false === $proto) { + throw new NotInstantiableTypeException($class); + } + } + } + if (null !== $proto && !$proto instanceof \Throwable && !$proto instanceof \Serializable && !method_exists($class, '__sleep') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__serialize'))) { + try { + serialize($proto); + } catch (\Exception $e) { + throw new NotInstantiableTypeException($class, $e); + } + } + } + + if (null === $cloneable) { + if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !method_exists($proto, '__wakeup') && (\PHP_VERSION_ID < 70400 || !method_exists($class, '__unserialize')))) { + throw new NotInstantiableTypeException($class); + } + + $cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone'); + } + + self::$cloneable[$class] = $cloneable; + self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor; + self::$prototypes[$class] = $proto; + + if ($proto instanceof \Throwable) { + static $setTrace; + + if (null === $setTrace) { + $setTrace = [ + new \ReflectionProperty(\Error::class, 'trace'), + new \ReflectionProperty(\Exception::class, 'trace'), + ]; + $setTrace[0]->setAccessible(true); + $setTrace[1]->setAccessible(true); + $setTrace[0] = \Closure::fromCallable([$setTrace[0], 'setValue']); + $setTrace[1] = \Closure::fromCallable([$setTrace[1], 'setValue']); + } + + $setTrace[$proto instanceof \Exception]($proto, []); + } + + return self::$reflectors[$class] = $reflector; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Values.php b/vendor/symfony/var-exporter/Internal/Values.php new file mode 100644 index 00000000..21ae04e6 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Values.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter\Internal; + +/** + * @author Nicolas Grekas + * + * @internal + */ +class Values +{ + public $values; + + public function __construct(array $values) + { + $this->values = $values; + } +} diff --git a/vendor/symfony/var-exporter/LICENSE b/vendor/symfony/var-exporter/LICENSE new file mode 100644 index 00000000..7536caea --- /dev/null +++ b/vendor/symfony/var-exporter/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/symfony/var-exporter/README.md b/vendor/symfony/var-exporter/README.md new file mode 100644 index 00000000..a34e4c23 --- /dev/null +++ b/vendor/symfony/var-exporter/README.md @@ -0,0 +1,38 @@ +VarExporter Component +===================== + +The VarExporter component allows exporting any serializable PHP data structure to +plain PHP code. While doing so, it preserves all the semantics associated with +the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`, +`__serialize`, `__unserialize`). + +It also provides an instantiator that allows creating and populating objects +without calling their constructor nor any other methods. + +The reason to use this component *vs* `serialize()` or +[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to +OPcache, the resulting code is significantly faster and more memory efficient +than using `unserialize()` or `igbinary_unserialize()`. + +Unlike `var_export()`, this works on any serializable PHP value. + +It also provides a few improvements over `var_export()`/`serialize()`: + + * the output is PSR-2 compatible; + * the output can be re-indented without messing up with `\r` or `\n` in the data + * missing classes throw a `ClassNotFoundException` instead of being unserialized to + `PHP_Incomplete_Class` objects; + * references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator` + instances are preserved; + * `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes + throw an exception when being serialized (their unserialized version is broken + anyway, see https://bugs.php.net/76737). + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/var_exporter.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/var-exporter/VarExporter.php b/vendor/symfony/var-exporter/VarExporter.php new file mode 100644 index 00000000..85813378 --- /dev/null +++ b/vendor/symfony/var-exporter/VarExporter.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\VarExporter; + +use Symfony\Component\VarExporter\Exception\ExceptionInterface; +use Symfony\Component\VarExporter\Internal\Exporter; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\Registry; +use Symfony\Component\VarExporter\Internal\Values; + +/** + * Exports serializable PHP values to PHP code. + * + * VarExporter allows serializing PHP data structures to plain PHP code (like var_export()) + * while preserving all the semantics associated with serialize() (unlike var_export()). + * + * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize(). + * + * @author Nicolas Grekas + */ +final class VarExporter +{ + /** + * Exports a serializable PHP value to PHP code. + * + * @param mixed $value The value to export + * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise + * @param array &$foundClasses Classes found in the value are added to this list as both keys and values + * + * @throws ExceptionInterface When the provided value cannot be serialized + */ + public static function export($value, bool &$isStaticValue = null, array &$foundClasses = []): string + { + $isStaticValue = true; + + if (!\is_object($value) && !(\is_array($value) && $value) && !\is_resource($value) || $value instanceof \UnitEnum) { + return Exporter::export($value); + } + + $objectsPool = new \SplObjectStorage(); + $refsPool = []; + $objectsCount = 0; + + try { + $value = Exporter::prepare([$value], $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0]; + } finally { + $references = []; + foreach ($refsPool as $i => $v) { + if ($v[0]->count) { + $references[1 + $i] = $v[2]; + } + $v[0] = $v[1]; + } + } + + if ($isStaticValue) { + return Exporter::export($value); + } + + $classes = []; + $values = []; + $states = []; + foreach ($objectsPool as $i => $v) { + [, $class, $values[], $wakeup] = $objectsPool[$v]; + $foundClasses[$class] = $classes[] = $class; + + if (0 < $wakeup) { + $states[$wakeup] = $i; + } elseif (0 > $wakeup) { + $states[-$wakeup] = [$i, array_pop($values)]; + $values[] = []; + } + } + ksort($states); + + $wakeups = [null]; + foreach ($states as $k => $v) { + if (\is_array($v)) { + $wakeups[-$v[0]] = $v[1]; + } else { + $wakeups[] = $v; + } + } + + if (null === $wakeups[0]) { + unset($wakeups[0]); + } + + $properties = []; + foreach ($values as $i => $vars) { + foreach ($vars as $class => $values) { + foreach ($values as $name => $v) { + $properties[$class][$name][$i] = $v; + } + } + } + + if ($classes || $references) { + $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups); + } else { + $isStaticValue = true; + } + + return Exporter::export($value); + } +} diff --git a/vendor/symfony/var-exporter/composer.json b/vendor/symfony/var-exporter/composer.json new file mode 100644 index 00000000..29d4901d --- /dev/null +++ b/vendor/symfony/var-exporter/composer.json @@ -0,0 +1,32 @@ +{ + "name": "symfony/var-exporter", + "type": "library", + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "keywords": ["export", "serialize", "instantiate", "hydrate", "construct", "clone"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "symfony/var-dumper": "^4.4.9|^5.0.9|^6.0" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\VarExporter\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev" +}