diff options
Diffstat (limited to 'vendor')
495 files changed, 19875 insertions, 4012 deletions
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 2b89e59e2e..410fa51a6f 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir); return array( 'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', + 'JsonException' => $vendorDir . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', 'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', 'QRcode' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/qrcode.php', 'TCPDF' => $vendorDir . '/tecnickcom/tcpdf/tcpdf.php', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index c916fa927f..0f7168b6d3 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -10,6 +10,7 @@ return array( '25072dd6e2470089de65ae7bf11d3109' => $vendorDir . '/symfony/polyfill-php72/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => $vendorDir . '/symfony/polyfill-intl-idn/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => $vendorDir . '/symfony/polyfill-php73/bootstrap.php', '72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php', '7b11c4dc42b3b3023073cb14e519683c' => $vendorDir . '/ralouphie/getallheaders/src/getallheaders.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 654d714d7b..362b450ec4 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -7,14 +7,19 @@ $baseDir = dirname($vendorDir); return array( 'Webuni\\CommonMark\\TableExtension\\' => array($vendorDir . '/webuni/commonmark-table-extension/src'), + 'Symfony\\Polyfill\\Php73\\' => array($vendorDir . '/symfony/polyfill-php73'), 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Polyfill\\Intl\\Idn\\' => array($vendorDir . '/symfony/polyfill-intl-idn'), 'Symfony\\Polyfill\\Iconv\\' => array($vendorDir . '/symfony/polyfill-iconv'), 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), - 'Symfony\\Contracts\\' => array($vendorDir . '/symfony/contracts'), + 'Symfony\\Contracts\\Translation\\' => array($vendorDir . '/symfony/translation-contracts'), + 'Symfony\\Contracts\\Service\\' => array($vendorDir . '/symfony/service-contracts'), + 'Symfony\\Contracts\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher-contracts'), + 'Symfony\\Contracts\\Cache\\' => array($vendorDir . '/symfony/cache-contracts'), 'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'), 'Symfony\\Component\\Translation\\' => array($vendorDir . '/symfony/translation'), + 'Symfony\\Component\\Mime\\' => array($vendorDir . '/symfony/mime'), 'Symfony\\Component\\HttpKernel\\' => array($vendorDir . '/symfony/http-kernel'), 'Symfony\\Component\\HttpFoundation\\' => array($vendorDir . '/symfony/http-foundation'), 'Symfony\\Component\\ExpressionLanguage\\' => array($vendorDir . '/symfony/expression-language'), diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 86e1a498d1..9128376592 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -11,6 +11,7 @@ class ComposerStaticInit74b5eb00e70cef0c1fba9491b929fdd1 '25072dd6e2470089de65ae7bf11d3109' => __DIR__ . '/..' . '/symfony/polyfill-php72/bootstrap.php', 'f598d06aa772fa33d905e87be6398fb1' => __DIR__ . '/..' . '/symfony/polyfill-intl-idn/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', + '0d59ee240a4cd96ddbb4ff164fccea4d' => __DIR__ . '/..' . '/symfony/polyfill-php73/bootstrap.php', '72579e7bd17821bb1321b87411366eae' => __DIR__ . '/..' . '/illuminate/support/helpers.php', '7b11c4dc42b3b3023073cb14e519683c' => __DIR__ . '/..' . '/ralouphie/getallheaders/src/getallheaders.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', @@ -30,14 +31,19 @@ class ComposerStaticInit74b5eb00e70cef0c1fba9491b929fdd1 ), 'S' => array ( + 'Symfony\\Polyfill\\Php73\\' => 23, 'Symfony\\Polyfill\\Php72\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, 'Symfony\\Polyfill\\Intl\\Idn\\' => 26, 'Symfony\\Polyfill\\Iconv\\' => 23, 'Symfony\\Polyfill\\Ctype\\' => 23, - 'Symfony\\Contracts\\' => 18, + 'Symfony\\Contracts\\Translation\\' => 30, + 'Symfony\\Contracts\\Service\\' => 26, + 'Symfony\\Contracts\\EventDispatcher\\' => 34, + 'Symfony\\Contracts\\Cache\\' => 24, 'Symfony\\Component\\VarExporter\\' => 30, 'Symfony\\Component\\Translation\\' => 30, + 'Symfony\\Component\\Mime\\' => 23, 'Symfony\\Component\\HttpKernel\\' => 29, 'Symfony\\Component\\HttpFoundation\\' => 33, 'Symfony\\Component\\ExpressionLanguage\\' => 37, @@ -125,6 +131,10 @@ class ComposerStaticInit74b5eb00e70cef0c1fba9491b929fdd1 array ( 0 => __DIR__ . '/..' . '/webuni/commonmark-table-extension/src', ), + 'Symfony\\Polyfill\\Php73\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/polyfill-php73', + ), 'Symfony\\Polyfill\\Php72\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php72', @@ -145,9 +155,21 @@ class ComposerStaticInit74b5eb00e70cef0c1fba9491b929fdd1 array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', ), - 'Symfony\\Contracts\\' => + 'Symfony\\Contracts\\Translation\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/translation-contracts', + ), + 'Symfony\\Contracts\\Service\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/service-contracts', + ), + 'Symfony\\Contracts\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher-contracts', + ), + 'Symfony\\Contracts\\Cache\\' => array ( - 0 => __DIR__ . '/..' . '/symfony/contracts', + 0 => __DIR__ . '/..' . '/symfony/cache-contracts', ), 'Symfony\\Component\\VarExporter\\' => array ( @@ -157,6 +179,10 @@ class ComposerStaticInit74b5eb00e70cef0c1fba9491b929fdd1 array ( 0 => __DIR__ . '/..' . '/symfony/translation', ), + 'Symfony\\Component\\Mime\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/mime', + ), 'Symfony\\Component\\HttpKernel\\' => array ( 0 => __DIR__ . '/..' . '/symfony/http-kernel', @@ -352,6 +378,7 @@ class ComposerStaticInit74b5eb00e70cef0c1fba9491b929fdd1 public static $classMap = array ( 'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', + 'JsonException' => __DIR__ . '/..' . '/symfony/polyfill-php73/Resources/stubs/JsonException.php', 'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', 'QRcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/qrcode.php', 'TCPDF' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 5227224711..b43f76aa32 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -363,17 +363,17 @@ }, { "name": "egulias/email-validator", - "version": "2.1.7", - "version_normalized": "2.1.7.0", + "version": "2.1.8", + "version_normalized": "2.1.8.0", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e" + "reference": "c26463ff9241f27907112fbcd0c86fa670cfef98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/709f21f92707308cdf8f9bcfa1af4cb26586521e", - "reference": "709f21f92707308cdf8f9bcfa1af4cb26586521e", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/c26463ff9241f27907112fbcd0c86fa670cfef98", + "reference": "c26463ff9241f27907112fbcd0c86fa670cfef98", "shasum": "" }, "require": { @@ -388,7 +388,7 @@ "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" }, - "time": "2018-12-04T22:38:24+00:00", + "time": "2019-05-16T22:02:54+00:00", "type": "library", "extra": { "branch-alias": { @@ -932,17 +932,17 @@ }, { "name": "illuminate/cache", - "version": "v5.8.17", - "version_normalized": "5.8.17.0", + "version": "v5.8.19", + "version_normalized": "5.8.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/cache.git", - "reference": "f25be6bcdb77da215f9c7fd16899c213c8a58beb" + "reference": "2eb67998857161904289db33e703e1a925243731" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/cache/zipball/f25be6bcdb77da215f9c7fd16899c213c8a58beb", - "reference": "f25be6bcdb77da215f9c7fd16899c213c8a58beb", + "url": "https://api.github.com/repos/illuminate/cache/zipball/2eb67998857161904289db33e703e1a925243731", + "reference": "2eb67998857161904289db33e703e1a925243731", "shasum": "" }, "require": { @@ -955,7 +955,7 @@ "illuminate/filesystem": "Required to use the file cache driver (5.8.*).", "illuminate/redis": "Required to use the redis cache driver (5.8.*)." }, - "time": "2019-04-22T18:38:59+00:00", + "time": "2019-05-26T12:37:11+00:00", "type": "library", "extra": { "branch-alias": { @@ -983,8 +983,8 @@ }, { "name": "illuminate/container", - "version": "v5.8.17", - "version_normalized": "5.8.17.0", + "version": "v5.8.19", + "version_normalized": "5.8.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/container.git", @@ -1030,17 +1030,17 @@ }, { "name": "illuminate/contracts", - "version": "v5.8.17", - "version_normalized": "5.8.17.0", + "version": "v5.8.19", + "version_normalized": "5.8.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", - "reference": "acd524087bcebcc0979748e84ccc0876395ae497" + "reference": "8e2466437516edaa30201a8b5d4eaa56fa99eacd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/contracts/zipball/acd524087bcebcc0979748e84ccc0876395ae497", - "reference": "acd524087bcebcc0979748e84ccc0876395ae497", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/8e2466437516edaa30201a8b5d4eaa56fa99eacd", + "reference": "8e2466437516edaa30201a8b5d4eaa56fa99eacd", "shasum": "" }, "require": { @@ -1048,7 +1048,7 @@ "psr/container": "^1.0", "psr/simple-cache": "^1.0" }, - "time": "2019-05-14T10:54:47+00:00", + "time": "2019-05-15T00:29:13+00:00", "type": "library", "extra": { "branch-alias": { @@ -1076,17 +1076,17 @@ }, { "name": "illuminate/database", - "version": "v5.8.17", - "version_normalized": "5.8.17.0", + "version": "v5.8.19", + "version_normalized": "5.8.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/database.git", - "reference": "6bcfc3a0baf19406ad0bb470193c2b64eeefa510" + "reference": "44740cedfbd90c5fc9710ab572adf40ab0b4c11c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/database/zipball/6bcfc3a0baf19406ad0bb470193c2b64eeefa510", - "reference": "6bcfc3a0baf19406ad0bb470193c2b64eeefa510", + "url": "https://api.github.com/repos/illuminate/database/zipball/44740cedfbd90c5fc9710ab572adf40ab0b4c11c", + "reference": "44740cedfbd90c5fc9710ab572adf40ab0b4c11c", "shasum": "" }, "require": { @@ -1104,7 +1104,7 @@ "illuminate/filesystem": "Required to use the migrations (5.8.*).", "illuminate/pagination": "Required to paginate the result set (5.8.*)." }, - "time": "2019-05-13T15:56:41+00:00", + "time": "2019-05-27T13:28:29+00:00", "type": "library", "extra": { "branch-alias": { @@ -1138,17 +1138,17 @@ }, { "name": "illuminate/support", - "version": "v5.8.17", - "version_normalized": "5.8.17.0", + "version": "v5.8.19", + "version_normalized": "5.8.19.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "128c6aaa1599811a04fd10c2d68e1213e433da3f" + "reference": "5283f273d0bc67964cc7f6373573273de7676c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/128c6aaa1599811a04fd10c2d68e1213e433da3f", - "reference": "128c6aaa1599811a04fd10c2d68e1213e433da3f", + "url": "https://api.github.com/repos/illuminate/support/zipball/5283f273d0bc67964cc7f6373573273de7676c77", + "reference": "5283f273d0bc67964cc7f6373573273de7676c77", "shasum": "" }, "require": { @@ -1170,7 +1170,7 @@ "symfony/var-dumper": "Required to use the dd function (^4.2).", "vlucas/phpdotenv": "Required to use the env helper (^3.3)." }, - "time": "2019-05-14T13:37:34+00:00", + "time": "2019-05-27T17:33:34+00:00", "type": "library", "extra": { "branch-alias": { @@ -1344,17 +1344,17 @@ }, { "name": "league/flysystem", - "version": "1.0.51", - "version_normalized": "1.0.51.0", + "version": "1.0.52", + "version_normalized": "1.0.52.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "755ba7bf3fb9031e6581d091db84d78275874396" + "reference": "c5a5097156387970e6f0ccfcdf03f752856f3391" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/755ba7bf3fb9031e6581d091db84d78275874396", - "reference": "755ba7bf3fb9031e6581d091db84d78275874396", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c5a5097156387970e6f0ccfcdf03f752856f3391", + "reference": "c5a5097156387970e6f0ccfcdf03f752856f3391", "shasum": "" }, "require": { @@ -1384,7 +1384,7 @@ "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" }, - "time": "2019-03-30T13:22:34+00:00", + "time": "2019-05-20T20:21:14+00:00", "type": "library", "extra": { "branch-alias": { @@ -1591,17 +1591,17 @@ }, { "name": "nesbot/carbon", - "version": "2.18.0", - "version_normalized": "2.18.0.0", + "version": "2.19.0", + "version_normalized": "2.19.0.0", "source": { "type": "git", "url": "https://github.com/briannesbitt/Carbon.git", - "reference": "8322b7bd1805be31867c13bf3cdaab948a0dd406" + "reference": "c3545b39197d314205226ac3c33cb4db99aa54ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/8322b7bd1805be31867c13bf3cdaab948a0dd406", - "reference": "8322b7bd1805be31867c13bf3cdaab948a0dd406", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/c3545b39197d314205226ac3c33cb4db99aa54ab", + "reference": "c3545b39197d314205226ac3c33cb4db99aa54ab", "shasum": "" }, "require": { @@ -1617,7 +1617,7 @@ "phpunit/phpunit": "^7.5 || ^8.0", "squizlabs/php_codesniffer": "^3.4" }, - "time": "2019-05-16T18:44:35+00:00", + "time": "2019-05-30T10:15:05+00:00", "type": "library", "extra": { "laravel": { @@ -2528,25 +2528,25 @@ }, { "name": "symfony/cache", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "9e64db924324700e19ef4f21c2c279a35ff9bdff" + "reference": "f09463d1165396745fef0aae64b7a784c891be9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/9e64db924324700e19ef4f21c2c279a35ff9bdff", - "reference": "9e64db924324700e19ef4f21c2c279a35ff9bdff", + "url": "https://api.github.com/repos/symfony/cache/zipball/f09463d1165396745fef0aae64b7a784c891be9f", + "reference": "f09463d1165396745fef0aae64b7a784c891be9f", "shasum": "" }, "require": { "php": "^7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/contracts": "^1.0", + "symfony/cache-contracts": "^1.1", + "symfony/service-contracts": "^1.1", "symfony/var-exporter": "^4.2" }, "conflict": { @@ -2557,22 +2557,23 @@ "provide": { "psr/cache-implementation": "1.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-contracts-implementation": "1.0" + "symfony/cache-implementation": "1.0" }, "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "~1.6", "doctrine/dbal": "~2.5", "predis/predis": "~1.1", + "psr/simple-cache": "^1.0", "symfony/config": "~4.2", "symfony/dependency-injection": "~3.4|~4.1", "symfony/var-dumper": "^4.1.1" }, - "time": "2019-04-16T09:36:45+00:00", + "time": "2019-05-27T08:16:38+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -2606,38 +2607,28 @@ ] }, { - "name": "symfony/contracts", - "version": "v1.1.0", - "version_normalized": "1.1.0.0", + "name": "symfony/cache-contracts", + "version": "v1.1.1", + "version_normalized": "1.1.1.0", "source": { "type": "git", - "url": "https://github.com/symfony/contracts.git", - "reference": "d3636025e8253c6144358ec0a62773cae588395b" + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "7ff3902cc747dd5e2c6f26dc42603ed07b530293" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/contracts/zipball/d3636025e8253c6144358ec0a62773cae588395b", - "reference": "d3636025e8253c6144358ec0a62773cae588395b", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/7ff3902cc747dd5e2c6f26dc42603ed07b530293", + "reference": "7ff3902cc747dd5e2c6f26dc42603ed07b530293", "shasum": "" }, "require": { "php": "^7.1.3" }, - "require-dev": { - "psr/cache": "^1.0", - "psr/container": "^1.0", - "symfony/polyfill-intl-idn": "^1.10" - }, "suggest": { - "psr/cache": "When using the Cache contracts", - "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/event-dispatcher-implementation": "", - "symfony/http-client-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" + "psr/cache": "", + "symfony/cache-implementation": "" }, - "time": "2019-04-27T14:29:50+00:00", + "time": "2019-05-22T12:23:29+00:00", "type": "library", "extra": { "branch-alias": { @@ -2647,11 +2638,8 @@ "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Contracts\\": "" - }, - "exclude-from-classmap": [ - "**/Tests/" - ] + "Symfony\\Contracts\\Cache\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2667,7 +2655,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "A set of abstractions extracted out of the Symfony components", + "description": "Generic abstractions related to caching", "homepage": "https://symfony.com", "keywords": [ "abstractions", @@ -2680,17 +2668,17 @@ }, { "name": "symfony/debug", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "2d279b6bb1d582dd5740d4d3251ae8c18812ed37" + "reference": "97cde06d798f1326857090bc1b7c8f9d225c3dcb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/2d279b6bb1d582dd5740d4d3251ae8c18812ed37", - "reference": "2d279b6bb1d582dd5740d4d3251ae8c18812ed37", + "url": "https://api.github.com/repos/symfony/debug/zipball/97cde06d798f1326857090bc1b7c8f9d225c3dcb", + "reference": "97cde06d798f1326857090bc1b7c8f9d225c3dcb", "shasum": "" }, "require": { @@ -2703,11 +2691,11 @@ "require-dev": { "symfony/http-kernel": "~3.4|~4.0" }, - "time": "2019-04-11T11:27:41+00:00", + "time": "2019-05-20T16:16:12+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -2738,42 +2726,48 @@ }, { "name": "symfony/event-dispatcher", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "fbce53cd74ac509cbe74b6f227622650ab759b02" + "reference": "c71314cd3b9420b732e1526f33a24eff5430b5b3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fbce53cd74ac509cbe74b6f227622650ab759b02", - "reference": "fbce53cd74ac509cbe74b6f227622650ab759b02", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c71314cd3b9420b732e1526f33a24eff5430b5b3", + "reference": "c71314cd3b9420b732e1526f33a24eff5430b5b3", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0" + "symfony/event-dispatcher-contracts": "^1.1" }, "conflict": { "symfony/dependency-injection": "<3.4" }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, "require-dev": { "psr/log": "~1.0", "symfony/config": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", + "symfony/http-foundation": "^3.4|^4.0", + "symfony/service-contracts": "^1.1", "symfony/stopwatch": "~3.4|~4.0" }, "suggest": { "symfony/dependency-injection": "", "symfony/http-kernel": "" }, - "time": "2019-04-06T13:51:08+00:00", + "time": "2019-05-28T07:50:59+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -2803,30 +2797,90 @@ "homepage": "https://symfony.com" }, { + "name": "symfony/event-dispatcher-contracts", + "version": "v1.1.1", + "version_normalized": "1.1.1.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "8fa2cf2177083dd59cf8e44ea4b6541764fbda69" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8fa2cf2177083dd59cf8e44ea4b6541764fbda69", + "reference": "8fa2cf2177083dd59cf8e44ea4b6541764fbda69", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "psr/event-dispatcher": "", + "symfony/event-dispatcher-implementation": "" + }, + "time": "2019-05-22T12:23:29+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "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 dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ] + }, + { "name": "symfony/expression-language", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "a69b153996a13ffdb05395e8724c7217a8448e9e" + "reference": "94f1b244c3f2f5e6d360d3d63d3ef77a5fc8aa82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/a69b153996a13ffdb05395e8724c7217a8448e9e", - "reference": "a69b153996a13ffdb05395e8724c7217a8448e9e", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/94f1b244c3f2f5e6d360d3d63d3ef77a5fc8aa82", + "reference": "94f1b244c3f2f5e6d360d3d63d3ef77a5fc8aa82", "shasum": "" }, "require": { "php": "^7.1.3", "symfony/cache": "~3.4|~4.0", - "symfony/contracts": "^1.0" + "symfony/service-contracts": "^1.1" }, - "time": "2019-01-16T20:31:39+00:00", + "time": "2019-05-27T08:16:38+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -2857,32 +2911,33 @@ }, { "name": "symfony/http-foundation", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "1ea878bd3af18f934dedb8c0de60656a9a31a718" + "reference": "e8da078912bed1339f046c3a9488a5cbd0605971" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/1ea878bd3af18f934dedb8c0de60656a9a31a718", - "reference": "1ea878bd3af18f934dedb8c0de60656a9a31a718", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/e8da078912bed1339f046c3a9488a5cbd0605971", + "reference": "e8da078912bed1339f046c3a9488a5cbd0605971", "shasum": "" }, "require": { "php": "^7.1.3", + "symfony/mime": "^4.3", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { "predis/predis": "~1.0", "symfony/expression-language": "~3.4|~4.0" }, - "time": "2019-05-01T08:36:31+00:00", + "time": "2019-05-29T18:10:42+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -2913,31 +2968,32 @@ }, { "name": "symfony/http-kernel", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a7713bc522f1a1cdf0b39f809fa4542523fc3114" + "reference": "b4ce396bdce518978a17324d3d39d61058d039e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a7713bc522f1a1cdf0b39f809fa4542523fc3114", - "reference": "a7713bc522f1a1cdf0b39f809fa4542523fc3114", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/b4ce396bdce518978a17324d3d39d61058d039e6", + "reference": "b4ce396bdce518978a17324d3d39d61058d039e6", "shasum": "" }, "require": { "php": "^7.1.3", "psr/log": "~1.0", - "symfony/contracts": "^1.0.2", "symfony/debug": "~3.4|~4.0", - "symfony/event-dispatcher": "~4.1", + "symfony/event-dispatcher": "^4.3", "symfony/http-foundation": "^4.1.1", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php73": "^1.9" }, "conflict": { + "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.2", + "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" @@ -2947,11 +3003,11 @@ }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "~3.4|~4.0", + "symfony/browser-kit": "^4.3", "symfony/config": "~3.4|~4.0", "symfony/console": "~3.4|~4.0", "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.2", + "symfony/dependency-injection": "^4.3", "symfony/dom-crawler": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", @@ -2960,7 +3016,9 @@ "symfony/stopwatch": "~3.4|~4.0", "symfony/templating": "~3.4|~4.0", "symfony/translation": "~4.2", - "symfony/var-dumper": "^4.1.1" + "symfony/translation-contracts": "^1.1", + "symfony/var-dumper": "^4.1.1", + "twig/twig": "^1.34|^2.4" }, "suggest": { "symfony/browser-kit": "", @@ -2969,11 +3027,11 @@ "symfony/dependency-injection": "", "symfony/var-dumper": "" }, - "time": "2019-05-01T13:31:08+00:00", + "time": "2019-05-30T06:21:08+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -3003,6 +3061,67 @@ "homepage": "https://symfony.com" }, { + "name": "symfony/mime", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0b166aee243364cd9de05755d2e9651876090abb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0b166aee243364cd9de05755d2e9651876090abb", + "reference": "0b166aee243364cd9de05755d2e9651876090abb", + "shasum": "" + }, + "require": { + "php": "^7.1.3", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "egulias/email-validator": "^2.0", + "symfony/dependency-injection": "~3.4|^4.1" + }, + "time": "2019-05-22T13:16:28+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "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": "A library to manipulate MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ] + }, + { "name": "symfony/polyfill-ctype", "version": "v1.11.0", "version_normalized": "1.11.0.0", @@ -3306,24 +3425,144 @@ ] }, { + "name": "symfony/polyfill-php73", + "version": "v1.11.0", + "version_normalized": "1.11.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "d1fb4abcc0c47be136208ad9d68bf59f1ee17abd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/d1fb4abcc0c47be136208ad9d68bf59f1ee17abd", + "reference": "d1fb4abcc0c47be136208ad9d68bf59f1ee17abd", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "time": "2019-02-06T07:57:58+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "files": [ + "bootstrap.php" + ], + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ] + }, + { + "name": "symfony/service-contracts", + "version": "v1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "191afdcb5804db960d26d8566b7e9a2843cab3a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/191afdcb5804db960d26d8566b7e9a2843cab3a0", + "reference": "191afdcb5804db960d26d8566b7e9a2843cab3a0", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "psr/container": "", + "symfony/service-implementation": "" + }, + "time": "2019-05-28T07:50:59+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "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" + ] + }, + { "name": "symfony/translation", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "181a426dd129cb496f12d7e7555f6d0b37a7615b" + "reference": "f7e90f0f90e354f99f20aa9ead95a1b201b126f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/181a426dd129cb496f12d7e7555f6d0b37a7615b", - "reference": "181a426dd129cb496f12d7e7555f6d0b37a7615b", + "url": "https://api.github.com/repos/symfony/translation/zipball/f7e90f0f90e354f99f20aa9ead95a1b201b126f9", + "reference": "f7e90f0f90e354f99f20aa9ead95a1b201b126f9", "shasum": "" }, "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0.2", - "symfony/polyfill-mbstring": "~1.0" + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.2" }, "conflict": { "symfony/config": "<3.4", @@ -3331,7 +3570,7 @@ "symfony/yaml": "<3.4" }, "provide": { - "symfony/translation-contracts-implementation": "1.0" + "symfony/translation-implementation": "1.0" }, "require-dev": { "psr/log": "~1.0", @@ -3341,6 +3580,7 @@ "symfony/finder": "~2.8|~3.0|~4.0", "symfony/http-kernel": "~3.4|~4.0", "symfony/intl": "~3.4|~4.0", + "symfony/service-contracts": "^1.1.2", "symfony/var-dumper": "~3.4|~4.0", "symfony/yaml": "~3.4|~4.0" }, @@ -3349,11 +3589,11 @@ "symfony/config": "", "symfony/yaml": "" }, - "time": "2019-05-01T12:55:36+00:00", + "time": "2019-05-28T09:09:27+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", @@ -3383,18 +3623,77 @@ "homepage": "https://symfony.com" }, { + "name": "symfony/translation-contracts", + "version": "v1.1.2", + "version_normalized": "1.1.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "93597ce975d91c52ebfaca1253343cd9ccb7916d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/93597ce975d91c52ebfaca1253343cd9ccb7916d", + "reference": "93597ce975d91c52ebfaca1253343cd9ccb7916d", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "suggest": { + "symfony/translation-implementation": "" + }, + "time": "2019-05-27T08:16:38+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + } + }, + "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 translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ] + }, + { "name": "symfony/var-exporter", - "version": "v4.2.8", - "version_normalized": "4.2.8.0", + "version": "v4.3.0", + "version_normalized": "4.3.0.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "57e00f3e0a3deee65b67cf971455b98afeacca46" + "reference": "2b7c857d553423b2317ac0741fb2581d9bfd8fb7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/57e00f3e0a3deee65b67cf971455b98afeacca46", - "reference": "57e00f3e0a3deee65b67cf971455b98afeacca46", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/2b7c857d553423b2317ac0741fb2581d9bfd8fb7", + "reference": "2b7c857d553423b2317ac0741fb2581d9bfd8fb7", "shasum": "" }, "require": { @@ -3403,11 +3702,11 @@ "require-dev": { "symfony/var-dumper": "^4.1.1" }, - "time": "2019-04-09T20:09:28+00:00", + "time": "2019-04-10T19:42:49+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } }, "installation-source": "dist", diff --git a/vendor/egulias/email-validator/EmailValidator/EmailLexer.php b/vendor/egulias/email-validator/EmailValidator/EmailLexer.php index 882c968154..38e4714ac0 100644 --- a/vendor/egulias/email-validator/EmailValidator/EmailLexer.php +++ b/vendor/egulias/email-validator/EmailValidator/EmailLexer.php @@ -89,7 +89,7 @@ class EmailLexer extends AbstractLexer } /** - * @param $type + * @param string $type * @throws \UnexpectedValueException * @return boolean */ @@ -189,7 +189,7 @@ class EmailLexer extends AbstractLexer } /** - * @param $value + * @param string $value * @return bool */ protected function isNullType($value) @@ -202,7 +202,7 @@ class EmailLexer extends AbstractLexer } /** - * @param $value + * @param string $value * @return bool */ protected function isUTF8Invalid($value) diff --git a/vendor/egulias/email-validator/EmailValidator/EmailParser.php b/vendor/egulias/email-validator/EmailValidator/EmailParser.php index d0627d8241..5bf605ac2f 100644 --- a/vendor/egulias/email-validator/EmailValidator/EmailParser.php +++ b/vendor/egulias/email-validator/EmailValidator/EmailParser.php @@ -33,7 +33,7 @@ class EmailParser } /** - * @param $str + * @param string $str * @return array */ public function parse($str) diff --git a/vendor/egulias/email-validator/EmailValidator/EmailValidator.php b/vendor/egulias/email-validator/EmailValidator/EmailValidator.php index 44b4b93c6b..1c2770721e 100644 --- a/vendor/egulias/email-validator/EmailValidator/EmailValidator.php +++ b/vendor/egulias/email-validator/EmailValidator/EmailValidator.php @@ -28,7 +28,7 @@ class EmailValidator } /** - * @param $email + * @param string $email * @param EmailValidation $emailValidation * @return bool */ diff --git a/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php b/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php index 2502811cac..a738eeb62f 100644 --- a/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php +++ b/vendor/egulias/email-validator/EmailValidator/Exception/ExpectingQPair.php @@ -2,7 +2,7 @@ namespace Egulias\EmailValidator\Exception; -class ExpectedQPair extends InvalidEmail +class ExpectingQPair extends InvalidEmail { const CODE = 136; const REASON = "Expecting QPAIR"; diff --git a/vendor/egulias/email-validator/EmailValidator/Exception/NoDNSRecord.php b/vendor/egulias/email-validator/EmailValidator/Exception/NoDNSRecord.php index 86ca21d557..0aa5fa7890 100644 --- a/vendor/egulias/email-validator/EmailValidator/Exception/NoDNSRecord.php +++ b/vendor/egulias/email-validator/EmailValidator/Exception/NoDNSRecord.php @@ -2,8 +2,6 @@ namespace Egulias\EmailValidator\Exception; -use Egulias\EmailValidator\Exception\InvalidEmail; - class NoDNSRecord extends InvalidEmail { const CODE = 5; diff --git a/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php b/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php index e5042e1a85..fa7bd44b30 100644 --- a/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php +++ b/vendor/egulias/email-validator/EmailValidator/Parser/Parser.php @@ -8,7 +8,7 @@ use Egulias\EmailValidator\Exception\ConsecutiveDot; use Egulias\EmailValidator\Exception\CRLFAtTheEnd; use Egulias\EmailValidator\Exception\CRLFX2; use Egulias\EmailValidator\Exception\CRNoLF; -use Egulias\EmailValidator\Exception\ExpectedQPair; +use Egulias\EmailValidator\Exception\ExpectingQPair; use Egulias\EmailValidator\Exception\ExpectingATEXT; use Egulias\EmailValidator\Exception\ExpectingCTEXT; use Egulias\EmailValidator\Exception\UnclosedComment; @@ -50,7 +50,7 @@ abstract class Parser { if (!($this->lexer->token['type'] === EmailLexer::INVALID || $this->lexer->token['type'] === EmailLexer::C_DEL)) { - throw new ExpectedQPair(); + throw new ExpectingQPair(); } $this->warnings[QuotedPart::CODE] = diff --git a/vendor/egulias/email-validator/README.md b/vendor/egulias/email-validator/README.md index 008669c8b9..b5b0d85fac 100644 --- a/vendor/egulias/email-validator/README.md +++ b/vendor/egulias/email-validator/README.md @@ -1,5 +1,5 @@ # EmailValidator -[](https://travis-ci.org/egulias/EmailValidator) [](https://coveralls.io/r/egulias/EmailValidator?branch=master) [](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6) +[](https://travis-ci.org/egulias/EmailValidator) [](https://coveralls.io/r/egulias/EmailValidator?branch=master) [](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6) ============================= ## Suported RFCs ## This library aims to support: @@ -16,7 +16,7 @@ RFC 5321, 5322, 6530, 6531, 6532. Run the command below to install via Composer ```shell -composer require egulias/email-validator "~2.1" +composer require egulias/email-validator ``` ## Getting Started ## diff --git a/vendor/illuminate/cache/CacheManager.php b/vendor/illuminate/cache/CacheManager.php index ecd51eeaaa..8c72c8146e 100755 --- a/vendor/illuminate/cache/CacheManager.php +++ b/vendor/illuminate/cache/CacheManager.php @@ -229,6 +229,7 @@ class CacheManager implements FactoryContract $dynamoConfig = [ 'region' => $config['region'], 'version' => 'latest', + 'endpoint' => $config['endpoint'] ?? null, ]; if ($config['key'] && $config['secret']) { diff --git a/vendor/illuminate/cache/DynamoDbStore.php b/vendor/illuminate/cache/DynamoDbStore.php index de55d2ec15..d5c84d6af4 100644 --- a/vendor/illuminate/cache/DynamoDbStore.php +++ b/vendor/illuminate/cache/DynamoDbStore.php @@ -390,7 +390,7 @@ class DynamoDbStore implements Store, LockProvider */ public function forever($key, $value) { - return $this->put($key, $value, now()->addYears(5)); + return $this->put($key, $value, now()->addYears(5)->getTimestamp()); } /** diff --git a/vendor/illuminate/cache/FileStore.php b/vendor/illuminate/cache/FileStore.php index f48ebc2b19..228d69976e 100755 --- a/vendor/illuminate/cache/FileStore.php +++ b/vendor/illuminate/cache/FileStore.php @@ -186,7 +186,13 @@ class FileStore implements Store return $this->emptyPayload(); } - $data = unserialize(substr($contents, 10)); + try { + $data = unserialize(substr($contents, 10)); + } catch (Exception $e) { + $this->forget($key); + + return $this->emptyPayload(); + } // Next, we'll extract the number of seconds that are remaining for a cache // so that we can properly retain the time for things like the increment diff --git a/vendor/illuminate/contracts/Auth/Guard.php b/vendor/illuminate/contracts/Auth/Guard.php index 2a2ed3d9a5..2a27fb5f50 100644 --- a/vendor/illuminate/contracts/Auth/Guard.php +++ b/vendor/illuminate/contracts/Auth/Guard.php @@ -28,7 +28,7 @@ interface Guard /** * Get the ID for the currently authenticated user. * - * @return int|null + * @return int|string|null */ public function id(); diff --git a/vendor/illuminate/database/ConfigurationUrlParser.php b/vendor/illuminate/database/ConfigurationUrlParser.php index 2b2430c113..bc7c624a28 100644 --- a/vendor/illuminate/database/ConfigurationUrlParser.php +++ b/vendor/illuminate/database/ConfigurationUrlParser.php @@ -2,189 +2,9 @@ namespace Illuminate\Database; -use Illuminate\Support\Arr; -use InvalidArgumentException; +use Illuminate\Support\ConfigurationUrlParser as BaseConfigurationUrlParser; -class ConfigurationUrlParser +class ConfigurationUrlParser extends BaseConfigurationUrlParser { - /** - * The drivers aliases map. - * - * @var array - */ - protected static $driverAliases = [ - 'mssql' => 'sqlsrv', - 'mysql2' => 'mysql', // RDS - 'postgres' => 'pgsql', - 'postgresql' => 'pgsql', - 'sqlite3' => 'sqlite', - ]; - - /** - * Parse the database configuration, hydrating options using a database configuration URL if possible. - * - * @param array|string $config - * @return array - */ - public function parseConfiguration($config) - { - if (is_string($config)) { - $config = ['url' => $config]; - } - - $url = $config['url'] ?? null; - - $config = Arr::except($config, 'url'); - - if (! $url) { - return $config; - } - - $parsedUrl = $this->parseUrl($url); - - return array_merge( - $config, - $this->getPrimaryOptions($parsedUrl), - $this->getQueryOptions($parsedUrl) - ); - } - - /** - * Get the primary database connection options. - * - * @param array $url - * @return array - */ - protected function getPrimaryOptions($url) - { - return array_filter([ - 'driver' => $this->getDriver($url), - 'database' => $this->getDatabase($url), - 'host' => $url['host'] ?? null, - 'port' => $url['port'] ?? null, - 'username' => $url['user'] ?? null, - 'password' => $url['pass'] ?? null, - ], function ($value) { - return ! is_null($value); - }); - } - - /** - * Get the database driver from the URL. - * - * @param array $url - * @return string|null - */ - protected function getDriver($url) - { - $alias = $url['scheme'] ?? null; - - if (! $alias) { - return; - } - - return static::$driverAliases[$alias] ?? $alias; - } - - /** - * Get the database name from the URL. - * - * @param array $url - * @return string|null - */ - protected function getDatabase($url) - { - $path = $url['path'] ?? null; - - return $path ? substr($path, 1) : null; - } - - /** - * Get all of the additional database options from the query string. - * - * @param array $url - * @return array - */ - protected function getQueryOptions($url) - { - $queryString = $url['query'] ?? null; - - if (! $queryString) { - return []; - } - - $query = []; - - parse_str($queryString, $query); - - return $this->parseStringsToNativeTypes($query); - } - - /** - * Parse the string URL to an array of components. - * - * @param string $url - * @return array - */ - protected function parseUrl($url) - { - $url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url); - - $parsedUrl = parse_url($url); - - if ($parsedUrl === false) { - throw new InvalidArgumentException('The database configuration URL is malformed.'); - } - - return $this->parseStringsToNativeTypes( - array_map('rawurldecode', $parsedUrl) - ); - } - - /** - * Convert string casted values to their native types. - * - * @param mixed $value - * @return mixed - */ - protected function parseStringsToNativeTypes($value) - { - if (is_array($value)) { - return array_map([$this, 'parseStringsToNativeTypes'], $value); - } - - if (! is_string($value)) { - return $value; - } - - $parsedValue = json_decode($value, true); - - if (json_last_error() === JSON_ERROR_NONE) { - return $parsedValue; - } - - return $value; - } - - /** - * Get all of the current drivers aliases. - * - * @return array - */ - public static function getDriverAliases() - { - return static::$driverAliases; - } - - /** - * Add the given driver alias to the driver aliases array. - * - * @param string $alias - * @param string $driver - * @return void - */ - public static function addDriverAlias($alias, $driver) - { - static::$driverAliases[$alias] = $driver; - } + // } diff --git a/vendor/illuminate/database/DatabaseManager.php b/vendor/illuminate/database/DatabaseManager.php index 05d8cf0d45..a5993066eb 100755 --- a/vendor/illuminate/database/DatabaseManager.php +++ b/vendor/illuminate/database/DatabaseManager.php @@ -6,6 +6,7 @@ use PDO; use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; +use Illuminate\Support\ConfigurationUrlParser; use Illuminate\Database\Connectors\ConnectionFactory; /** diff --git a/vendor/illuminate/database/Eloquent/Builder.php b/vendor/illuminate/database/Eloquent/Builder.php index e827f4cc31..b4825a489a 100755 --- a/vendor/illuminate/database/Eloquent/Builder.php +++ b/vendor/illuminate/database/Eloquent/Builder.php @@ -870,7 +870,11 @@ class Builder $values ); - $values[$this->qualifyColumn($column)] = $values[$column]; + $segments = preg_split('/\s+as\s+/i', $this->query->from); + + $qualifiedColumn = end($segments).'.'.$column; + + $values[$qualifiedColumn] = $values[$column]; unset($values[$column]); diff --git a/vendor/illuminate/database/Query/Builder.php b/vendor/illuminate/database/Query/Builder.php index 3311c1ad6e..670ea25d5f 100755 --- a/vendor/illuminate/database/Query/Builder.php +++ b/vendor/illuminate/database/Query/Builder.php @@ -2078,7 +2078,7 @@ class Builder /** * Execute a query for a single record by ID. * - * @param int $id + * @param int|string $id * @param array $columns * @return mixed|static */ diff --git a/vendor/illuminate/support/Arr.php b/vendor/illuminate/support/Arr.php index 0f0b6fcf8e..31824b60c9 100755 --- a/vendor/illuminate/support/Arr.php +++ b/vendor/illuminate/support/Arr.php @@ -213,10 +213,14 @@ class Arr if (! is_array($item)) { $result[] = $item; - } elseif ($depth === 1) { - $result = array_merge($result, array_values($item)); } else { - $result = array_merge($result, static::flatten($item, $depth - 1)); + $values = $depth === 1 + ? array_values($item) + : static::flatten($item, $depth - 1); + + foreach ($values as $value) { + $result[] = $value; + } } } diff --git a/vendor/illuminate/support/ConfigurationUrlParser.php b/vendor/illuminate/support/ConfigurationUrlParser.php new file mode 100644 index 0000000000..308ff8f890 --- /dev/null +++ b/vendor/illuminate/support/ConfigurationUrlParser.php @@ -0,0 +1,189 @@ +<?php + +namespace Illuminate\Support; + +use InvalidArgumentException; + +class ConfigurationUrlParser +{ + /** + * The drivers aliases map. + * + * @var array + */ + protected static $driverAliases = [ + 'mssql' => 'sqlsrv', + 'mysql2' => 'mysql', // RDS + 'postgres' => 'pgsql', + 'postgresql' => 'pgsql', + 'sqlite3' => 'sqlite', + ]; + + /** + * Parse the database configuration, hydrating options using a database configuration URL if possible. + * + * @param array|string $config + * @return array + */ + public function parseConfiguration($config) + { + if (is_string($config)) { + $config = ['url' => $config]; + } + + $url = $config['url'] ?? null; + + $config = Arr::except($config, 'url'); + + if (! $url) { + return $config; + } + + $parsedUrl = $this->parseUrl($url); + + return array_merge( + $config, + $this->getPrimaryOptions($parsedUrl), + $this->getQueryOptions($parsedUrl) + ); + } + + /** + * Get the primary database connection options. + * + * @param array $url + * @return array + */ + protected function getPrimaryOptions($url) + { + return array_filter([ + 'driver' => $this->getDriver($url), + 'database' => $this->getDatabase($url), + 'host' => $url['host'] ?? null, + 'port' => $url['port'] ?? null, + 'username' => $url['user'] ?? null, + 'password' => $url['pass'] ?? null, + ], function ($value) { + return ! is_null($value); + }); + } + + /** + * Get the database driver from the URL. + * + * @param array $url + * @return string|null + */ + protected function getDriver($url) + { + $alias = $url['scheme'] ?? null; + + if (! $alias) { + return; + } + + return static::$driverAliases[$alias] ?? $alias; + } + + /** + * Get the database name from the URL. + * + * @param array $url + * @return string|null + */ + protected function getDatabase($url) + { + $path = $url['path'] ?? null; + + return $path ? substr($path, 1) : null; + } + + /** + * Get all of the additional database options from the query string. + * + * @param array $url + * @return array + */ + protected function getQueryOptions($url) + { + $queryString = $url['query'] ?? null; + + if (! $queryString) { + return []; + } + + $query = []; + + parse_str($queryString, $query); + + return $this->parseStringsToNativeTypes($query); + } + + /** + * Parse the string URL to an array of components. + * + * @param string $url + * @return array + */ + protected function parseUrl($url) + { + $url = preg_replace('#^(sqlite3?):///#', '$1://null/', $url); + + $parsedUrl = parse_url($url); + + if ($parsedUrl === false) { + throw new InvalidArgumentException('The database configuration URL is malformed.'); + } + + return $this->parseStringsToNativeTypes( + array_map('rawurldecode', $parsedUrl) + ); + } + + /** + * Convert string casted values to their native types. + * + * @param mixed $value + * @return mixed + */ + protected function parseStringsToNativeTypes($value) + { + if (is_array($value)) { + return array_map([$this, 'parseStringsToNativeTypes'], $value); + } + + if (! is_string($value)) { + return $value; + } + + $parsedValue = json_decode($value, true); + + if (json_last_error() === JSON_ERROR_NONE) { + return $parsedValue; + } + + return $value; + } + + /** + * Get all of the current drivers aliases. + * + * @return array + */ + public static function getDriverAliases() + { + return static::$driverAliases; + } + + /** + * Add the given driver alias to the driver aliases array. + * + * @param string $alias + * @param string $driver + * @return void + */ + public static function addDriverAlias($alias, $driver) + { + static::$driverAliases[$alias] = $driver; + } +} diff --git a/vendor/illuminate/support/Facades/Response.php b/vendor/illuminate/support/Facades/Response.php index 11161c2737..ab8576b18b 100755 --- a/vendor/illuminate/support/Facades/Response.php +++ b/vendor/illuminate/support/Facades/Response.php @@ -6,12 +6,14 @@ use Illuminate\Contracts\Routing\ResponseFactory as ResponseFactoryContract; /** * @method static \Illuminate\Http\Response make(string $content = '', int $status = 200, array $headers = []) + * @method static \Illuminate\Http\Response noContent($status = 204, array $headers = []) * @method static \Illuminate\Http\Response view(string $view, array $data = [], int $status = 200, array $headers = []) * @method static \Illuminate\Http\JsonResponse json(string|array $data = [], int $status = 200, array $headers = [], int $options = 0) * @method static \Illuminate\Http\JsonResponse jsonp(string $callback, string|array $data = [], int $status = 200, array $headers = [], int $options = 0) * @method static \Symfony\Component\HttpFoundation\StreamedResponse stream(\Closure $callback, int $status = 200, array $headers = []) * @method static \Symfony\Component\HttpFoundation\StreamedResponse streamDownload(\Closure $callback, string|null $name = null, array $headers = [], string|null $disposition = 'attachment') * @method static \Symfony\Component\HttpFoundation\BinaryFileResponse download(\SplFileInfo|string $file, string|null $name = null, array $headers = [], string|null $disposition = 'attachment') + * @method static \Symfony\Component\HttpFoundation\BinaryFileResponse file($file, array $headers = []) * @method static \Illuminate\Http\RedirectResponse redirectTo(string $path, int $status = 302, array $headers = [], bool|null $secure = null) * @method static \Illuminate\Http\RedirectResponse redirectToRoute(string $route, array $parameters = [], int $status = 302, array $headers = []) * @method static \Illuminate\Http\RedirectResponse redirectToAction(string $action, array $parameters = [], int $status = 302, array $headers = []) diff --git a/vendor/illuminate/support/Facades/URL.php b/vendor/illuminate/support/Facades/URL.php index 2dd66e7d79..baa2356966 100755 --- a/vendor/illuminate/support/Facades/URL.php +++ b/vendor/illuminate/support/Facades/URL.php @@ -12,9 +12,9 @@ namespace Illuminate\Support\Facades; * @method static string route(string $name, $parameters = [], bool $absolute = true) * @method static string action(string $action, $parameters = [], bool $absolute = true) * @method static \Illuminate\Contracts\Routing\UrlGenerator setRootControllerNamespace(string $rootNamespace) - * @method static string signedRoute(string $name, array $parameters = [], \DateTimeInterface|\DateInterval|int $expiration = null) - * @method static string temporarySignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = []) - * @method static string hasValidSignature(\Illuminate\Http\Request $request, bool $absolute) + * @method static string signedRoute(string $name, array $parameters = [], \DateTimeInterface|\DateInterval|int $expiration = null, bool $absolute = true) + * @method static string temporarySignedRoute(string $name, \DateTimeInterface|\DateInterval|int $expiration, array $parameters = [], bool $absolute = true) + * @method static string hasValidSignature(\Illuminate\Http\Request $request, bool $absolute = true) * @method static void defaults(array $defaults) * * @see \Illuminate\Routing\UrlGenerator diff --git a/vendor/illuminate/support/Testing/Fakes/BusFake.php b/vendor/illuminate/support/Testing/Fakes/BusFake.php index b42491e4c0..4cd6deb26e 100644 --- a/vendor/illuminate/support/Testing/Fakes/BusFake.php +++ b/vendor/illuminate/support/Testing/Fakes/BusFake.php @@ -127,7 +127,7 @@ class BusFake implements Dispatcher */ public function pipeThrough(array $pipes) { - // + return $this; } /** diff --git a/vendor/illuminate/support/Testing/Fakes/MailFake.php b/vendor/illuminate/support/Testing/Fakes/MailFake.php index e0a886f01e..b93c0d2460 100644 --- a/vendor/illuminate/support/Testing/Fakes/MailFake.php +++ b/vendor/illuminate/support/Testing/Fakes/MailFake.php @@ -331,6 +331,6 @@ class MailFake implements Mailer, MailQueue */ public function failures() { - // + return []; } } diff --git a/vendor/league/flysystem/src/Adapter/Local.php b/vendor/league/flysystem/src/Adapter/Local.php index eea8cb6e70..8e61e658ab 100644 --- a/vendor/league/flysystem/src/Adapter/Local.php +++ b/vendor/league/flysystem/src/Adapter/Local.php @@ -220,7 +220,7 @@ class Local extends AbstractAdapter public function read($path) { $location = $this->applyPathPrefix($path); - $contents = file_get_contents($location); + $contents = @file_get_contents($location); if ($contents === false) { return false; diff --git a/vendor/league/flysystem/src/Util/MimeType.php b/vendor/league/flysystem/src/Util/MimeType.php index 254bc2a141..adc0aa8843 100644 --- a/vendor/league/flysystem/src/Util/MimeType.php +++ b/vendor/league/flysystem/src/Util/MimeType.php @@ -13,7 +13,7 @@ class MimeType protected static $extensionToMimeTypeMap = [ 'hqx' => 'application/mac-binhex40', 'cpt' => 'application/mac-compactpro', - 'csv' => 'text/x-comma-separated-values', + 'csv' => 'text/csv', 'bin' => 'application/octet-stream', 'dms' => 'application/octet-stream', 'lha' => 'application/octet-stream', diff --git a/vendor/nesbot/carbon/contributing.md b/vendor/nesbot/carbon/contributing.md index 1cc26c5f91..d2bedac5ae 100644 --- a/vendor/nesbot/carbon/contributing.md +++ b/vendor/nesbot/carbon/contributing.md @@ -14,6 +14,18 @@ clear as a code chunk with the output you expect from it (for either bug report ## Code Contributions +### Where to begin + +We use the label **good first issue** to tag issues that could be a good fit for new contributors, see if there are such issues now following this link: + +https://github.com/briannesbitt/Carbon/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22 + +Else, check the roadmap to see what we plan to do in next releases: + +https://github.com/briannesbitt/Carbon/issues/1681 + +### Develop locally, then submit changes + Fork the [GitHub project](https://github.com/briannesbitt/Carbon) and download it locally: ```shell diff --git a/vendor/nesbot/carbon/src/Carbon/Carbon.php b/vendor/nesbot/carbon/src/Carbon/Carbon.php index eb03de5357..b950fe9340 100644 --- a/vendor/nesbot/carbon/src/Carbon/Carbon.php +++ b/vendor/nesbot/carbon/src/Carbon/Carbon.php @@ -30,8 +30,8 @@ use DateTime; * @property int $timestamp seconds since the Unix Epoch * @property string $englishDayOfWeek the day of week in English * @property string $shortEnglishDayOfWeek the abbreviated day of week in English - * @property string $englishMonth the day of week in English - * @property string $shortEnglishMonth the abbreviated day of week in English + * @property string $englishMonth the month in English + * @property string $shortEnglishMonth the abbreviated month in English * @property string $localeDayOfWeek the day of week in current locale LC_TIME * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale LC_TIME * @property string $localeMonth the month in current locale LC_TIME diff --git a/vendor/nesbot/carbon/src/Carbon/CarbonImmutable.php b/vendor/nesbot/carbon/src/Carbon/CarbonImmutable.php index 6ca85f73c5..93c7a099d8 100644 --- a/vendor/nesbot/carbon/src/Carbon/CarbonImmutable.php +++ b/vendor/nesbot/carbon/src/Carbon/CarbonImmutable.php @@ -30,8 +30,8 @@ use DateTimeImmutable; * @property int $timestamp seconds since the Unix Epoch * @property string $englishDayOfWeek the day of week in English * @property string $shortEnglishDayOfWeek the abbreviated day of week in English - * @property string $englishMonth the day of week in English - * @property string $shortEnglishMonth the abbreviated day of week in English + * @property string $englishMonth the month in English + * @property string $shortEnglishMonth the abbreviated month in English * @property string $localeDayOfWeek the day of week in current locale LC_TIME * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale LC_TIME * @property string $localeMonth the month in current locale LC_TIME diff --git a/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php b/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php index aba318edf0..42acb4f66f 100644 --- a/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php +++ b/vendor/nesbot/carbon/src/Carbon/CarbonInterface.php @@ -35,8 +35,8 @@ use ReflectionException; * @property int $timestamp seconds since the Unix Epoch * @property string $englishDayOfWeek the day of week in English * @property string $shortEnglishDayOfWeek the abbreviated day of week in English - * @property string $englishMonth the day of week in English - * @property string $shortEnglishMonth the abbreviated day of week in English + * @property string $englishMonth the month in English + * @property string $shortEnglishMonth the abbreviated month in English * @property string $localeDayOfWeek the day of week in current locale LC_TIME * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale LC_TIME * @property string $localeMonth the month in current locale LC_TIME diff --git a/vendor/nesbot/carbon/src/Carbon/Lang/ca.php b/vendor/nesbot/carbon/src/Carbon/Lang/ca.php index b51b571d09..05545f9d0d 100644 --- a/vendor/nesbot/carbon/src/Carbon/Lang/ca.php +++ b/vendor/nesbot/carbon/src/Carbon/Lang/ca.php @@ -19,29 +19,30 @@ * - Quentí * - Víctor Díaz * - Xavi + * - qcardona */ return [ 'year' => ':count any|:count anys', 'a_year' => 'un any|:count anys', - 'y' => ':count a.', + 'y' => ':count any|:count anys', 'month' => ':count mes|:count mesos', 'a_month' => 'un mes|:count mesos', - 'm' => ':count me.', + 'm' => ':count mes|:count mesos', 'week' => ':count setmana|:count setmanes', 'a_week' => 'una setmana|:count setmanes', - 'w' => ':count st.', + 'w' => ':count setmana|:count setmanes', 'day' => ':count dia|:count dies', 'a_day' => 'un dia|:count dies', - 'd' => ':count d.', + 'd' => ':count d', 'hour' => ':count hora|:count hores', 'a_hour' => 'una hora|:count hores', - 'h' => ':count h.', + 'h' => ':count h', 'minute' => ':count minut|:count minuts', 'a_minute' => 'un minut|:count minuts', - 'min' => ':count mi.', + 'min' => ':count min', 'second' => ':count segon|:count segons', 'a_second' => 'uns segons|:count segons', - 's' => ':count sg.', + 's' => ':count s', 'ago' => 'fa :time', 'from_now' => 'd\'aquí :time', 'after' => ':time després', diff --git a/vendor/nesbot/carbon/src/Carbon/Lang/fi.php b/vendor/nesbot/carbon/src/Carbon/Lang/fi.php index f3da5808d4..26f089fdfc 100644 --- a/vendor/nesbot/carbon/src/Carbon/Lang/fi.php +++ b/vendor/nesbot/carbon/src/Carbon/Lang/fi.php @@ -33,22 +33,23 @@ * - Petri Kivikangas * - Nizar Jouini * - Marko Seppae + * - Tomi Mynttinen (Pikseli) */ return [ 'year' => ':count vuosi|:count vuotta', - 'y' => ':count vuosi|:count vuotta', + 'y' => ':count v', 'month' => ':count kuukausi|:count kuukautta', - 'm' => ':count kuukausi|:count kuukautta', + 'm' => ':count kk', 'week' => ':count viikko|:count viikkoa', - 'w' => ':count viikko|:count viikkoa', + 'w' => ':count vk', 'day' => ':count päivä|:count päivää', - 'd' => ':count päivä|:count päivää', + 'd' => ':count pv', 'hour' => ':count tunti|:count tuntia', - 'h' => ':count tunti|:count tuntia', + 'h' => ':count t', 'minute' => ':count minuutti|:count minuuttia', - 'min' => ':count minuutti|:count minuuttia', + 'min' => ':count min', 'second' => ':count sekunti|:count sekuntia', - 's' => ':count sekunti|:count sekuntia', + 's' => ':count s', 'ago' => ':time sitten', 'from_now' => ':time tästä hetkestä', 'after' => ':time sen jälkeen', diff --git a/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php b/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php index ef3ea6ae46..a50c19190b 100644 --- a/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php +++ b/vendor/nesbot/carbon/src/Carbon/Lang/sr_Latn_ME.php @@ -15,8 +15,13 @@ * - Milos Sakovic */ return array_replace_recursive(require __DIR__.'/sr.php', [ + 'month' => ':count mjesec|:count mjeseca|:count mjeseci', + 'week' => ':count nedjelja|:count nedjelje|:count nedjelja', + 'second' => ':count sekund|:count sekunde|:count sekundi', 'ago' => 'prije :time', 'from_now' => 'za :time', 'after' => ':time nakon', 'before' => ':time prije', + 'week_from_now' => ':count nedjelju|:count nedjelje|:count nedjelja', + 'week_ago' => ':count nedjelju|:count nedjelje|:count nedjelja', ]); diff --git a/vendor/nesbot/carbon/src/Carbon/Lang/zgh.php b/vendor/nesbot/carbon/src/Carbon/Lang/zgh.php index 472fd93920..a65ebbde29 100644 --- a/vendor/nesbot/carbon/src/Carbon/Lang/zgh.php +++ b/vendor/nesbot/carbon/src/Carbon/Lang/zgh.php @@ -15,8 +15,8 @@ */ return [ 'year' => ':count ⵓⵙⴳⴳⵯⴰⵙ|:count ⵉⵙⴳⴳⵓⵙⴰ', - 'a_year' => 'un an|:count ⵉⵙⴳⴳⵓⵙⴰ', - 'y' => ':count an|:count ⵉⵙⴳⴳⵓⵙⴰ', + 'a_year' => 'ⵓⵙⴳⴳⵯⴰⵙ|:count ⵉⵙⴳⴳⵓⵙⴰ', + 'y' => ':count ⵓⵙⴳⴳⵯⴰⵙ|:count ⵉⵙⴳⴳⵓⵙⴰ', 'month' => ':count ⵡⴰⵢⵢⵓⵔ|:count ⴰⵢⵢⵓⵔⵏ', 'a_month' => 'ⵉⴷⵊ ⵡⴰⵢⵢⵓⵔ|:count ⴰⵢⵢⵓⵔⵏ', 'm' => ':count ⴰⵢⵢⵓⵔⵏ', diff --git a/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php b/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php index 610671c6b7..c91b8647d4 100644 --- a/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php +++ b/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php @@ -250,6 +250,13 @@ trait Creator return static::create(1, 1, 1, 0, 0, 0); } + private static function assertBetween($unit, $value, $min, $max) + { + if (static::isStrictModeEnabled() && ($value < $min || $value > $max)) { + throw new InvalidArgumentException("$unit must be between $min and $max, $value given"); + } + } + /** * Create a new Carbon instance from a specific date and time. * @@ -305,6 +312,12 @@ trait Creator $minute = $minute === null ? $getDefault('minute') : $minute; $second = (float) ($second === null ? $getDefault('second') : $second); + self::assertBetween('month', $month, 0, 99); + self::assertBetween('day', $day, 0, 99); + self::assertBetween('hour', $hour, 0, 99); + self::assertBetween('minute', $minute, 0, 99); + self::assertBetween('second', $second, 0, 99); + $fixYear = null; if ($year < 0) { diff --git a/vendor/nesbot/carbon/src/Carbon/Traits/Date.php b/vendor/nesbot/carbon/src/Carbon/Traits/Date.php index 3bb15d408f..a47b9aab9c 100644 --- a/vendor/nesbot/carbon/src/Carbon/Traits/Date.php +++ b/vendor/nesbot/carbon/src/Carbon/Traits/Date.php @@ -36,8 +36,8 @@ use ReflectionException; * @property int $timestamp seconds since the Unix Epoch * @property string $englishDayOfWeek the day of week in English * @property string $shortEnglishDayOfWeek the abbreviated day of week in English - * @property string $englishMonth the day of week in English - * @property string $shortEnglishMonth the abbreviated day of week in English + * @property string $englishMonth the month in English + * @property string $shortEnglishMonth the abbreviated month in English * @property string $localeDayOfWeek the day of week in current locale LC_TIME * @property string $shortLocaleDayOfWeek the abbreviated day of week in current locale LC_TIME * @property string $localeMonth the month in current locale LC_TIME @@ -796,9 +796,9 @@ trait Date 'englishDayOfWeek' => 'l', // @property string the abbreviated day of week in English 'shortEnglishDayOfWeek' => 'D', - // @property string the day of week in English + // @property string the month in English 'englishMonth' => 'F', - // @property string the abbreviated day of week in English + // @property string the abbreviated month in English 'shortEnglishMonth' => 'M', // @property string the day of week in current locale LC_TIME 'localeDayOfWeek' => '%A', diff --git a/vendor/symfony/contracts/Cache/CacheInterface.php b/vendor/symfony/cache-contracts/CacheInterface.php index 4b1686b873..4b1686b873 100644 --- a/vendor/symfony/contracts/Cache/CacheInterface.php +++ b/vendor/symfony/cache-contracts/CacheInterface.php diff --git a/vendor/symfony/contracts/Cache/CacheTrait.php b/vendor/symfony/cache-contracts/CacheTrait.php index 7bbdef087e..7bbdef087e 100644 --- a/vendor/symfony/contracts/Cache/CacheTrait.php +++ b/vendor/symfony/cache-contracts/CacheTrait.php diff --git a/vendor/symfony/contracts/Cache/CallbackInterface.php b/vendor/symfony/cache-contracts/CallbackInterface.php index 7dae2aac37..7dae2aac37 100644 --- a/vendor/symfony/contracts/Cache/CallbackInterface.php +++ b/vendor/symfony/cache-contracts/CallbackInterface.php diff --git a/vendor/symfony/contracts/Cache/ItemInterface.php b/vendor/symfony/cache-contracts/ItemInterface.php index 4884a2fffe..4884a2fffe 100644 --- a/vendor/symfony/contracts/Cache/ItemInterface.php +++ b/vendor/symfony/cache-contracts/ItemInterface.php diff --git a/vendor/symfony/contracts/LICENSE b/vendor/symfony/cache-contracts/LICENSE index 3f853aaf35..3f853aaf35 100644 --- a/vendor/symfony/contracts/LICENSE +++ b/vendor/symfony/cache-contracts/LICENSE diff --git a/vendor/symfony/cache-contracts/README.md b/vendor/symfony/cache-contracts/README.md new file mode 100644 index 0000000000..58c589e9ea --- /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/master/README.md for more information. diff --git a/vendor/symfony/contracts/Cache/TagAwareCacheInterface.php b/vendor/symfony/cache-contracts/TagAwareCacheInterface.php index 7c4cf11116..7c4cf11116 100644 --- a/vendor/symfony/contracts/Cache/TagAwareCacheInterface.php +++ b/vendor/symfony/cache-contracts/TagAwareCacheInterface.php diff --git a/vendor/symfony/cache-contracts/composer.json b/vendor/symfony/cache-contracts/composer.json new file mode 100644 index 0000000000..d5d7e99b9f --- /dev/null +++ b/vendor/symfony/cache-contracts/composer.json @@ -0,0 +1,34 @@ +{ + "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.1.3" + }, + "suggest": { + "psr/cache": "", + "symfony/cache-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Cache\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + } +} diff --git a/vendor/symfony/cache/Adapter/AbstractAdapter.php b/vendor/symfony/cache/Adapter/AbstractAdapter.php index 6897fbceee..883a94ba9b 100644 --- a/vendor/symfony/cache/Adapter/AbstractAdapter.php +++ b/vendor/symfony/cache/Adapter/AbstractAdapter.php @@ -11,14 +11,13 @@ namespace Symfony\Component\Cache\Adapter; -use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerAwareInterface; use Psr\Log\LoggerInterface; use Psr\Log\NullLogger; 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; @@ -27,15 +26,12 @@ use Symfony\Contracts\Cache\CacheInterface; */ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { - use AbstractTrait; + use AbstractAdapterTrait; use ContractsTrait; private static $apcuSupported; private static $phpFilesSupported; - private $createCacheItem; - private $mergeByLifetime; - protected function __construct(string $namespace = '', int $defaultLifetime = 0) { $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; @@ -132,7 +128,7 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg 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 (0 === strpos($dsn, 'redis:') || 0 === strpos($dsn, 'rediss:')) { return RedisAdapter::createConnection($dsn, $options); } if (0 === strpos($dsn, 'memcached:')) { @@ -145,81 +141,6 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg /** * {@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} - */ public function commit() { $ok = true; @@ -243,7 +164,8 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg $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) { @@ -265,39 +187,11 @@ abstract class AbstractAdapter implements AdapterInterface, CacheInterface, Logg } $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 __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 0000000000..2eb5ce8c6e --- /dev/null +++ b/vendor/symfony/cache/Adapter/AbstractTagAwareAdapter.php @@ -0,0 +1,305 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @internal + * @experimental in 4.3 + */ +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) use ($defaultLifetime) { + $item = new CacheItem(); + $item->key = $key; + $item->defaultLifetime = $defaultLifetime; + $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) { + $byLifetime = []; + $now = microtime(true); + $expiredIds = []; + + foreach ($deferred as $key => $item) { + $key = (string) $key; + if (null === $item->expiry) { + $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0; + } elseif (0 >= $ttl = (int) ($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) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::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; + } + + 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 + * @param array $tagData Optional array of tag identifiers => key 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, 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; + + /** + * {@inheritdoc} + */ + public function commit() + { + $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(). + $this->doDelete($expiredIds); + } + 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} + * + * Overloaded in order to deal with tags for adjusted doDelete() signature. + */ + public function deleteItems(array $keys) + { + if (!$keys) { + return true; + } + + $ids = []; + $tagData = []; + + foreach ($keys as $key) { + $ids[$key] = $this->getId($key); + unset($this->deferred[$key]); + } + + foreach ($this->doFetch($ids) as $id => $value) { + foreach ($value['tags'] ?? [] as $tag) { + $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id; + } + } + + try { + if ($this->doDelete(\array_values($ids), $tagData)) { + return true; + } + } catch (\Exception $e) { + } + + $ok = true; + + // 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); + } + + if ($this->doInvalidate($tagIds)) { + return true; + } + + 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/FilesystemTagAwareAdapter.php b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php new file mode 100644 index 0000000000..f96c670ae9 --- /dev/null +++ b/vendor/symfony/cache/Adapter/FilesystemTagAwareAdapter.php @@ -0,0 +1,149 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\Exception\LogicException; +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\Component\Filesystem\Filesystem; + +/** + * Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @experimental in 4.3 + */ +class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface +{ + use FilesystemTrait { + doSave as doSaveCache; + doDelete as doDeleteCache; + } + + /** + * Folder used for tag symlinks. + */ + private const TAG_FOLDER = 'tags'; + + /** + * @var Filesystem|null + */ + private $fs; + + 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); + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $removeTagData = []): array + { + $failed = $this->doSaveCache($values, $lifetime); + + $fs = $this->getFilesystem(); + // 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); + $fs->symlink($file, $this->getFile($id, true, $tagFolder)); + } + } + + // Unlink removed Tags + $files = []; + foreach ($removeTagData as $tagId => $ids) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($ids as $id) { + if ($failed && \in_array($id, $failed, true)) { + continue; + } + + $files[] = $this->getFile($id, false, $tagFolder); + } + } + $fs->remove($files); + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids, array $tagData = []): bool + { + $ok = $this->doDeleteCache($ids); + + // Remove tags + $files = []; + $fs = $this->getFilesystem(); + foreach ($tagData as $tagId => $idMap) { + $tagFolder = $this->getTagFolder($tagId); + foreach ($idMap as $id) { + $files[] = $this->getFile($id, false, $tagFolder); + } + } + $fs->remove($files); + + return $ok; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + foreach ($tagIds as $tagId) { + $tagsFolder = $this->getTagFolder($tagId); + if (!file_exists($tagsFolder)) { + continue; + } + + foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS)) as $itemLink) { + if (!$itemLink->isLink()) { + throw new LogicException('Expected a (sym)link when iterating over tag folder, non link found: '.$itemLink); + } + + $valueFile = $itemLink->getRealPath(); + if ($valueFile && \file_exists($valueFile)) { + @unlink($valueFile); + } + + @unlink((string) $itemLink); + } + } + + return true; + } + + private function getFilesystem(): Filesystem + { + return $this->fs ?? $this->fs = new Filesystem(); + } + + 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/Psr16Adapter.php b/vendor/symfony/cache/Adapter/Psr16Adapter.php new file mode 100644 index 0000000000..a14ee082be --- /dev/null +++ b/vendor/symfony/cache/Adapter/Psr16Adapter.php @@ -0,0 +1,81 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <p@tchwork.com> + */ +class Psr16Adapter extends AbstractAdapter implements PruneableInterface, ResettableInterface +{ + use ProxyTrait; + + 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, $lifetime) + { + return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); + } +} diff --git a/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php new file mode 100644 index 0000000000..4e09387213 --- /dev/null +++ b/vendor/symfony/cache/Adapter/RedisTagAwareAdapter.php @@ -0,0 +1,209 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; +use Predis\Connection\Aggregate\ClusterInterface; +use Predis\Response\Status; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; +use Symfony\Component\Cache\Traits\RedisTrait; + +/** + * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using sPOP. + * + * 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). + * + * Requirements: + * - Server: Redis 3.2+ + * - Client: PHP Redis 3.1.3+ OR Predis + * - Redis Server(s) configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory + * + * Design limitations: + * - Max 2 billion cache keys per cache tag + * E.g. If you use a "all" items tag for expiry instead of clear(), that limits you to 2 billion cache items as well + * + * @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. + * @see https://redis.io/commands/spop Documentation for sPOP operation, capable of retriving AND emptying a Set at once. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author André Rømcke <andre.romcke+symfony@gmail.com> + * + * @experimental in 4.3 + */ +class RedisTagAwareAdapter extends AbstractTagAwareAdapter +{ + use RedisTrait; + + /** + * Redis "Set" can hold more than 4 billion members, here we limit ourselves to PHP's > 2 billion max int (32Bit). + */ + private const POP_MAX_LIMIT = 2147483647 - 1; + + /** + * Limits for how many keys are deleted in batch. + */ + private const BULK_DELETE_LIMIT = 10000; + + /** + * 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 bool|null + */ + private $redisServerSupportSPOP = null; + + /** + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient The redis client + * @param string $namespace The default namespace + * @param int $defaultLifetime The default lifetime + * @param MarshallerInterface|null $marshaller + * + * @throws \Symfony\Component\Cache\Exception\LogicException If phpredis with version lower than 3.1.3. + */ + public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) + { + $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); + + // Make sure php-redis is 3.1.3 or higher configured for Redis classes + if (!$this->redis instanceof Predis\Client && \version_compare(\phpversion('redis'), '3.1.3', '<')) { + throw new LogicException('RedisTagAwareAdapter requires php-redis 3.1.3 or higher, alternatively use predis/predis'); + } + } + + /** + * {@inheritdoc} + */ + protected function doSave(array $values, ?int $lifetime, array $addTagData = [], array $delTagData = []): array + { + // 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) { + // 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) { + yield 'sAdd' => array_merge([$tagId], $ids); + } + + foreach ($delTagData as $tagId => $ids) { + 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 || $result !== Status::get('OK'))) { + $failed[] = $id; + } + } + + return $failed; + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids, array $tagData = []): bool + { + if (!$ids) { + return true; + } + + $predisCluster = $this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface; + $this->pipeline(static function () use ($ids, $tagData, $predisCluster) { + if ($predisCluster) { + foreach ($ids as $id) { + yield 'del' => [$id]; + } + } else { + yield 'del' => $ids; + } + + foreach ($tagData as $tagId => $idList) { + yield 'sRem' => \array_merge([$tagId], $idList); + } + })->rewind(); + + return true; + } + + /** + * {@inheritdoc} + */ + protected function doInvalidate(array $tagIds): bool + { + if (!$this->redisServerSupportSPOP()) { + return false; + } + + // Pop all tag info at once to avoid race conditions + $tagIdSets = $this->pipeline(static function () use ($tagIds) { + foreach ($tagIds as $tagId) { + // Client: Predis or PHP Redis 3.1.3+ (https://github.com/phpredis/phpredis/commit/d2e203a6) + // Server: Redis 3.2 or higher (https://redis.io/commands/spop) + yield 'sPop' => [$tagId, self::POP_MAX_LIMIT]; + } + }); + + // Flatten generator result from pipeline, ignore keys (tag ids) + $ids = \array_unique(\array_merge(...\iterator_to_array($tagIdSets, false))); + + // Delete cache in chunks to avoid overloading the connection + foreach (\array_chunk($ids, self::BULK_DELETE_LIMIT) as $chunkIds) { + $this->doDelete($chunkIds); + } + + return true; + } + + private function redisServerSupportSPOP(): bool + { + if (null !== $this->redisServerSupportSPOP) { + return $this->redisServerSupportSPOP; + } + + foreach ($this->getHosts() as $host) { + $info = $host->info('Server'); + $info = isset($info['Server']) ? $info['Server'] : $info; + if (version_compare($info['redis_version'], '3.2', '<')) { + CacheItem::log($this->logger, 'Redis server needs to be version 3.2 or higher, your Redis server was detected as '.$info['redis_version']); + + return $this->redisServerSupportSPOP = false; + } + } + + return $this->redisServerSupportSPOP = true; + } +} diff --git a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php index 5a836a3dbf..d0d42e57f0 100644 --- a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php +++ b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php @@ -11,68 +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 <p@tchwork.com> + * @deprecated since Symfony 4.3, use Psr16Adapter instead. */ -class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface +class SimpleCacheAdapter extends Psr16Adapter { - use ProxyTrait; - - 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, $lifetime) - { - return $this->pool->setMultiple($values, 0 === $lifetime ? null : $lifetime); - } } diff --git a/vendor/symfony/cache/CHANGELOG.md b/vendor/symfony/cache/CHANGELOG.md index 9016bc5dbf..37dd2e11a0 100644 --- a/vendor/symfony/cache/CHANGELOG.md +++ b/vendor/symfony/cache/CHANGELOG.md @@ -1,6 +1,13 @@ CHANGELOG ========= +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 ----- diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php index b1af39755e..5d7a2369c2 100644 --- a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php @@ -68,14 +68,20 @@ class CachePoolPass implements CompilerPassInterface 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'])) { + if (null !== $class) { + $seed .= '.'.$class; + } + $tags[0]['namespace'] = $this->getNamespace($seed, $name); } if (isset($tags[0]['clearer'])) { @@ -136,6 +142,10 @@ class CachePoolPass implements CompilerPassInterface $clearer->addTag($this->cacheSystemClearerTag); } } + + if ($container->hasDefinition('console.command.cache_pool_list')) { + $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($pools)); + } } private function getNamespace($seed, $id) diff --git a/vendor/symfony/cache/Exception/CacheException.php b/vendor/symfony/cache/Exception/CacheException.php index e87b2db8fe..d2e975b2bc 100644 --- a/vendor/symfony/cache/Exception/CacheException.php +++ b/vendor/symfony/cache/Exception/CacheException.php @@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception; 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 828bf3ed77..7f9584a264 100644 --- a/vendor/symfony/cache/Exception/InvalidArgumentException.php +++ b/vendor/symfony/cache/Exception/InvalidArgumentException.php @@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception; 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 index d299673eb2..9ffa7ed695 100644 --- a/vendor/symfony/cache/Exception/LogicException.php +++ b/vendor/symfony/cache/Exception/LogicException.php @@ -14,6 +14,12 @@ namespace Symfony\Component\Cache\Exception; use Psr\Cache\CacheException as Psr6CacheInterface; use Psr\SimpleCache\CacheException as SimpleCacheInterface; -class LogicException extends \LogicException implements Psr6CacheInterface, 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/LockRegistry.php b/vendor/symfony/cache/LockRegistry.php index ef49805ea0..676fba5dca 100644 --- a/vendor/symfony/cache/LockRegistry.php +++ b/vendor/symfony/cache/LockRegistry.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache; +use Psr\Log\LoggerInterface; use Symfony\Contracts\Cache\CacheInterface; use Symfony\Contracts\Cache\ItemInterface; @@ -33,19 +34,23 @@ final class LockRegistry */ 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', @@ -74,7 +79,7 @@ final class LockRegistry return $previousFiles; } - public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null) + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null) { $key = self::$files ? crc32($item->getKey()) % \count(self::$files) : -1; @@ -86,6 +91,7 @@ final class LockRegistry try { // race to get the lock in non-blocking mode if (flock($lock, LOCK_EX | LOCK_NB)) { + $logger && $logger->info('Lock acquired, now computing item "{key}"', ['key' => $item->getKey()]); self::$lockedFiles[$key] = true; $value = $callback($item, $save); @@ -102,6 +108,7 @@ final class LockRegistry 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); @@ -113,6 +120,7 @@ final class LockRegistry try { $value = $pool->get($item->getKey(), $signalingCallback, 0); + $logger && $logger->info('Item "{key}" retrieved after lock was released', ['key' => $item->getKey()]); $save = false; return $value; @@ -120,6 +128,7 @@ final class LockRegistry if ($signalingException !== $e) { throw $e; } + $logger && $logger->info('Item "{key}" not found while lock was released, now retrying', ['key' => $item->getKey()]); } } } diff --git a/vendor/symfony/cache/Psr16Cache.php b/vendor/symfony/cache/Psr16Cache.php new file mode 100644 index 0000000000..589ffa0d8b --- /dev/null +++ b/vendor/symfony/cache/Psr16Cache.php @@ -0,0 +1,263 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; + +/** + * Turns a PSR-6 cache into a PSR-16 one. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +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( + 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, null, $allowInt)->set($value); + }; + } + + /** + * {@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 = []; + + 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) $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]]; + } + } + + 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/AbstractCache.php b/vendor/symfony/cache/Simple/AbstractCache.php index 7a2a3cb36e..312a7dbfd0 100644 --- a/vendor/symfony/cache/Simple/AbstractCache.php +++ b/vendor/symfony/cache/Simple/AbstractCache.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\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 <p@tchwork.com> + * @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 { use AbstractTrait { deleteItems as private; @@ -52,7 +56,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re 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; @@ -86,7 +90,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re 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); @@ -125,7 +129,8 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re 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; } @@ -171,7 +176,7 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re 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 0877c394bb..c22771e822 100644 --- a/vendor/symfony/cache/Simple/ApcuCache.php +++ b/vendor/symfony/cache/Simple/ApcuCache.php @@ -13,6 +13,11 @@ namespace Symfony\Component\Cache\Simple; use Symfony\Component\Cache\Traits\ApcuTrait; +@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; diff --git a/vendor/symfony/cache/Simple/ArrayCache.php b/vendor/symfony/cache/Simple/ArrayCache.php index e36dacb829..3df5b4990c 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 <p@tchwork.com> + * @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; diff --git a/vendor/symfony/cache/Simple/ChainCache.php b/vendor/symfony/cache/Simple/ChainCache.php index 18e9462ba0..a0122fdee9 100644 --- a/vendor/symfony/cache/Simple/ChainCache.php +++ b/vendor/symfony/cache/Simple/ChainCache.php @@ -11,21 +11,25 @@ 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. * * 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 <p@tchwork.com> + * @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 = []; @@ -33,8 +37,8 @@ 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, int $defaultLifetime = 0) { @@ -43,8 +47,8 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf } 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)); } } diff --git a/vendor/symfony/cache/Simple/DoctrineCache.php b/vendor/symfony/cache/Simple/DoctrineCache.php index 0ba701d7cd..6a6d003153 100644 --- a/vendor/symfony/cache/Simple/DoctrineCache.php +++ b/vendor/symfony/cache/Simple/DoctrineCache.php @@ -12,8 +12,15 @@ 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; diff --git a/vendor/symfony/cache/Simple/FilesystemCache.php b/vendor/symfony/cache/Simple/FilesystemCache.php index 8e04d53355..8891abd94c 100644 --- a/vendor/symfony/cache/Simple/FilesystemCache.php +++ b/vendor/symfony/cache/Simple/FilesystemCache.php @@ -11,11 +11,18 @@ 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; diff --git a/vendor/symfony/cache/Simple/MemcachedCache.php b/vendor/symfony/cache/Simple/MemcachedCache.php index 8e418b071e..e1934119aa 100644 --- a/vendor/symfony/cache/Simple/MemcachedCache.php +++ b/vendor/symfony/cache/Simple/MemcachedCache.php @@ -11,9 +11,16 @@ 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; diff --git a/vendor/symfony/cache/Simple/NullCache.php b/vendor/symfony/cache/Simple/NullCache.php index fa986aebd1..d1ca6f7187 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\Components\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 <p@tchwork.com> + * @deprecated since Symfony 4.3, use NullAdapter and type-hint for CacheInterface instead. */ -class NullCache implements CacheInterface +class NullCache implements Psr16CacheInterface { /** * {@inheritdoc} diff --git a/vendor/symfony/cache/Simple/PdoCache.php b/vendor/symfony/cache/Simple/PdoCache.php index 521e9b8f2d..07849e93fe 100644 --- a/vendor/symfony/cache/Simple/PdoCache.php +++ b/vendor/symfony/cache/Simple/PdoCache.php @@ -11,10 +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; diff --git a/vendor/symfony/cache/Simple/PhpArrayCache.php b/vendor/symfony/cache/Simple/PhpArrayCache.php index 6ba8527885..566609359d 100644 --- a/vendor/symfony/cache/Simple/PhpArrayCache.php +++ b/vendor/symfony/cache/Simple/PhpArrayCache.php @@ -11,28 +11,28 @@ 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 <galopintitouan@gmail.com> - * @author Nicolas Grekas <p@tchwork.com> + * @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(string $file, CacheInterface $fallbackPool) + public function __construct(string $file, Psr16CacheInterface $fallbackPool) { $this->file = $file; $this->pool = $fallbackPool; @@ -43,9 +43,9 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt * * @param string $file The PHP file were values are cached * - * @return CacheInterface + * @return Psr16CacheInterface */ - public static function create($file, CacheInterface $fallbackPool) + public static function create($file, Psr16CacheInterface $fallbackPool) { // Shared memory is available in PHP 7.0+ with OPCache enabled if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { diff --git a/vendor/symfony/cache/Simple/PhpFilesCache.php b/vendor/symfony/cache/Simple/PhpFilesCache.php index 37432c5af8..060244a086 100644 --- a/vendor/symfony/cache/Simple/PhpFilesCache.php +++ b/vendor/symfony/cache/Simple/PhpFilesCache.php @@ -11,10 +11,17 @@ 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; diff --git a/vendor/symfony/cache/Simple/Psr6Cache.php b/vendor/symfony/cache/Simple/Psr6Cache.php index fceb9ba70f..090f48c172 100644 --- a/vendor/symfony/cache/Simple/Psr6Cache.php +++ b/vendor/symfony/cache/Simple/Psr6Cache.php @@ -11,254 +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 <p@tchwork.com> + * @deprecated since Symfony 4.3, use Psr16Cache instead. */ -class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterface +class Psr6Cache extends Psr16Cache { - 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( - 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, null, $allowInt)->set($value); - }; - } - - /** - * {@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 = []; - - 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) $metadata[CacheItem::METADATA_EXPIRY] - self::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $values[$key]]; - } - } - - 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 df2a96e86b..2933bf15b3 100644 --- a/vendor/symfony/cache/Simple/RedisCache.php +++ b/vendor/symfony/cache/Simple/RedisCache.php @@ -11,9 +11,16 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\Marshaller\MarshallerInterface; 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; diff --git a/vendor/symfony/cache/Simple/TraceableCache.php b/vendor/symfony/cache/Simple/TraceableCache.php index 2db335ac96..ad9bfcf09c 100644 --- a/vendor/symfony/cache/Simple/TraceableCache.php +++ b/vendor/symfony/cache/Simple/TraceableCache.php @@ -11,23 +11,24 @@ namespace Symfony\Component\Cache\Simple; -use Psr\SimpleCache\CacheInterface; +use Psr\SimpleCache\CacheInterface as Psr16CacheInterface; 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 <p@tchwork.com> + * @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(); diff --git a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php index 0eceb6e572..2b66d2bea0 100644 --- a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php +++ b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php @@ -59,6 +59,26 @@ abstract class AdapterTestCase extends CachePoolTest $this->assertFalse($isHit); } + public function testRecursiveGet() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(0, __FUNCTION__); + + $v = $cache->get('k1', function () use (&$counter, $cache) { + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); + + return $v; + }); + + $this->assertSame(1, $counter); + $this->assertSame(1, $v); + $this->assertSame(1, $cache->get('k2', function () { return 2; })); + } + public function testGetMetadata() { if (isset($this->skippedTests[__FUNCTION__])) { @@ -215,14 +235,9 @@ abstract class AdapterTestCase extends CachePoolTest } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/vendor/symfony/cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php new file mode 100644 index 0000000000..83a7ea52dd --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/FilesystemTagAwareAdapterTest.php @@ -0,0 +1,28 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\FilesystemTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +/** + * @group time-sensitive + */ +class FilesystemTagAwareAdapterTest extends FilesystemAdapterTest +{ + use TagAwareTestTrait; + + public function createCachePool($defaultLifetime = 0) + { + return new FilesystemTagAwareAdapter('', $defaultLifetime); + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php index cee80ac196..3a5904b107 100644 --- a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -23,6 +23,7 @@ class PhpArrayAdapterTest extends AdapterTestCase { protected $skippedTests = [ 'testGet' => 'PhpArrayAdapter is read-only.', + 'testRecursiveGet' => 'PhpArrayAdapter is read-only.', 'testBasicUsage' => 'PhpArrayAdapter is read-only.', 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', 'testClear' => 'PhpArrayAdapter is read-only.', diff --git a/vendor/symfony/cache/Tests/Adapter/PredisTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareAdapterTest.php new file mode 100644 index 0000000000..e321a1c9b8 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareAdapterTest extends PredisAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php new file mode 100644 index 0000000000..a8a72e1de4 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareClusterAdapterTest extends PredisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php new file mode 100644 index 0000000000..5b82a80ecb --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisTagAwareRedisClusterAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class PredisTagAwareRedisClusterAdapterTest extends PredisRedisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\Predis\Client::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/Psr16AdapterTest.php b/vendor/symfony/cache/Tests/Adapter/Psr16AdapterTest.php new file mode 100644 index 0000000000..19907ddf78 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/Psr16AdapterTest.php @@ -0,0 +1,31 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\Psr16Adapter; +use Symfony\Component\Cache\Psr16Cache; + +/** + * @group time-sensitive + */ +class Psr16AdapterTest extends AdapterTestCase +{ + protected $skippedTests = [ + 'testPrune' => 'Psr16adapter just proxies', + ]; + + public function createCachePool($defaultLifetime = 0) + { + return new Psr16Adapter(new Psr16Cache(new FilesystemAdapter()), '', $defaultLifetime); + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php index c83abaf91b..4d9bc319eb 100644 --- a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php @@ -31,30 +31,33 @@ class RedisAdapterTest extends AbstractRedisAdapterTest return $adapter; } - public function testCreateConnection() + /** + * @dataProvider provideValidSchemes + */ + public function testCreateConnection($dsnScheme) { - $redis = RedisAdapter::createConnection('redis:?host[h1]&host[h2]&host[/foo:]'); + $redis = RedisAdapter::createConnection($dsnScheme.':?host[h1]&host[h2]&host[/foo:]'); $this->assertInstanceOf(\RedisArray::class, $redis); $this->assertSame(['h1:6379', 'h2:6379', '/foo'], $redis->_hosts()); @$redis = null; // some versions of phpredis connect on destruct, let's silence the warning $redisHost = getenv('REDIS_HOST'); - $redis = RedisAdapter::createConnection('redis://'.$redisHost); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost); $this->assertInstanceOf(\Redis::class, $redis); $this->assertTrue($redis->isConnected()); $this->assertSame(0, $redis->getDbNum()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'/2'); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost.'/2'); $this->assertSame(2, $redis->getDbNum()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['timeout' => 3]); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost, ['timeout' => 3]); $this->assertEquals(3, $redis->getTimeout()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost.'?timeout=4'); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost.'?timeout=4'); $this->assertEquals(4, $redis->getTimeout()); - $redis = RedisAdapter::createConnection('redis://'.$redisHost, ['read_timeout' => 5]); + $redis = RedisAdapter::createConnection($dsnScheme.'://'.$redisHost, ['read_timeout' => 5]); $this->assertEquals(5, $redis->getReadTimeout()); } @@ -87,6 +90,14 @@ class RedisAdapterTest extends AbstractRedisAdapterTest RedisAdapter::createConnection($dsn); } + public function provideValidSchemes() + { + return [ + ['redis'], + ['rediss'], + ]; + } + public function provideInvalidCreateConnection() { return [ diff --git a/vendor/symfony/cache/Tests/Adapter/RedisTagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareAdapterTest.php new file mode 100644 index 0000000000..95e5fe7e3a --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareAdapterTest.php @@ -0,0 +1,35 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; +use Symfony\Component\Cache\Traits\RedisProxy; + +class RedisTagAwareAdapterTest extends RedisAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisProxy::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php new file mode 100644 index 0000000000..5855cc3adf --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; + +class RedisTagAwareArrayAdapterTest extends RedisArrayAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(\RedisArray::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php new file mode 100644 index 0000000000..ef17c1d69e --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php @@ -0,0 +1,35 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\RedisTagAwareAdapter; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; +use Symfony\Component\Cache\Traits\RedisClusterProxy; + +class RedisTagAwareClusterAdapterTest extends RedisClusterAdapterTest +{ + use TagAwareTestTrait; + + protected function setUp() + { + parent::setUp(); + $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); + $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php index 3028af47c6..b11f72d5a3 100644 --- a/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/SimpleCacheAdapterTest.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Cache\Tests\Adapter; -use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\SimpleCacheAdapter; -use Symfony\Component\Cache\Simple\Psr6Cache; +use Symfony\Component\Cache\Simple\FilesystemCache; /** * @group time-sensitive + * @group legacy */ class SimpleCacheAdapterTest extends AdapterTestCase { @@ -26,6 +26,6 @@ class SimpleCacheAdapterTest extends AdapterTestCase public function createCachePool($defaultLifetime = 0) { - return new SimpleCacheAdapter(new Psr6Cache(new FilesystemAdapter()), '', $defaultLifetime); + return new SimpleCacheAdapter(new FilesystemCache(), '', $defaultLifetime); } } diff --git a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php index 7b8895b700..a339790862 100644 --- a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php @@ -14,13 +14,15 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\TagAwareAdapter; -use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Tests\Traits\TagAwareTestTrait; /** * @group time-sensitive */ class TagAwareAdapterTest extends AdapterTestCase { + use TagAwareTestTrait; + public function createCachePool($defaultLifetime = 0) { return new TagAwareAdapter(new FilesystemAdapter('', $defaultLifetime)); @@ -32,53 +34,9 @@ class TagAwareAdapterTest extends AdapterTestCase } /** - * @expectedException \Psr\Cache\InvalidArgumentException + * Test feature specific to TagAwareAdapter as it implicit needs to save deferred when also saving expiry info. */ - public function testInvalidTag() - { - $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() + public function testInvalidateCommitsSeperatePools() { $pool1 = $this->createCachePool(); @@ -94,76 +52,6 @@ class TagAwareAdapterTest extends AdapterTestCase $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()); - } - - /** - * @group legacy - */ - 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 testGetMetadata() - { - $pool = $this->createCachePool(); - - $i = $pool->getItem('k'); - $pool->save($i->tag('foo')); - - $i = $pool->getItem('k'); - $this->assertSame(['foo' => 'foo'], $i->getMetadata()[CacheItem::METADATA_TAGS]); - } - public function testPrune() { $cache = new TagAwareAdapter($this->getPruneableMock()); diff --git a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php index f307aa5386..4681b3dc81 100644 --- a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php +++ b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DependencyInjection\CachePoolPass; use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -48,6 +49,27 @@ class CachePoolPassTest extends TestCase $this->assertSame('z3X945Jbf5', $cachePool->getArgument(0)); } + public function testNamespaceArgumentIsSeededWithAdapterClassName() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + $adapter = new Definition(); + $adapter->setAbstract(true); + $adapter->addTag('cache.pool'); + $adapter->setClass(RedisAdapter::class); + $container->setDefinition('app.cache_adapter', $adapter); + $container->setAlias('app.cache_adapter_alias', 'app.cache_adapter'); + $cachePool = new ChildDefinition('app.cache_adapter_alias'); + $cachePool->addArgument(null); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertSame('xmOJ8gqF-Y', $cachePool->getArgument(0)); + } + public function testNamespaceArgumentIsNotReplacedIfArrayAdapterIsUsed() { $container = new ContainerBuilder(); diff --git a/vendor/symfony/cache/Tests/Psr16CacheTest.php b/vendor/symfony/cache/Tests/Psr16CacheTest.php new file mode 100644 index 0000000000..e56d99e441 --- /dev/null +++ b/vendor/symfony/cache/Tests/Psr16CacheTest.php @@ -0,0 +1,168 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 Cache\IntegrationTests\SimpleCacheTest; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\Cache\Psr16Cache; + +/** + * @group time-sensitive + */ +class Psr16CacheTest extends SimpleCacheTest +{ + protected function setUp() + { + parent::setUp(); + + if (\array_key_exists('testPrune', $this->skippedTests)) { + return; + } + + $pool = $this->createSimpleCache(); + if ($pool instanceof Psr16Cache) { + $pool = ((array) $pool)[sprintf("\0%s\0pool", Psr16Cache::class)]; + } + + if (!$pool instanceof PruneableInterface) { + $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; + } + } + + public function createSimpleCache($defaultLifetime = 0) + { + return new Psr16Cache(new FilesystemAdapter('', $defaultLifetime)); + } + + public static function 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__]); + } + + /** @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(); + } + + protected function isPruned($cache, $name) + { + if (Psr16Cache::class !== \get_class($cache)) { + $this->fail('Test classes for pruneable caches must implement `isPruned($cache, $name)` method.'); + } + + $pool = ((array) $cache)[sprintf("\0%s\0pool", Psr16Cache::class)]; + $getFileMethod = (new \ReflectionObject($pool))->getMethod('getFile'); + $getFileMethod->setAccessible(true); + + return !file_exists($getFileMethod->invoke($pool, $name)); + } +} + +class NotUnserializable +{ + public function __wakeup() + { + throw new \Exception(__CLASS__); + } +} diff --git a/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php b/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php index dd5e1509c1..a9f5d98b92 100644 --- a/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/AbstractRedisCacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\RedisCache; +/** + * @group legacy + */ abstract class AbstractRedisCacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php index f37b95a093..b322094603 100644 --- a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\ApcuCache; +/** + * @group legacy + */ class ApcuCacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php index 26c3e14d09..587304a5db 100644 --- a/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ArrayCacheTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Simple\ArrayCache; /** * @group time-sensitive + * @group legacy */ class ArrayCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php index 3c8824869b..d4b3d07f62 100644 --- a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php +++ b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php @@ -132,14 +132,9 @@ abstract class CacheTestCase extends SimpleCacheTest } } -class NotUnserializable implements \Serializable +class NotUnserializable { - public function serialize() - { - return serialize(123); - } - - public function unserialize($ser) + public function __wakeup() { throw new \Exception(__CLASS__); } diff --git a/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php b/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php index e6f7c7cc63..806bb7633b 100644 --- a/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ChainCacheTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Cache\Simple\FilesystemCache; /** * @group time-sensitive + * @group legacy */ class ChainCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php b/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php index af4331d69b..5d78c00cac 100644 --- a/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/DoctrineCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Tests\Fixtures\ArrayCache; /** * @group time-sensitive + * @group legacy */ class DoctrineCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php b/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php index 620305a58a..9f423ba641 100644 --- a/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/FilesystemCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\FilesystemCache; /** * @group time-sensitive + * @group legacy */ class FilesystemCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php index f83f0a2e34..692259296f 100644 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php @@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Simple\MemcachedCache; +/** + * @group legacy + */ class MemcachedCacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php index 13865a6098..d68131a1db 100644 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php +++ b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTextModeTest.php @@ -14,6 +14,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\Cache\Simple\MemcachedCache; +/** + * @group legacy + */ class MemcachedCacheTextModeTest extends MemcachedCacheTest { public function createSimpleCache($defaultLifetime = 0) diff --git a/vendor/symfony/cache/Tests/Simple/NullCacheTest.php b/vendor/symfony/cache/Tests/Simple/NullCacheTest.php index 31f42c32b6..cf0dde92b3 100644 --- a/vendor/symfony/cache/Tests/Simple/NullCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/NullCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\NullCache; /** * @group time-sensitive + * @group legacy */ class NullCacheTest extends TestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php b/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php index 665db09f67..fbdf03be7e 100644 --- a/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PdoCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; /** * @group time-sensitive + * @group legacy */ class PdoCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php b/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php index ce1a9ae4f8..af5c42340b 100644 --- a/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PdoDbalCacheTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Tests\Traits\PdoPruneableTrait; /** * @group time-sensitive + * @group legacy */ class PdoDbalCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php index ba4bde3139..5272604dc3 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest; /** * @group time-sensitive + * @group legacy */ class PhpArrayCacheTest extends CacheTestCase { @@ -127,35 +128,3 @@ class PhpArrayCacheTest extends CacheTestCase $this->assertSame($expected, $values, 'Warm up should create a PHP file that OPCache can load in memory'); } } - -class PhpArrayCacheWrapper extends PhpArrayCache -{ - protected $data = []; - - public function set($key, $value, $ttl = null) - { - (\Closure::bind(function () use ($key, $value) { - $this->data[$key] = $value; - $this->warmUp($this->data); - list($this->keys, $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); - } - (\Closure::bind(function () use ($values) { - foreach ($values as $key => $value) { - $this->data[$key] = $value; - } - $this->warmUp($this->data); - list($this->keys, $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 index abee5e7872..90aa7bb6ef 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Cache\Tests\Adapter\FilesystemAdapterTest; /** * @group time-sensitive + * @group legacy */ class PhpArrayCacheWithFallbackTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWrapper.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWrapper.php new file mode 100644 index 0000000000..1e102fe1ff --- /dev/null +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheWrapper.php @@ -0,0 +1,46 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\PhpArrayCache; + +class PhpArrayCacheWrapper extends PhpArrayCache +{ + protected $data = []; + + public function set($key, $value, $ttl = null) + { + (\Closure::bind(function () use ($key, $value) { + $this->data[$key] = $value; + $this->warmUp($this->data); + list($this->keys, $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); + } + (\Closure::bind(function () use ($values) { + foreach ($values as $key => $value) { + $this->data[$key] = $value; + } + $this->warmUp($this->data); + list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); + }, $this, PhpArrayCache::class))(); + + return true; + } +} diff --git a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php index 3a68dd3984..7e40df7de5 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\PhpFilesCache; /** * @group time-sensitive + * @group legacy */ class PhpFilesCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php index 65d48a978c..9fff36e402 100644 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/Psr6CacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\Psr6Cache; +/** + * @group legacy + */ abstract class Psr6CacheTest extends CacheTestCase { protected $skippedTests = [ diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php index 46da9354d6..e5c7a6a4c7 100644 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php +++ b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithAdapterTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Adapter\FilesystemAdapter; /** * @group time-sensitive + * @group legacy */ class Psr6CacheWithAdapterTest extends Psr6CacheTest { diff --git a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php index a8c4164dcb..f987d40539 100644 --- a/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php +++ b/vendor/symfony/cache/Tests/Simple/Psr6CacheWithoutAdapterTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter; /** * @group time-sensitive + * @group legacy */ class Psr6CacheWithoutAdapterTest extends Psr6CacheTest { diff --git a/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php index bda39d990b..b52f5f9acd 100644 --- a/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/RedisArrayCacheTest.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Cache\Tests\Simple; +/** + * @group legacy + */ class RedisArrayCacheTest extends AbstractRedisCacheTest { public static function setupBeforeClass() diff --git a/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php index 407d916c73..ddb674b285 100644 --- a/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/RedisCacheTest.php @@ -13,6 +13,9 @@ namespace Symfony\Component\Cache\Tests\Simple; use Symfony\Component\Cache\Simple\RedisCache; +/** + * @group legacy + */ class RedisCacheTest extends AbstractRedisCacheTest { public static function setupBeforeClass() diff --git a/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php b/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php index 99d4e518fb..33c7acae0b 100644 --- a/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/RedisClusterCacheTest.php @@ -11,6 +11,9 @@ namespace Symfony\Component\Cache\Tests\Simple; +/** + * @group legacy + */ class RedisClusterCacheTest extends AbstractRedisCacheTest { public static function setupBeforeClass() diff --git a/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php b/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php index e684caf36e..c2e8a477b4 100644 --- a/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/TraceableCacheTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Cache\Simple\TraceableCache; /** * @group time-sensitive + * @group legacy */ class TraceableCacheTest extends CacheTestCase { diff --git a/vendor/symfony/cache/Tests/Traits/TagAwareTestTrait.php b/vendor/symfony/cache/Tests/Traits/TagAwareTestTrait.php new file mode 100644 index 0000000000..38cc4dc9cc --- /dev/null +++ b/vendor/symfony/cache/Tests/Traits/TagAwareTestTrait.php @@ -0,0 +1,160 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; + +use Symfony\Component\Cache\CacheItem; + +/** + * Common assertions for TagAware adapters. + * + * @method \Symfony\Component\Cache\Adapter\TagAwareAdapterInterface createCachePool() Must be implemented by TestCase + */ +trait TagAwareTestTrait +{ + /** + * @expectedException \Psr\Cache\InvalidArgumentException + */ + public function testInvalidTag() + { + $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() + { + $pool = $this->createCachePool(); + + $foo = $pool->getItem('foo'); + $foo->tag('tag'); + + $pool->saveDeferred($foo->set('foo')); + $pool->invalidateTags(['tag']); + + // ??: This seems to contradict a bit logic in deleteItems, where it does unset($this->deferred[$key]); on key matches + + $foo = $pool->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() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $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()); + } + + /** + * @group legacy + */ + 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 testGetMetadata() + { + $pool = $this->createCachePool(); + + $i = $pool->getItem('k'); + $pool->save($i->tag('foo')); + + $i = $pool->getItem('k'); + $this->assertSame(['foo' => 'foo'], $i->getMetadata()[CacheItem::METADATA_TAGS]); + } +} diff --git a/vendor/symfony/cache/Traits/AbstractAdapterTrait.php b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php new file mode 100644 index 0000000000..eb464c319e --- /dev/null +++ b/vendor/symfony/cache/Traits/AbstractAdapterTrait.php @@ -0,0 +1,139 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +trait AbstractAdapterTrait +{ + use AbstractTrait; + + /** + * @var \Closure needs to be set by class, signature is function(string <key>, mixed <value>, bool <isHit>) + */ + private $createCacheItem; + + /** + * @var \Closure needs to be set by class, signature is function(array <deferred>, string <namespace>, array <&expiredIds>) + */ + private $mergeByLifetime; + + /** + * {@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}": '.$e->getMessage(), ['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 items: '.$e->getMessage(), ['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; + } + + 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 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 2553ea75cb..1d6c189c81 100644 --- a/vendor/symfony/cache/Traits/AbstractTrait.php +++ b/vendor/symfony/cache/Traits/AbstractTrait.php @@ -94,7 +94,7 @@ trait AbstractTrait 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; } @@ -122,7 +122,7 @@ trait AbstractTrait try { return $this->doClear($this->namespace) || $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; } @@ -166,7 +166,8 @@ trait AbstractTrait } } 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; } diff --git a/vendor/symfony/cache/Traits/ArrayTrait.php b/vendor/symfony/cache/Traits/ArrayTrait.php index e585c3d48c..8ae9cad59b 100644 --- a/vendor/symfony/cache/Traits/ArrayTrait.php +++ b/vendor/symfony/cache/Traits/ArrayTrait.php @@ -128,7 +128,8 @@ trait ArrayTrait $serialized = 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]); + $message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage()); + CacheItem::log($this->logger, $message, ['key' => substr($id, \strlen($this->namespace)), 'exception' => $e]); return; } @@ -150,7 +151,7 @@ trait ArrayTrait try { $value = unserialize($value); } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', ['key' => $key, 'exception' => $e]); + CacheItem::log($this->logger, 'Failed to unserialize key "{key}": '.$e->getMessage(), ['key' => $key, 'exception' => $e]); $value = false; } if (false === $value) { diff --git a/vendor/symfony/cache/Traits/ContractsTrait.php b/vendor/symfony/cache/Traits/ContractsTrait.php index bd7be08dd5..d9514d3965 100644 --- a/vendor/symfony/cache/Traits/ContractsTrait.php +++ b/vendor/symfony/cache/Traits/ContractsTrait.php @@ -11,6 +11,7 @@ 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; @@ -31,6 +32,7 @@ trait ContractsTrait } private $callbackWrapper = [LockRegistry::class, 'compute']; + private $computing = []; /** * Wraps the callback passed to ->get() in a callable. @@ -40,7 +42,7 @@ trait ContractsTrait public function setCallbackWrapper(?callable $callbackWrapper): callable { $previousWrapper = $this->callbackWrapper; - $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata) { + $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata, ?LoggerInterface $logger) { return $callback($item, $save); }; @@ -68,27 +70,28 @@ trait ContractsTrait CacheItem::class ); - return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata) { + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) { // don't wrap nor save recursive calls - if (null === $callbackWrapper = $this->callbackWrapper) { + if (isset($this->computing[$key])) { $value = $callback($item, $save); $save = false; return $value; } - $this->callbackWrapper = null; + + $this->computing[$key] = $key; $startTime = microtime(true); try { - $value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) { + $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 { - $this->callbackWrapper = $callbackWrapper; + unset($this->computing[$key]); } - }, $beta, $metadata); + }, $beta, $metadata, $this->logger ?? null); } } diff --git a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php index 3f684acd68..37e1fd1f06 100644 --- a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php +++ b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php @@ -101,11 +101,11 @@ trait FilesystemCommonTrait } } - private function getFile($id, $mkdir = false) + private function getFile($id, $mkdir = false, string $directory = null) { // 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 = $this->directory.strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); + $dir = ($directory ?? $this->directory).strtoupper($hash[0].\DIRECTORY_SEPARATOR.$hash[1].\DIRECTORY_SEPARATOR); if ($mkdir && !file_exists($dir)) { @mkdir($dir, 0777, true); diff --git a/vendor/symfony/cache/Traits/RedisTrait.php b/vendor/symfony/cache/Traits/RedisTrait.php index 350a54360e..b2faca651d 100644 --- a/vendor/symfony/cache/Traits/RedisTrait.php +++ b/vendor/symfony/cache/Traits/RedisTrait.php @@ -80,15 +80,19 @@ trait RedisTrait */ 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 (0 === strpos($dsn, 'redis:')) { + $scheme = 'redis'; + } elseif (0 === strpos($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) { + $params = preg_replace_callback('#^'.$scheme.':(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { if (isset($m[2])) { $auth = $m[2]; } @@ -317,33 +321,13 @@ trait RedisTrait protected function doClear($namespace) { $cleared = true; - $hosts = [$this->redis]; - $evalArgs = [[$namespace], 0]; - if ($this->redis instanceof \Predis\Client) { $evalArgs = [0, $namespace]; - - $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[] = $h = new \Redis(); - $h->connect($host[0], $host[1]); - } + } else { + $evalArgs = [[$namespace], 0]; } - foreach ($hosts as $host) { + foreach ($this->getHosts() as $host) { if (!isset($namespace[0])) { $cleared = $host->flushDb() && $cleared; continue; @@ -475,4 +459,31 @@ trait RedisTrait yield $id => $results[$k]; } } + + private function getHosts(): array + { + $hosts = [$this->redis]; + if ($this->redis instanceof \Predis\Client) { + $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[] = $h = new \Redis(); + $h->connect($host[0], $host[1]); + } + } + + return $hosts; + } } diff --git a/vendor/symfony/cache/composer.json b/vendor/symfony/cache/composer.json index 8f9e669a33..05bed1cf75 100644 --- a/vendor/symfony/cache/composer.json +++ b/vendor/symfony/cache/composer.json @@ -18,14 +18,14 @@ "provide": { "psr/cache-implementation": "1.0", "psr/simple-cache-implementation": "1.0", - "symfony/cache-contracts-implementation": "1.0" + "symfony/cache-implementation": "1.0" }, "require": { "php": "^7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", - "psr/simple-cache": "^1.0", - "symfony/contracts": "^1.0", + "symfony/cache-contracts": "^1.1", + "symfony/service-contracts": "^1.1", "symfony/var-exporter": "^4.2" }, "require-dev": { @@ -33,6 +33,7 @@ "doctrine/cache": "~1.6", "doctrine/dbal": "~2.5", "predis/predis": "~1.1", + "psr/simple-cache": "^1.0", "symfony/config": "~4.2", "symfony/dependency-injection": "~3.4|~4.1", "symfony/var-dumper": "^4.1.1" @@ -51,7 +52,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/cache/phpunit.xml.dist b/vendor/symfony/cache/phpunit.xml.dist index c35458ca44..591046cf1c 100644 --- a/vendor/symfony/cache/phpunit.xml.dist +++ b/vendor/symfony/cache/phpunit.xml.dist @@ -40,7 +40,8 @@ <element key="1"><string>Doctrine\Common\Cache</string></element> <element key="2"><string>Symfony\Component\Cache</string></element> <element key="3"><string>Symfony\Component\Cache\Tests\Fixtures</string></element> - <element key="4"><string>Symfony\Component\Cache\Traits</string></element> + <element key="4"><string>Symfony\Component\Cache\Tests\Traits</string></element> + <element key="5"><string>Symfony\Component\Cache\Traits</string></element> </array> </element> </array> diff --git a/vendor/symfony/contracts/CHANGELOG.md b/vendor/symfony/contracts/CHANGELOG.md deleted file mode 100644 index f909b4976f..0000000000 --- a/vendor/symfony/contracts/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -CHANGELOG -========= - -1.1.0 ------ - - * added `HttpClient` namespace with contracts for implementing flexible HTTP clients - * added `EventDispatcherInterface` and `Event` in namespace `EventDispatcher` - * added `ServiceProviderInterface` in namespace `Service` - -1.0.0 ------ - - * added `Service\ResetInterface` to provide a way to reset an object to its initial state - * added `Translation\TranslatorInterface` and `Translation\TranslatorTrait` - * added `Cache` contract to extend PSR-6 with tag invalidation, callback-based computation and stampede protection - * added `Service\ServiceSubscriberInterface` to declare the dependencies of a class that consumes a service locator - * added `Service\ServiceSubscriberTrait` to implement `Service\ServiceSubscriberInterface` using methods' return types - * added `Service\ServiceLocatorTrait` to help implement PSR-11 service locators diff --git a/vendor/symfony/contracts/HttpClient/ChunkInterface.php b/vendor/symfony/contracts/HttpClient/ChunkInterface.php deleted file mode 100644 index bbec2cdfa6..0000000000 --- a/vendor/symfony/contracts/HttpClient/ChunkInterface.php +++ /dev/null @@ -1,66 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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 <p@tchwork.com> - * - * @experimental in 1.1 - */ -interface ChunkInterface -{ - /** - * Tells when the inactivity 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 inactivity timeout is reached - */ - public function isFirst(): bool; - - /** - * Tells when the body just completed. - * - * @throws TransportExceptionInterface on a network error or when the inactivity timeout is reached - */ - public function isLast(): bool; - - /** - * Returns the content of the response chunk. - * - * @throws TransportExceptionInterface on a network error or when the inactivity 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/contracts/HttpClient/Exception/HttpExceptionInterface.php b/vendor/symfony/contracts/HttpClient/Exception/HttpExceptionInterface.php deleted file mode 100644 index 0e9f39f6ee..0000000000 --- a/vendor/symfony/contracts/HttpClient/Exception/HttpExceptionInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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 <anton_ch1989@mail.ru> - * - * @experimental in 1.1 - */ -interface HttpExceptionInterface extends ExceptionInterface -{ - public function getResponse(): ResponseInterface; -} diff --git a/vendor/symfony/contracts/HttpClient/Exception/RedirectionExceptionInterface.php b/vendor/symfony/contracts/HttpClient/Exception/RedirectionExceptionInterface.php deleted file mode 100644 index 8cdd3e70d7..0000000000 --- a/vendor/symfony/contracts/HttpClient/Exception/RedirectionExceptionInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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 <p@tchwork.com> - * - * @experimental in 1.1 - */ -interface RedirectionExceptionInterface extends HttpExceptionInterface -{ -} diff --git a/vendor/symfony/contracts/HttpClient/HttpClientInterface.php b/vendor/symfony/contracts/HttpClient/HttpClientInterface.php deleted file mode 100644 index b985585220..0000000000 --- a/vendor/symfony/contracts/HttpClient/HttpClientInterface.php +++ /dev/null @@ -1,91 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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 - * - * @author Nicolas Grekas <p@tchwork.com> - * - * @experimental in 1.1 - */ -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; when - // an array is passed, it is meant as a form payload of field names and values - 'json' => null, // array|\JsonSerializable - when set, implementations MUST set the "body" option to - // the JSON-encoded value and set the "content-type" headers to a JSON-compatible - // value if they are not defined - 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 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 - whether the content of the response should be buffered or not - '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 inactivity timeout - defaults to ini_get('default_socket_timeout') - '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|ResponseInterface[]|iterable $responses One or more responses created by the current HTTP client - * @param float|null $timeout The inactivity timeout before exiting the iterator - */ - public function stream($responses, float $timeout = null): ResponseStreamInterface; -} diff --git a/vendor/symfony/contracts/HttpClient/ResponseInterface.php b/vendor/symfony/contracts/HttpClient/ResponseInterface.php deleted file mode 100644 index 6751184b87..0000000000 --- a/vendor/symfony/contracts/HttpClient/ResponseInterface.php +++ /dev/null @@ -1,101 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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\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 <p@tchwork.com> - * - * @experimental in 1.1 - */ -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 TransportExceptionInterface When the body cannot be decoded or 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; - - /** - * 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: - * - response_headers - an array modelled after the special $http_response_header variable - * - redirect_count - the number of redirects followed while executing the request - * - redirect_url - the resolved location of redirect responses, null otherwise - * - start_time - the time when the request was sent or 0.0 when it's pending - * - http_method - the HTTP verb of the last request - * - http_code - the last response code or 0 when it is not known yet - * - error - the error message when the transfer was aborted, null otherwise - * - user_data - the value of the "user_data" request option, null if not set - * - url - the last effective URL of the request - * - * 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 array|mixed|null 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/contracts/HttpClient/ResponseStreamInterface.php b/vendor/symfony/contracts/HttpClient/ResponseStreamInterface.php deleted file mode 100644 index dfff554dfe..0000000000 --- a/vendor/symfony/contracts/HttpClient/ResponseStreamInterface.php +++ /dev/null @@ -1,26 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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 <p@tchwork.com> - * - * @experimental in 1.1 - */ -interface ResponseStreamInterface extends \Iterator -{ - public function key(): ResponseInterface; - - public function current(): ChunkInterface; -} diff --git a/vendor/symfony/contracts/HttpClient/Test/Fixtures/web/index.php b/vendor/symfony/contracts/HttpClient/Test/Fixtures/web/index.php deleted file mode 100644 index ff68ab6878..0000000000 --- a/vendor/symfony/contracts/HttpClient/Test/Fixtures/web/index.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php - -if ('cli-server' !== \PHP_SAPI) { - // safe guard against unwanted execution - throw new \Exception("You cannot run this script directly, it's a fixture for TestHttpServer."); -} - -$vars = []; - -if (!$_POST) { - $_POST = json_decode(file_get_contents('php://input'), true); - $_POST['content-type'] = $_SERVER['HTTP_CONTENT_TYPE'] ?? '?'; -} - -foreach ($_SERVER as $k => $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; - } -} - -switch ($vars['REQUEST_URI']) { - default: - exit; - - case '/': - case '/?a=a&b=b': - case 'http://127.0.0.1:8057/': - case 'http://localhost:8057/': - header('Content-Type: application/json'); - ob_start('ob_gzhandler'); - break; - - case '/404': - header('Content-Type: application/json', true, 404); - break; - - 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 '/302': - if (!isset($vars['HTTP_AUTHORIZATION'])) { - header('Location: http://localhost:8057/', true, 302); - } - break; - - case '/302/relative': - header('Location: ..', true, 302); - break; - - 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; -} - -header('Content-Type: application/json', true); - -echo json_encode($vars, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); diff --git a/vendor/symfony/contracts/HttpClient/Test/HttpClientTestCase.php b/vendor/symfony/contracts/HttpClient/Test/HttpClientTestCase.php deleted file mode 100644 index b898ba55c6..0000000000 --- a/vendor/symfony/contracts/HttpClient/Test/HttpClientTestCase.php +++ /dev/null @@ -1,733 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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\TransportExceptionInterface; -use Symfony\Contracts\HttpClient\HttpClientInterface; - -/** - * A reference test suite for HttpClientInterface implementations. - * - * @experimental in 1.1 - */ -abstract class HttpClientTestCase extends TestCase -{ - private static $server; - - public static function setUpBeforeClass() - { - 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 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 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)); - } - - 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 testRedirects() - { - $client = $this->getHttpClient(__FUNCTION__); - $response = $client->request('POST', 'http://localhost:8057/301', [ - 'auth_basic' => 'foo:bar', - '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 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->assertContains('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 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' => 3]); - } - - 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 testTimeoutOnStream() - { - usleep(300000); // wait for the previous test to release the server - $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 testDestruct() - { - $client = $this->getHttpClient(__FUNCTION__); - - $downloaded = 0; - $start = microtime(true); - $client->request('GET', 'http://localhost:8057/timeout-long'); - $client = null; - $duration = microtime(true) - $start; - - $this->assertGreaterThan(1, $duration); - $this->assertLessThan(3, $duration); - } - - 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->assertRegexp('#^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']); - } - - 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->assertContains('gzip', $headers['content-encoding'][0]); - - $body = $response->toArray(); - - $this->assertContains('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']); - } - - /** - * @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->assertContains('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(); - } -} diff --git a/vendor/symfony/contracts/HttpClient/Test/TestHttpServer.php b/vendor/symfony/contracts/HttpClient/Test/TestHttpServer.php deleted file mode 100644 index 8e7a469c42..0000000000 --- a/vendor/symfony/contracts/HttpClient/Test/TestHttpServer.php +++ /dev/null @@ -1,49 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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; - -/** - * @experimental in 1.1 - */ -class TestHttpServer -{ - private static $server; - - public static function start() - { - if (null !== self::$server) { - return; - } - - $finder = new PhpExecutableFinder(); - $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', '127.0.0.1:8057'])); - $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); - $process->setTimeout(300); - $process->start(); - - self::$server = new class() { - public $process; - - public function __destruct() - { - $this->process->stop(); - } - }; - - self::$server->process = $process; - - sleep('\\' === \DIRECTORY_SEPARATOR ? 10 : 1); - } -} diff --git a/vendor/symfony/contracts/README.md b/vendor/symfony/contracts/README.md deleted file mode 100644 index d9cfd2c225..0000000000 --- a/vendor/symfony/contracts/README.md +++ /dev/null @@ -1,70 +0,0 @@ -Symfony 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. - -Design Principles ------------------ - - * contracts are split by domain, each into their own sub-namespaces; - * contracts are small and consistent sets of PHP interfaces, traits, normative - docblocks and reference test suites when applicable, ...; - * all contracts must have a proven implementation to enter this repository; - * they must be backward compatible with existing Symfony components. - -Packages that implement specific contracts should list them in the "provide" -section of their "composer.json" file, using the `symfony/*-contracts-implementation` -convention (e.g. `"provide": { "symfony/cache-contracts-implementation": "1.0" }`). - -FAQ ---- - -### How to use this package? - -The abstractions in this package are useful to achieve loose coupling and -interoperability. By using the provided interfaces as type hints, you are able -to reuse any implementations that match their contracts. It could be a Symfony -component, or another one provided by the PHP community at large. - -Depending on their semantics, some interfaces can be combined with autowiring to -seamlessly inject a service in your classes. - -Others might be useful as labeling interfaces, to hint about a specific behavior -that could be enabled when using autoconfiguration or manual service tagging (or -any other means provided by your framework.) - -### How is this different from PHP-FIG's PSRs? - -When applicable, the provided contracts are built on top of PHP-FIG's PSRs. But -the group has different goals and different processes. Here, we're focusing on -providing abstractions that are useful on their own while still compatible with -implementations provided by Symfony. Although not the main target, we hope that -the declared contracts will directly or indirectly contribute to the PHP-FIG. - -### Why isn't this package split into several packages? - -Putting all interfaces in one package eases discoverability and dependency -management. Instead of dealing with a myriad of small packages and the -corresponding matrix of versions, you just need to deal with one package and one -version. Also when using IDE autocompletion or just reading the source code, it -makes it easier to figure out which contracts are provided. - -There are two downsides to this approach: you may have unused files in your -`vendor/` directory, and in the future, it will be impossible to use two -different sub-namespaces in different major versions of the package. For the -"unused files" downside, it has no practical consequences: their file sizes are -very small, and there is no performance overhead at all since they are never -loaded. For major versions, this package follows the Symfony BC + deprecation -policies, with an additional restriction to never remove deprecated interfaces. - -Resources ---------- - - * [Documentation](https://symfony.com/doc/current/components/contracts.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/contracts/Tests/Cache/CacheTraitTest.php b/vendor/symfony/contracts/Tests/Cache/CacheTraitTest.php deleted file mode 100644 index f77d103c93..0000000000 --- a/vendor/symfony/contracts/Tests/Cache/CacheTraitTest.php +++ /dev/null @@ -1,165 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Contracts\Tests\Cache; - -use PHPUnit\Framework\TestCase; -use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Contracts\Cache\CacheTrait; - -/** - * @author Tobias Nyholm <tobias.nyholm@gmail.com> - */ -class CacheTraitTest extends TestCase -{ - public function testSave() - { - $item = $this->getMockBuilder(CacheItemInterface::class)->getMock(); - $item->method('set') - ->willReturn($item); - $item->method('isHit') - ->willReturn(false); - - $item->expects($this->once()) - ->method('set') - ->with('computed data'); - - $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) - ->getMock(); - $cache->expects($this->once()) - ->method('getItem') - ->with('key') - ->willReturn($item); - $cache->expects($this->once()) - ->method('save'); - - $callback = function (CacheItemInterface $item) { - return 'computed data'; - }; - - $cache->get('key', $callback); - } - - public function testNoCallbackCallOnHit() - { - $item = $this->getMockBuilder(CacheItemInterface::class)->getMock(); - $item->method('isHit') - ->willReturn(true); - - $item->expects($this->never()) - ->method('set'); - - $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) - ->getMock(); - - $cache->expects($this->once()) - ->method('getItem') - ->with('key') - ->willReturn($item); - $cache->expects($this->never()) - ->method('save'); - - $callback = function (CacheItemInterface $item) { - $this->assertTrue(false, 'This code should never be reached'); - }; - - $cache->get('key', $callback); - } - - public function testRecomputeOnBetaInf() - { - $item = $this->getMockBuilder(CacheItemInterface::class)->getMock(); - $item->method('set') - ->willReturn($item); - $item->method('isHit') - // We want to recompute even if it is a hit - ->willReturn(true); - - $item->expects($this->once()) - ->method('set') - ->with('computed data'); - - $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) - ->getMock(); - - $cache->expects($this->once()) - ->method('getItem') - ->with('key') - ->willReturn($item); - $cache->expects($this->once()) - ->method('save'); - - $callback = function (CacheItemInterface $item) { - return 'computed data'; - }; - - $cache->get('key', $callback, INF); - } - - public function testExceptionOnNegativeBeta() - { - $cache = $this->getMockBuilder(TestPool::class) - ->setMethods(['getItem', 'save']) - ->getMock(); - - $callback = function (CacheItemInterface $item) { - return 'computed data'; - }; - - $this->expectException(\InvalidArgumentException::class); - $cache->get('key', $callback, -2); - } -} - -class TestPool implements CacheItemPoolInterface -{ - use CacheTrait; - - public function hasItem($key) - { - } - - public function deleteItem($key) - { - } - - public function deleteItems(array $keys = []) - { - } - - public function getItem($key) - { - } - - public function getItems(array $key = []) - { - } - - public function saveDeferred(CacheItemInterface $item) - { - } - - public function save(CacheItemInterface $item) - { - } - - public function commit() - { - } - - public function clear() - { - } -} diff --git a/vendor/symfony/contracts/Tests/Service/ServiceSubscriberTraitTest.php b/vendor/symfony/contracts/Tests/Service/ServiceSubscriberTraitTest.php deleted file mode 100644 index 344bba8772..0000000000 --- a/vendor/symfony/contracts/Tests/Service/ServiceSubscriberTraitTest.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Contracts\Tests\Service; - -use PHPUnit\Framework\TestCase; -use Psr\Container\ContainerInterface; -use Symfony\Contracts\Service\ServiceLocatorTrait; -use Symfony\Contracts\Service\ServiceSubscriberInterface; -use Symfony\Contracts\Service\ServiceSubscriberTrait; - -class ServiceSubscriberTraitTest extends TestCase -{ - public function testMethodsOnParentsAndChildrenAreIgnoredInGetSubscribedServices() - { - $expected = [TestService::class.'::aService' => '?Symfony\Contracts\Tests\Service\Service2']; - - $this->assertEquals($expected, ChildTestService::getSubscribedServices()); - } - - public function testSetContainerIsCalledOnParent() - { - $container = new class([]) implements ContainerInterface { - use ServiceLocatorTrait; - }; - - $this->assertSame($container, (new TestService())->setContainer($container)); - } -} - -class ParentTestService -{ - public function aParentService(): Service1 - { - } - - public function setContainer(ContainerInterface $container) - { - return $container; - } -} - -class TestService extends ParentTestService implements ServiceSubscriberInterface -{ - use ServiceSubscriberTrait; - - public function aService(): Service2 - { - } -} - -class ChildTestService extends TestService -{ - public function aChildService(): Service3 - { - } -} diff --git a/vendor/symfony/contracts/composer.json b/vendor/symfony/contracts/composer.json deleted file mode 100644 index b83e7c0535..0000000000 --- a/vendor/symfony/contracts/composer.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "symfony/contracts", - "type": "library", - "description": "A set of abstractions extracted out of the Symfony components", - "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" - }, - "require-dev": { - "psr/cache": "^1.0", - "psr/container": "^1.0", - "symfony/polyfill-intl-idn": "^1.10" - }, - "suggest": { - "psr/cache": "When using the Cache contracts", - "psr/container": "When using the Service contracts", - "symfony/cache-contracts-implementation": "", - "symfony/event-dispatcher-implementation": "", - "symfony/http-client-contracts-implementation": "", - "symfony/service-contracts-implementation": "", - "symfony/translation-contracts-implementation": "" - }, - "autoload": { - "psr-4": { "Symfony\\Contracts\\": "" }, - "exclude-from-classmap": [ - "**/Tests/" - ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "1.1-dev" - } - } -} diff --git a/vendor/symfony/debug/CHANGELOG.md b/vendor/symfony/debug/CHANGELOG.md index 122af73174..367e834f01 100644 --- a/vendor/symfony/debug/CHANGELOG.md +++ b/vendor/symfony/debug/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG ========= +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 ----- diff --git a/vendor/symfony/debug/DebugClassLoader.php b/vendor/symfony/debug/DebugClassLoader.php index e648bf60c5..db92f5adf8 100644 --- a/vendor/symfony/debug/DebugClassLoader.php +++ b/vendor/symfony/debug/DebugClassLoader.php @@ -39,6 +39,7 @@ class DebugClassLoader private static $internalMethods = []; private static $annotatedParameters = []; private static $darwinCache = ['/' => ['/', []]]; + private static $method = []; public function __construct(callable $classLoader) { @@ -236,6 +237,24 @@ class DebugClassLoader 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); @@ -266,6 +285,28 @@ class DebugClassLoader 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) { + list($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)) { @@ -311,7 +352,7 @@ class DebugClassLoader } foreach (self::$annotatedParameters[$class][$method->name] as $parameterName => $deprecation) { - if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param (.*?)(?<= )\\\${$parameterName}\\b/", $doc))) { + if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param +((?(?!callable *\().*?|callable *\(.*\).*?))(?<= )\\\${$parameterName}\\b/", $doc))) { $deprecations[] = sprintf($deprecation, $class); } } @@ -334,7 +375,7 @@ class DebugClassLoader if ($finalOrInternal || $method->isConstructor() || false === \strpos($doc, '@param') || StatelessInvocation::class === $class) { continue; } - if (!preg_match_all('#\n\s+\* @param (.*?)(?<= )\$([a-zA-Z0-9_\x7f-\xff]++)#', $doc, $matches, PREG_SET_ORDER)) { + 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])) { diff --git a/vendor/symfony/debug/ErrorHandler.php b/vendor/symfony/debug/ErrorHandler.php index 78ac0240ab..2f250cba36 100644 --- a/vendor/symfony/debug/ErrorHandler.php +++ b/vendor/symfony/debug/ErrorHandler.php @@ -45,6 +45,8 @@ use Symfony\Component\Debug\FatalErrorHandler\UndefinedMethodFatalErrorHandler; * * @author Nicolas Grekas <p@tchwork.com> * @author Grégoire Pineau <lyrixx@lyrixx.info> + * + * @final since Symfony 4.3 */ class ErrorHandler { diff --git a/vendor/symfony/debug/Exception/FlattenException.php b/vendor/symfony/debug/Exception/FlattenException.php index d016bb2fb4..304df0405c 100644 --- a/vendor/symfony/debug/Exception/FlattenException.php +++ b/vendor/symfony/debug/Exception/FlattenException.php @@ -27,6 +27,7 @@ class FlattenException private $code; private $previous; private $trace; + private $traceAsString; private $class; private $statusCode; private $headers; @@ -239,6 +240,8 @@ class FlattenException public function setTraceFromThrowable(\Throwable $throwable) { + $this->traceAsString = $throwable->getTraceAsString(); + return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine()); } @@ -324,4 +327,33 @@ class FlattenException 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/ExceptionHandler.php b/vendor/symfony/debug/ExceptionHandler.php index 2cad1df9be..7ae85eebb7 100644 --- a/vendor/symfony/debug/ExceptionHandler.php +++ b/vendor/symfony/debug/ExceptionHandler.php @@ -26,9 +26,21 @@ use Symfony\Component\HttpKernel\Debug\FileLinkFormatter; * * @author Fabien Potencier <fabien@symfony.com> * @author Nicolas Grekas <p@tchwork.com> + * + * @final since Symfony 4.3 */ 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; @@ -205,7 +217,7 @@ class ExceptionHandler $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) { @@ -440,6 +452,15 @@ EOF; private function getSymfonyGhostAsSvg() { - return '<svg viewBox="0 0 136 81" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><path d="M92.4 20.4a23.2 23.2 0 0 1 9 1.9 23.7 23.7 0 0 1 5.2 3 24.3 24.3 0 0 1 3.4 3.4 24.8 24.8 0 0 1 5 9.4c.5 1.7.8 3.4 1 5.2v14.5h.4l.5.2a7.4 7.4 0 0 0 2.5.2l.2-.2.6-.8.8-1.3-.2-.1a5.5 5.5 0 0 1-.8-.3 5.6 5.6 0 0 1-2.3-1.8 5.7 5.7 0 0 1-.9-1.6 6.5 6.5 0 0 1-.2-2.8 7.3 7.3 0 0 1 .5-2l.3-.3.8-.9.3-.3c.2-.2.5-.3.8-.3H120.7c.2 0 .3-.1.4 0h.4l.2.1.3.2.2-.4.3-.4.1-.1 1.2-1 .3-.2.4-.1.4-.1h.3l1.5.1.4.1.8.5.1.2 1 1.1v.2H129.4l.4-.2 1.4-.5h1.1c.3 0 .7.2 1 .4.2 0 .3.2.5.3l.2.2.5.3.4.6.1.3.4 1.4.1.4v.6a7.8 7.8 0 0 1-.1.6 9.9 9.9 0 0 1-.8 2.4 7.8 7.8 0 0 1-3 3.3 6.4 6.4 0 0 1-1 .5 6.1 6.1 0 0 1-.6.2l-.7.1h-.1a23.4 23.4 0 0 1-.2 1.7 14.3 14.3 0 0 1-.6 2.1l-.8 2a9.2 9.2 0 0 1-.4.6l-.7 1a9.1 9.1 0 0 1-2.3 2.2c-.9.5-2 .6-3 .7l-1.4.1h-.5l-.4.1a15.8 15.8 0 0 1-2.8-.1v4.2a9.7 9.7 0 0 1-.7 3.5 9.6 9.6 0 0 1-1.7 2.8 9.3 9.3 0 0 1-3 2.3 9 9 0 0 1-5.4.7 9 9 0 0 1-3-1 9.4 9.4 0 0 1-2.7-2.5 10 10 0 0 1-1 1.2 9.3 9.3 0 0 1-2 1.3 9 9 0 0 1-2.4 1 9 9 0 0 1-6.5-1.1A9.4 9.4 0 0 1 85 77V77a10.9 10.9 0 0 1-.6.6 9.3 9.3 0 0 1-2.7 2 9 9 0 0 1-6 .8 9 9 0 0 1-2.4-1 9.3 9.3 0 0 1-2.3-1.7 9.6 9.6 0 0 1-1.8-2.8 9.7 9.7 0 0 1-.8-3.7v-4a18.5 18.5 0 0 1-2.9.2l-1.2-.1c-1.9-.3-3.7-1-5.1-2.1A8.2 8.2 0 0 1 58 64a10.2 10.2 0 0 1-.9-1.2 15.3 15.3 0 0 1-.7-1.3 20.8 20.8 0 0 1-1.9-6.2v-.2a6.5 6.5 0 0 1-1-.3 6.1 6.1 0 0 1-.6-.3 6.6 6.6 0 0 1-.9-.5 8.2 8.2 0 0 1-2.7-3.8 10 10 0 0 1-.3-1 10.3 10.3 0 0 1-.3-1.9V47v-.4l.1-.4.6-1.4.1-.2a2 2 0 0 1 .8-.8l.3-.2.3-.2a3.2 3.2 0 0 1 1.8-.5h.4l.3.2 1.4.6.2.2.4.3.3.4.7-.7.2-.2.4-.2.6-.2h2.1l.4.2.4.2.3.2.8 1 .2-.1h.1v-.1H63l1.1.1h.3l.8.5.3.4.7 1 .2.3.1.5a11 11 0 0 1 .2 1.5c0 .8 0 1.6-.3 2.3a6 6 0 0 1-.5 1.2 5.5 5.5 0 0 1-3.3 2.5 12.3 12.3 0 0 0 1.4 3h.1l.2.1 1 .2h1.5l.5-.2H67.8l.5-.2h.1V44v-.4a26.7 26.7 0 0 1 .3-2.3 24.7 24.7 0 0 1 5.7-12.5 24.2 24.2 0 0 1 3.5-3.3 23.7 23.7 0 0 1 4.9-3 23.2 23.2 0 0 1 5.6-1.7 23.7 23.7 0 0 1 4-.3zm-.3 2a21.2 21.2 0 0 0-8 1.7 21.6 21.6 0 0 0-4.8 2.7 22.2 22.2 0 0 0-3.2 3 22.7 22.7 0 0 0-5 9.2 23.4 23.4 0 0 0-.7 4.9v15.7l-.5.1a34.3 34.3 0 0 1-1.5.3h-.2l-.4.1h-.4l-.9.2a10 10 0 0 1-1.9 0c-.5 0-1-.2-1.5-.4a1.8 1.8 0 0 1-.3-.2 2 2 0 0 1-.3-.3 5.2 5.2 0 0 1-.1-.2 9 9 0 0 1-.6-.9 13.8 13.8 0 0 1-1-2 14.3 14.3 0 0 1-.6-2 14 14 0 0 1-.1-.8v-.2h.3a12.8 12.8 0 0 0 1.4-.2 4.4 4.4 0 0 0 .3 0 3.6 3.6 0 0 0 1.1-.7 3.4 3.4 0 0 0 1.2-1.7l.2-1.2a5.1 5.1 0 0 0 0-.8 7.2 7.2 0 0 0-.1-.8l-.7-1-1.2-.2-1 .7-.1 1.3a5 5 0 0 1 .1.4v.6a1 1 0 0 1 0 .3c-.1.3-.4.4-.7.5l-1.2.4v-.7A9.9 9.9 0 0 1 60 49l.3-.6v-.2l.1-.1v-1.6l-1-1.2h-1.5l-1 1.1v.4a5.3 5.3 0 0 0-.2.6 5.5 5.5 0 0 0 0 .5c0 .7 0 1.4.3 2 0 .4.2.8.4 1.2L57 51a9.5 9.5 0 0 1-1.1-.5h-.2a2 2 0 0 1-.4-.3c-.4-.4-.5-1-.6-1.6a5.6 5.6 0 0 1 0-.5v-.5-.5l-.6-1.5-1.4-.6-.9.3s-.2 0-.3.2a2 2 0 0 1-.1 0l-.6 1.4v.7a8.5 8.5 0 0 0 .5 2c.4 1.1 1 2.1 2 2.8a4.7 4.7 0 0 0 2.1.9h1a22.8 22.8 0 0 0 .1 1 18.1 18.1 0 0 0 .8 3.8 18.2 18.2 0 0 0 1.6 3.7l1 1.3c1 1 2.3 1.6 3.7 2a11.7 11.7 0 0 0 4.8 0h.4l.5-.2.5-.1.6-.2v6.6a8 8 0 0 0 .1 1.3 7.5 7.5 0 0 0 2.4 4.3 7.2 7.2 0 0 0 2.3 1.3 7 7 0 0 0 7-1.1 7.5 7.5 0 0 0 2-2.6A7.7 7.7 0 0 0 85 72V71a8.2 8.2 0 0 0 .2 1.3c0 .7.3 1.4.6 2a7.5 7.5 0 0 0 1.7 2.3 7.3 7.3 0 0 0 2.2 1.4 7.1 7.1 0 0 0 4.6.2 7.2 7.2 0 0 0 2.4-1.2 7.5 7.5 0 0 0 2.1-2.7 7.8 7.8 0 0 0 .7-2.4V71a9.3 9.3 0 0 0 .1.6 7.6 7.6 0 0 0 .6 2.5 7.5 7.5 0 0 0 2.4 3 7.1 7.1 0 0 0 7 .8 7.3 7.3 0 0 0 2.3-1.5 7.5 7.5 0 0 0 1.6-2.3 7.6 7.6 0 0 0 .5-2l.1-1.1v-6.7l.4.1a12.2 12.2 0 0 0 2 .5 11.1 11.1 0 0 0 2.5 0h.8l1.2-.1a9.5 9.5 0 0 0 1.4-.2l.9-.3a3.5 3.5 0 0 0 .6-.4l1.2-1.4a12.2 12.2 0 0 0 .8-1.2c0-.3.2-.5.3-.7a15.9 15.9 0 0 0 .7-2l.3-1.6v-1.3l.2-.9V54.6a15.5 15.5 0 0 0 1.8 0 4.5 4.5 0 0 0 1.4-.5 5.7 5.7 0 0 0 2.5-3.2 7.6 7.6 0 0 0 .4-1.5v-.3l-.4-1.4a5.2 5.2 0 0 1-.2-.1l-.4-.4a3.8 3.8 0 0 0-.2 0 1.4 1.4 0 0 0-.5-.2l-1.4.4-.7 1.3v.7a5.7 5.7 0 0 1-.1.8l-.7 1.4a1.9 1.9 0 0 1-.5.3h-.3a9.6 9.6 0 0 1-.8.3 8.8 8.8 0 0 1-.6 0l.2-.4.2-.5.2-.3v-.4l.1-.2V50l.1-1 .1-.6v-.6a4.8 4.8 0 0 0 0-.8v-.2l-1-1.1-1.5-.2-1.1 1-.2 1.4v.1l.2.4.2.3v.4l.1 1.1v.3l.1.5v.8a9.6 9.6 0 0 1-.8-.3l-.2-.1h-.3l-.8-.1h-.2a1.6 1.6 0 0 1-.2-.2.9.9 0 0 1-.2-.2 1 1 0 0 1-.1-.5l.2-.9v-1.2l-.9-.8h-1.2l-.8.9v.3a4.8 4.8 0 0 0-.3 2l.3.9a3.5 3.5 0 0 0 1.2 1.6l1 .5.8.2 1.4.1h.4l.2.1a12.1 12.1 0 0 1-1 2.6 13.2 13.2 0 0 1-.8 1.5 9.5 9.5 0 0 1-1 1.2l-.2.3a1.7 1.7 0 0 1-.4.3 2.4 2.4 0 0 1-.7.2h-2.5a7.8 7.8 0 0 1-.6-.2l-.7-.2h-.2a14.8 14.8 0 0 1-.6-.2 23.4 23.4 0 0 1-.4-.1l-.4-.1-.3-.1V43.9a34.6 34.6 0 0 0 0-.6 23.6 23.6 0 0 0-.4-3 22.7 22.7 0 0 0-1.5-4.7 22.6 22.6 0 0 0-4.6-6.7 21.9 21.9 0 0 0-6.9-4.7 21.2 21.2 0 0 0-8.1-1.8H92zm9.1 33.7l.3.1a1 1 0 0 1 .6.8v.4a8.4 8.4 0 0 1 0 .5 8.8 8.8 0 0 1-1.6 4.2l-1 1.3A10 10 0 0 1 95 66c-1.3.3-2.7.4-4 .3a10.4 10.4 0 0 1-2.7-.8 10 10 0 0 1-3.6-2.5 9.3 9.3 0 0 1-.8-1 9 9 0 0 1-.7-1.2 8.6 8.6 0 0 1-.8-3.4V57a1 1 0 0 1 .3-.6 1 1 0 0 1 1.3-.2 1 1 0 0 1 .4.8v.4a6.5 6.5 0 0 0 .5 2.2 7 7 0 0 0 2.1 2.8l1 .6c2.6 1.6 6 1.6 8.5 0a8 8 0 0 0 1.1-.6 7.6 7.6 0 0 0 1.2-1.2 7 7 0 0 0 1-1.7 6.5 6.5 0 0 0 .4-2.5 1 1 0 0 1 .7-1h.4zM30.7 43.7c-15.5 1-28.5-6-30.1-16.4C-1.2 15.7 11.6 4 29 1.3 46.6-1.7 62.3 5.5 64 17.1c1.6 10.4-8.7 21-23.7 25a31.2 31.2 0 0 0 0 .9v.3a19 19 0 0 0 .1 1l.1.4.1.9a4.7 4.7 0 0 0 .5 1l.7 1a9.2 9.2 0 0 0 1.2 1l1.5.8.6.8-.7.6-1.1.3a11.2 11.2 0 0 1-2.6.4 8.6 8.6 0 0 1-3-.5 8.5 8.5 0 0 1-1-.4 11.2 11.2 0 0 1-1.8-1.2 13.3 13.3 0 0 1-1-1 18 18 0 0 1-.7-.6l-.4-.4a23.4 23.4 0 0 1-1.3-1.8l-.1-.1-.3-.5V45l-.3-.6v-.7zM83.1 36c3.6 0 6.5 3.2 6.5 7.1 0 4-3 7.2-6.5 7.2S76.7 47 76.7 43 79.6 36 83 36zm18 0c3.6 0 6.5 3.2 6.5 7.1 0 4-2.9 7.2-6.4 7.2S94.7 47 94.7 43s3-7.1 6.5-7.1zm-18 6.1c2 0 3.5 1.6 3.5 3.6S85 49.2 83 49.2s-3.4-1.6-3.4-3.6S81.2 42 83 42zm17.9 0c1.9 0 3.4 1.6 3.4 3.6s-1.5 3.6-3.4 3.6c-2 0-3.5-1.6-3.5-3.6S99.1 42 101 42zM17 28c-.3 1.6-1.8 5-5.2 5.8-2.5.6-4.1-.8-4.5-2.6-.4-1.9.7-3.5 2.1-4.5A3.5 3.5 0 0 1 8 24.6c-.4-2 .8-3.7 3.2-4.2 1.9-.5 3.1.2 3.4 1.5.3 1.1-.5 2.2-1.8 2.5-.9.3-1.6 0-1.7-.6a1.4 1.4 0 0 1 0-.7s.3.2 1 0c.7-.1 1-.7.9-1.2-.2-.6-1-.8-1.8-.6-1 .2-2 1-1.7 2.6.3 1 .9 1.6 1.5 1.8l.7-.2c1-.2 1.5 0 1.6.5 0 .4-.2 1-1.2 1.2a3.3 3.3 0 0 1-1.5 0c-.9.7-1.6 1.9-1.3 3.2.3 1.3 1.3 2.2 3 1.8 2.5-.7 3.8-3.7 4.2-5-.3-.5-.6-1-.7-1.6-.1-.5.1-1 .9-1.2.4 0 .7.2.8.8a2.8 2.8 0 0 1 0 1l.7 1c.6-2 1.4-4 1.7-4 .6-.2 1.5.6 1.5.6-.8.7-1.7 2.4-2.3 4.2.8.6 1.6 1 2.1 1 .5-.1.8-.6 1-1.2-.3-2.2 1-4.3 2.3-4.6.7-.2 1.3.2 1.4.8.1.5 0 1.3-.9 1.7-.2-1-.6-1.3-1-1.3-.4.1-.7 1.4-.4 2.8.2 1 .7 1.5 1.3 1.4.8-.2 1.3-1.2 1.7-2.1-.3-2.1.9-4.2 2.2-4.5.7-.2 1.2.1 1.4 1 .4 1.4-1 2.8-2.2 3.4.3.7.7 1 1.3.9 1-.3 1.6-1.5 2-2.5l-.5-3v-.3s1.6-.3 1.8.6v.1c.2-.6.7-1.2 1.3-1.4.8-.1 1.5.6 1.7 1.6.5 2.2-.5 4.4-1.8 4.7H33a31.9 31.9 0 0 0 1 5.2c-.4.1-1.8.4-2-.4l-.5-5.6c-.5 1-1.3 2.2-2.5 2.4-1 .3-1.6-.3-2-1.1-.5 1-1.3 2.1-2.4 2.4-.8.2-1.5-.1-2-1-.3.8-.9 1.5-1.5 1.7-.7.1-1.5-.3-2.4-1-.3.8-.4 1.6-.4 2.2 0 0-.7 0-.8-.4-.1-.5 0-1.5.3-2.7a10.3 10.3 0 0 1-.7-.8zm38.2-17.8l.2.9c.5 1.9.4 4.4.8 6.4 0 .6-.4 3-1.4 3.3-.2 0-.3 0-.4-.4-.1-.7 0-1.6-.3-2.6-.2-1.1-.8-1.6-1.5-1.5-.8.2-1.3 1-1.6 2l-.1-.5c-.2-1-1.8-.6-1.8-.6a6.2 6.2 0 0 1 .4 1.3l.2 1c-.2.5-.6 1-1.2 1l-.2.1a7 7 0 0 0-.1-.8c-.3-1.1-1-2-1.6-1.8a.7.7 0 0 0-.4.3c-1.3.3-2.4 2-2.1 3.9-.2.9-.6 1.7-1 1.9-.5 0-.8-.5-1.1-1.8l-.1-1.2a4 4 0 0 0 0-1.7c0-.4-.4-.7-.8-.6-.7.2-.9 1.7-.5 3.8-.2 1-.6 2-1.3 2-.4.2-.8-.2-1-1l-.2-3c1.2-.5 2-1 1.8-1.7-.1-.5-.8-.7-.8-.7s0 .7-1 1.2l-.2-1.4c-.1-.6-.4-1-1.7-.6l.4 1 .2 1.5h-1v.8c0 .3.4.3 1 .2 0 1.3 0 2.7.2 3.6.3 1.4 1.2 2 2 1.7 1-.2 1.6-1.3 2-2.3.3 1.2 1 2 1.9 1.7.7-.2 1.2-1.1 1.6-2.2.4.8 1.1 1.1 2 1 1.2-.4 1.7-1.6 1.8-2.8h.2c.6-.2 1-.6 1.3-1 0 .8 0 1.5.2 2.1.1.5.3.7.6.6.5-.1 1-.9 1-.9a4 4 0 0 1-.3-1c-.3-1.3.3-3.6 1-3.7.2 0 .3.2.5.7v.8l.2 1.5v.7c.2.7.7 1.3 1.5 1 1.3-.2 2-2.6 2.1-3.9.3.2.6.2 1 .1-.6-2.2 0-6.1-.3-7.9-.1-.4-1-.5-1.7-.5h-.4zm-21.5 12c.4 0 .7.3 1 1.1.2 1.3-.3 2.6-.9 2.8-.2 0-.7 0-1-1.2v-.4c0-1.3.4-2 1-2.2zm-5.2 1c.3 0 .6.2.6.5.2.6-.3 1.3-1.2 2-.3-1.4.1-2.3.6-2.5zm18-.4c-.5.2-1-.4-1.2-1.2-.2-1 0-2.1.7-2.5v.5c.2.7.6 1.5 1.3 1.9 0 .7-.2 1.2-.7 1.3zm10-1.6c0 .5.4.7 1 .6.8-.2 1-1 .8-1.6 0-.5-.4-1-1-.8-.5.1-1 .9-.8 1.8zm-14.3-5.5c0-.4-.5-.7-1-.5-.8.2-1 1-.9 1.5.2.6.5 1 1 .8.5 0 1.1-1 1-1.8z" fill="#fff" fill-opacity=".6"/></svg>'; + return '<svg viewBox="0 0 136 81" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.4"><path d="M92.4 20.4a23.2 23.2 0 0 1 9 1.9 23.7 23.7 0 0 1 5.2 3 24.3 24.3 0 0 1 3.4 3.4 24.8 24.8 0 0 1 5 9.4c.5 1.7.8 3.4 1 5.2v14.5h.4l.5.2a7.4 7.4 0 0 0 2.5.2l.2-.2.6-.8.8-1.3-.2-.1a5.5 5.5 0 0 1-.8-.3 5.6 5.6 0 0 1-2.3-1.8 5.7 5.7 0 0 1-.9-1.6 6.5 6.5 0 0 1-.2-2.8 7.3 7.3 0 0 1 .5-2l.3-.3.8-.9.3-.3c.2-.2.5-.3.8-.3H120.7c.2 0 .3-.1.4 0h.4l.2.1.3.2.2-.4.3-.4.1-.1 1.2-1 .3-.2.4-.1.4-.1h.3l1.5.1.4.1.8.5.1.2 1 1.1v.2H129.4l.4-.2 1.4-.5h1.1c.3 0 .7.2 1 .4.2 0 .3.2.5.3l.2.2.5.3.4.6.1.3.4 1.4.1.4v.6a7.8 7.8 0 0 1-.1.6 9.9 9.9 0 0 1-.8 2.4 7.8 7.8 0 0 1-3 3.3 6.4 6.4 0 0 1-1 .5 6.1 6.1 0 0 1-.6.2l-.7.1h-.1a23.4 23.4 0 0 1-.2 1.7 14.3 14.3 0 0 1-.6 2.1l-.8 2a9.2 9.2 0 0 1-.4.6l-.7 1a9.1 9.1 0 0 1-2.3 2.2c-.9.5-2 .6-3 .7l-1.4.1h-.5l-.4.1a15.8 15.8 0 0 1-2.8-.1v4.2a9.7 9.7 0 0 1-.7 3.5 9.6 9.6 0 0 1-1.7 2.8 9.3 9.3 0 0 1-3 2.3 9 9 0 0 1-5.4.7 9 9 0 0 1-3-1 9.4 9.4 0 0 1-2.7-2.5 10 10 0 0 1-1 1.2 9.3 9.3 0 0 1-2 1.3 9 9 0 0 1-2.4 1 9 9 0 0 1-6.5-1.1A9.4 9.4 0 0 1 85 77V77a10.9 10.9 0 0 1-.6.6 9.3 9.3 0 0 1-2.7 2 9 9 0 0 1-6 .8 9 9 0 0 1-2.4-1 9.3 9.3 0 0 1-2.3-1.7 9.6 9.6 0 0 1-1.8-2.8 9.7 9.7 0 0 1-.8-3.7v-4a18.5 18.5 0 0 1-2.9.2l-1.2-.1c-1.9-.3-3.7-1-5.1-2.1A8.2 8.2 0 0 1 58 64a10.2 10.2 0 0 1-.9-1.2 15.3 15.3 0 0 1-.7-1.3 20.8 20.8 0 0 1-1.9-6.2v-.2a6.5 6.5 0 0 1-1-.3 6.1 6.1 0 0 1-.6-.3 6.6 6.6 0 0 1-.9-.5 8.2 8.2 0 0 1-2.7-3.8 10 10 0 0 1-.3-1 10.3 10.3 0 0 1-.3-1.9V47v-.4l.1-.4.6-1.4.1-.2a2 2 0 0 1 .8-.8l.3-.2.3-.2a3.2 3.2 0 0 1 1.8-.5h.4l.3.2 1.4.6.2.2.4.3.3.4.7-.7.2-.2.4-.2.6-.2h2.1l.4.2.4.2.3.2.8 1 .2-.1h.1v-.1H63l1.1.1h.3l.8.5.3.4.7 1 .2.3.1.5a11 11 0 0 1 .2 1.5c0 .8 0 1.6-.3 2.3a6 6 0 0 1-.5 1.2 5.5 5.5 0 0 1-3.3 2.5 12.3 12.3 0 0 0 1.4 3h.1l.2.1 1 .2h1.5l.5-.2H67.8l.5-.2h.1V44v-.4a26.7 26.7 0 0 1 .3-2.3 24.7 24.7 0 0 1 5.7-12.5 24.2 24.2 0 0 1 3.5-3.3 23.7 23.7 0 0 1 4.9-3 23.2 23.2 0 0 1 5.6-1.7 23.7 23.7 0 0 1 4-.3zm-.3 2a21.2 21.2 0 0 0-8 1.7 21.6 21.6 0 0 0-4.8 2.7 22.2 22.2 0 0 0-3.2 3 22.7 22.7 0 0 0-5 9.2 23.4 23.4 0 0 0-.7 4.9v15.7l-.5.1a34.3 34.3 0 0 1-1.5.3h-.2l-.4.1h-.4l-.9.2a10 10 0 0 1-1.9 0c-.5 0-1-.2-1.5-.4a1.8 1.8 0 0 1-.3-.2 2 2 0 0 1-.3-.3 5.2 5.2 0 0 1-.1-.2 9 9 0 0 1-.6-.9 13.8 13.8 0 0 1-1-2 14.3 14.3 0 0 1-.6-2 14 14 0 0 1-.1-.8v-.2h.3a12.8 12.8 0 0 0 1.4-.2 4.4 4.4 0 0 0 .3 0 3.6 3.6 0 0 0 1.1-.7 3.4 3.4 0 0 0 1.2-1.7l.2-1.2a5.1 5.1 0 0 0 0-.8 7.2 7.2 0 0 0-.1-.8l-.7-1-1.2-.2-1 .7-.1 1.3a5 5 0 0 1 .1.4v.6a1 1 0 0 1 0 .3c-.1.3-.4.4-.7.5l-1.2.4v-.7A9.9 9.9 0 0 1 60 49l.3-.6v-.2l.1-.1v-1.6l-1-1.2h-1.5l-1 1.1v.4a5.3 5.3 0 0 0-.2.6 5.5 5.5 0 0 0 0 .5c0 .7 0 1.4.3 2 0 .4.2.8.4 1.2L57 51a9.5 9.5 0 0 1-1.1-.5h-.2a2 2 0 0 1-.4-.3c-.4-.4-.5-1-.6-1.6a5.6 5.6 0 0 1 0-.5v-.5-.5l-.6-1.5-1.4-.6-.9.3s-.2 0-.3.2a2 2 0 0 1-.1 0l-.6 1.4v.7a8.5 8.5 0 0 0 .5 2c.4 1.1 1 2.1 2 2.8a4.7 4.7 0 0 0 2.1.9h1a22.8 22.8 0 0 0 .1 1 18.1 18.1 0 0 0 .8 3.8 18.2 18.2 0 0 0 1.6 3.7l1 1.3c1 1 2.3 1.6 3.7 2a11.7 11.7 0 0 0 4.8 0h.4l.5-.2.5-.1.6-.2v6.6a8 8 0 0 0 .1 1.3 7.5 7.5 0 0 0 2.4 4.3 7.2 7.2 0 0 0 2.3 1.3 7 7 0 0 0 7-1.1 7.5 7.5 0 0 0 2-2.6A7.7 7.7 0 0 0 85 72V71a8.2 8.2 0 0 0 .2 1.3c0 .7.3 1.4.6 2a7.5 7.5 0 0 0 1.7 2.3 7.3 7.3 0 0 0 2.2 1.4 7.1 7.1 0 0 0 4.6.2 7.2 7.2 0 0 0 2.4-1.2 7.5 7.5 0 0 0 2.1-2.7 7.8 7.8 0 0 0 .7-2.4V71a9.3 9.3 0 0 0 .1.6 7.6 7.6 0 0 0 .6 2.5 7.5 7.5 0 0 0 2.4 3 7.1 7.1 0 0 0 7 .8 7.3 7.3 0 0 0 2.3-1.5 7.5 7.5 0 0 0 1.6-2.3 7.6 7.6 0 0 0 .5-2l.1-1.1v-6.7l.4.1a12.2 12.2 0 0 0 2 .5 11.1 11.1 0 0 0 2.5 0h.8l1.2-.1a9.5 9.5 0 0 0 1.4-.2l.9-.3a3.5 3.5 0 0 0 .6-.4l1.2-1.4a12.2 12.2 0 0 0 .8-1.2c0-.3.2-.5.3-.7a15.9 15.9 0 0 0 .7-2l.3-1.6v-1.3l.2-.9V54.6a15.5 15.5 0 0 0 1.8 0 4.5 4.5 0 0 0 1.4-.5 5.7 5.7 0 0 0 2.5-3.2 7.6 7.6 0 0 0 .4-1.5v-.3l-.4-1.4a5.2 5.2 0 0 1-.2-.1l-.4-.4a3.8 3.8 0 0 0-.2 0 1.4 1.4 0 0 0-.5-.2l-1.4.4-.7 1.3v.7a5.7 5.7 0 0 1-.1.8l-.7 1.4a1.9 1.9 0 0 1-.5.3h-.3a9.6 9.6 0 0 1-.8.3 8.8 8.8 0 0 1-.6 0l.2-.4.2-.5.2-.3v-.4l.1-.2V50l.1-1 .1-.6v-.6a4.8 4.8 0 0 0 0-.8v-.2l-1-1.1-1.5-.2-1.1 1-.2 1.4v.1l.2.4.2.3v.4l.1 1.1v.3l.1.5v.8a9.6 9.6 0 0 1-.8-.3l-.2-.1h-.3l-.8-.1h-.2a1.6 1.6 0 0 1-.2-.2.9.9 0 0 1-.2-.2 1 1 0 0 1-.1-.5l.2-.9v-1.2l-.9-.8h-1.2l-.8.9v.3a4.8 4.8 0 0 0-.3 2l.3.9a3.5 3.5 0 0 0 1.2 1.6l1 .5.8.2 1.4.1h.4l.2.1a12.1 12.1 0 0 1-1 2.6 13.2 13.2 0 0 1-.8 1.5 9.5 9.5 0 0 1-1 1.2l-.2.3a1.7 1.7 0 0 1-.4.3 2.4 2.4 0 0 1-.7.2h-2.5a7.8 7.8 0 0 1-.6-.2l-.7-.2h-.2a14.8 14.8 0 0 1-.6-.2 23.4 23.4 0 0 1-.4-.1l-.4-.1-.3-.1V43.9a34.6 34.6 0 0 0 0-.6 23.6 23.6 0 0 0-.4-3 22.7 22.7 0 0 0-1.5-4.7 22.6 22.6 0 0 0-4.6-6.7 21.9 21.9 0 0 0-6.9-4.7 21.2 21.2 0 0 0-8.1-1.8H92zm9.1 33.7l.3.1a1 1 0 0 1 .6.8v.4a8.4 8.4 0 0 1 0 .5 8.8 8.8 0 0 1-1.6 4.2l-1 1.3A10 10 0 0 1 95 66c-1.3.3-2.7.4-4 .3a10.4 10.4 0 0 1-2.7-.8 10 10 0 0 1-3.6-2.5 9.3 9.3 0 0 1-.8-1 9 9 0 0 1-.7-1.2 8.6 8.6 0 0 1-.8-3.4V57a1 1 0 0 1 .3-.6 1 1 0 0 1 1.3-.2 1 1 0 0 1 .4.8v.4a6.5 6.5 0 0 0 .5 2.2 7 7 0 0 0 2.1 2.8l1 .6c2.6 1.6 6 1.6 8.5 0a8 8 0 0 0 1.1-.6 7.6 7.6 0 0 0 1.2-1.2 7 7 0 0 0 1-1.7 6.5 6.5 0 0 0 .4-2.5 1 1 0 0 1 .7-1h.4zM30.7 43.7c-15.5 1-28.5-6-30.1-16.4C-1.2 15.7 11.6 4 29 1.3 46.6-1.7 62.3 5.5 64 17.1c1.6 10.4-8.7 21-23.7 25a31.2 31.2 0 0 0 0 .9v.3a19 19 0 0 0 .1 1l.1.4.1.9a4.7 4.7 0 0 0 .5 1l.7 1a9.2 9.2 0 0 0 1.2 1l1.5.8.6.8-.7.6-1.1.3a11.2 11.2 0 0 1-2.6.4 8.6 8.6 0 0 1-3-.5 8.5 8.5 0 0 1-1-.4 11.2 11.2 0 0 1-1.8-1.2 13.3 13.3 0 0 1-1-1 18 18 0 0 1-.7-.6l-.4-.4a23.4 23.4 0 0 1-1.3-1.8l-.1-.1-.3-.5V45l-.3-.6v-.7zM83.1 36c3.6 0 6.5 3.2 6.5 7.1 0 4-3 7.2-6.5 7.2S76.7 47 76.7 43 79.6 36 83 36zm18 0c3.6 0 6.5 3.2 6.5 7.1 0 4-2.9 7.2-6.4 7.2S94.7 47 94.7 43s3-7.1 6.5-7.1zm-18 6.1c2 0 3.5 1.6 3.5 3.6S85 49.2 83 49.2s-3.4-1.6-3.4-3.6S81.2 42 83 42zm17.9 0c1.9 0 3.4 1.6 3.4 3.6s-1.5 3.6-3.4 3.6c-2 0-3.5-1.6-3.5-3.6S99.1 42 101 42zM17 28c-.3 1.6-1.8 5-5.2 5.8-2.5.6-4.1-.8-4.5-2.6-.4-1.9.7-3.5 2.1-4.5A3.5 3.5 0 0 1 8 24.6c-.4-2 .8-3.7 3.2-4.2 1.9-.5 3.1.2 3.4 1.5.3 1.1-.5 2.2-1.8 2.5-.9.3-1.6 0-1.7-.6a1.4 1.4 0 0 1 0-.7s.3.2 1 0c.7-.1 1-.7.9-1.2-.2-.6-1-.8-1.8-.6-1 .2-2 1-1.7 2.6.3 1 .9 1.6 1.5 1.8l.7-.2c1-.2 1.5 0 1.6.5 0 .4-.2 1-1.2 1.2a3.3 3.3 0 0 1-1.5 0c-.9.7-1.6 1.9-1.3 3.2.3 1.3 1.3 2.2 3 1.8 2.5-.7 3.8-3.7 4.2-5-.3-.5-.6-1-.7-1.6-.1-.5.1-1 .9-1.2.4 0 .7.2.8.8a2.8 2.8 0 0 1 0 1l.7 1c.6-2 1.4-4 1.7-4 .6-.2 1.5.6 1.5.6-.8.7-1.7 2.4-2.3 4.2.8.6 1.6 1 2.1 1 .5-.1.8-.6 1-1.2-.3-2.2 1-4.3 2.3-4.6.7-.2 1.3.2 1.4.8.1.5 0 1.3-.9 1.7-.2-1-.6-1.3-1-1.3-.4.1-.7 1.4-.4 2.8.2 1 .7 1.5 1.3 1.4.8-.2 1.3-1.2 1.7-2.1-.3-2.1.9-4.2 2.2-4.5.7-.2 1.2.1 1.4 1 .4 1.4-1 2.8-2.2 3.4.3.7.7 1 1.3.9 1-.3 1.6-1.5 2-2.5l-.5-3v-.3s1.6-.3 1.8.6v.1c.2-.6.7-1.2 1.3-1.4.8-.1 1.5.6 1.7 1.6.5 2.2-.5 4.4-1.8 4.7H33a31.9 31.9 0 0 0 1 5.2c-.4.1-1.8.4-2-.4l-.5-5.6c-.5 1-1.3 2.2-2.5 2.4-1 .3-1.6-.3-2-1.1-.5 1-1.3 2.1-2.4 2.4-.8.2-1.5-.1-2-1-.3.8-.9 1.5-1.5 1.7-.7.1-1.5-.3-2.4-1-.3.8-.4 1.6-.4 2.2 0 0-.7 0-.8-.4-.1-.5 0-1.5.3-2.7a10.3 10.3 0 0 1-.7-.8zm38.2-17.8l.2.9c.5 1.9.4 4.4.8 6.4 0 .6-.4 3-1.4 3.3-.2 0-.3 0-.4-.4-.1-.7 0-1.6-.3-2.6-.2-1.1-.8-1.6-1.5-1.5-.8.2-1.3 1-1.6 2l-.1-.5c-.2-1-1.8-.6-1.8-.6a6.2 6.2 0 0 1 .4 1.3l.2 1c-.2.5-.6 1-1.2 1l-.2.1a7 7 0 0 0-.1-.8c-.3-1.1-1-2-1.6-1.8a.7.7 0 0 0-.4.3c-1.3.3-2.4 2-2.1 3.9-.2.9-.6 1.7-1 1.9-.5 0-.8-.5-1.1-1.8l-.1-1.2a4 4 0 0 0 0-1.7c0-.4-.4-.7-.8-.6-.7.2-.9 1.7-.5 3.8-.2 1-.6 2-1.3 2-.4.2-.8-.2-1-1l-.2-3c1.2-.5 2-1 1.8-1.7-.1-.5-.8-.7-.8-.7s0 .7-1 1.2l-.2-1.4c-.1-.6-.4-1-1.7-.6l.4 1 .2 1.5h-1v.8c0 .3.4.3 1 .2 0 1.3 0 2.7.2 3.6.3 1.4 1.2 2 2 1.7 1-.2 1.6-1.3 2-2.3.3 1.2 1 2 1.9 1.7.7-.2 1.2-1.1 1.6-2.2.4.8 1.1 1.1 2 1 1.2-.4 1.7-1.6 1.8-2.8h.2c.6-.2 1-.6 1.3-1 0 .8 0 1.5.2 2.1.1.5.3.7.6.6.5-.1 1-.9 1-.9a4 4 0 0 1-.3-1c-.3-1.3.3-3.6 1-3.7.2 0 .3.2.5.7v.8l.2 1.5v.7c.2.7.7 1.3 1.5 1 1.3-.2 2-2.6 2.1-3.9.3.2.6.2 1 .1-.6-2.2 0-6.1-.3-7.9-.1-.4-1-.5-1.7-.5h-.4zm-21.5 12c.4 0 .7.3 1 1.1.2 1.3-.3 2.6-.9 2.8-.2 0-.7 0-1-1.2v-.4c0-1.3.4-2 1-2.2zm-5.2 1c.3 0 .6.2.6.5.2.6-.3 1.3-1.2 2-.3-1.4.1-2.3.6-2.5zm18-.4c-.5.2-1-.4-1.2-1.2-.2-1 0-2.1.7-2.5v.5c.2.7.6 1.5 1.3 1.9 0 .7-.2 1.2-.7 1.3zm10-1.6c0 .5.4.7 1 .6.8-.2 1-1 .8-1.6 0-.5-.4-1-1-.8-.5.1-1 .9-.8 1.8zm-14.3-5.5c0-.4-.5-.7-1-.5-.8.2-1 1-.9 1.5.2.6.5 1 1 .8.5 0 1.1-1 1-1.8z" fill="#fff" fill-opacity=".6"/>'.$this->addElementToGhost().'</svg>'; + } + + private function addElementToGhost() + { + if (!isset(self::GHOST_ADDONS[\date('m-d')])) { + return ''; + } + + return '<path d="'.self::GHOST_ADDONS[\date('m-d')].'" fill="#fff" fill-opacity="0.6"></path>'; } } diff --git a/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php index 30c5665e60..a0e2f770f0 100644 --- a/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php @@ -171,7 +171,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface } } - require_once $file; + try { + require_once $file; + } catch (\Throwable $e) { + return null; + } foreach ($candidates as $candidate) { if ($this->classExists($candidate)) { diff --git a/vendor/symfony/debug/Tests/DebugClassLoaderTest.php b/vendor/symfony/debug/Tests/DebugClassLoaderTest.php index da02cf855f..6ee20ae8a7 100644 --- a/vendor/symfony/debug/Tests/DebugClassLoaderTest.php +++ b/vendor/symfony/debug/Tests/DebugClassLoaderTest.php @@ -294,6 +294,11 @@ class DebugClassLoaderTest extends TestCase $this->assertSame([ 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::quzMethod()" method will require a new "Quz $quz" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.', 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::whereAmI()" method will require a new "bool $matrix" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.', + 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "$noType" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.', + 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable(\Throwable|null $reason, mixed $value) $callback" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.', + 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "string $param" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.', + 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "callable ($a, $b) $anotherOne" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.', + 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::iAmHere()" method will require a new "Type$WithDollarIsStillAType $ccc" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\InterfaceWithAnnotatedParameters", not defining it is deprecated.', 'The "Symfony\Component\Debug\Tests\Fixtures\SubClassWithAnnotatedParameters::isSymfony()" method will require a new "true $yes" argument in the next major version of its parent class "Symfony\Component\Debug\Tests\Fixtures\ClassWithAnnotatedParameters", not defining it is deprecated.', ], $deprecations); } @@ -312,6 +317,46 @@ class DebugClassLoaderTest extends TestCase $this->assertSame([], $deprecations); } + public function testVirtualUse() + { + $deprecations = []; + set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); + $e = error_reporting(E_USER_DEPRECATED); + + class_exists('Test\\'.__NAMESPACE__.'\\ExtendsVirtual', true); + + error_reporting($e); + restore_error_handler(); + + $this->assertSame([ + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::sameLineInterfaceMethodNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::newLineInterfaceMethod()": Some description!', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::newLineInterfaceMethodNoBraces()": Description.', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::invalidInterfaceMethod()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::invalidInterfaceMethodNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::complexInterfaceMethod($arg, ...$args)".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::complexInterfaceMethodTyped($arg, int ...$args)": Description ...', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodTyped(int $arg)": Description.', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtualParent" should implement method "static Symfony\Component\Debug\Tests\Fixtures\VirtualInterface::staticMethodTypedNoBraces()".', + 'Class "Test\Symfony\Component\Debug\Tests\ExtendsVirtual" should implement method "Symfony\Component\Debug\Tests\Fixtures\VirtualSubInterface::subInterfaceMethod()".', + ], $deprecations); + } + + public function testVirtualUseWithMagicCall() + { + $deprecations = []; + set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); + $e = error_reporting(E_USER_DEPRECATED); + + class_exists('Test\\'.__NAMESPACE__.'\\ExtendsVirtualMagicCall', true); + + error_reporting($e); + restore_error_handler(); + + $this->assertSame([], $deprecations); + } + public function testEvaluatedCode() { $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true)); @@ -372,6 +417,32 @@ class ClassLoader eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }'); } elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtual' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtual extends ExtendsVirtualParent implements \\'.__NAMESPACE__.'\Fixtures\VirtualSubInterface { + public function ownClassMethod() { } + public function classMethod() { } + public function sameLineInterfaceMethodNoBraces() { } + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualParent' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualParent extends ExtendsVirtualAbstract { + public function ownParentMethod() { } + public function traitMethod() { } + public function sameLineInterfaceMethod() { } + public function staticMethodNoBraces() { } // should be static + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualAbstract' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; abstract class ExtendsVirtualAbstract extends ExtendsVirtualAbstractBase { + public static function staticMethod() { } + public function ownAbstractMethod() { } + public function interfaceMethod() { } + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualAbstractBase' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; abstract class ExtendsVirtualAbstractBase extends \\'.__NAMESPACE__.'\Fixtures\VirtualClass implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface { + public function ownAbstractBaseMethod() { } + }'); + } elseif ('Test\\'.__NAMESPACE__.'\ExtendsVirtualMagicCall' === $class) { + eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsVirtualMagicCall extends \\'.__NAMESPACE__.'\Fixtures\VirtualClassMagicCall implements \\'.__NAMESPACE__.'\Fixtures\VirtualInterface { + }'); } } } diff --git a/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php b/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php index eb884b51c1..e86210b903 100644 --- a/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php +++ b/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php @@ -346,6 +346,41 @@ class FlattenExceptionTest extends TestCase $this->assertSame('Class "RuntimeException@anonymous" blah.', $flattened->getMessage()); } + public function testToStringEmptyMessage() + { + $exception = new \RuntimeException(); + + $flattened = FlattenException::create($exception); + + $this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString()); + $this->assertSame($exception->__toString(), $flattened->getAsString()); + } + + public function testToString() + { + $test = function ($a, $b, $c, $d) { + return new \RuntimeException('This is a test message'); + }; + + $exception = $test('foo123', 1, null, 1.5); + + $flattened = FlattenException::create($exception); + + $this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString()); + $this->assertSame($exception->__toString(), $flattened->getAsString()); + } + + public function testToStringParent() + { + $exception = new \LogicException('This is message 1'); + $exception = new \RuntimeException('This is messsage 2', 500, $exception); + + $flattened = FlattenException::create($exception); + + $this->assertSame($exception->getTraceAsString(), $flattened->getTraceAsString()); + $this->assertSame($exception->__toString(), $flattened->getAsString()); + } + private function createException($foo) { return new \Exception(); diff --git a/vendor/symfony/debug/Tests/ExceptionHandlerTest.php b/vendor/symfony/debug/Tests/ExceptionHandlerTest.php index e166136cbb..4910fe5ec9 100644 --- a/vendor/symfony/debug/Tests/ExceptionHandlerTest.php +++ b/vendor/symfony/debug/Tests/ExceptionHandlerTest.php @@ -48,8 +48,17 @@ class ExceptionHandlerTest extends TestCase $handler->sendPhpResponse(new \RuntimeException('Foo')); $response = ob_get_clean(); - $this->assertContains('Whoops, looks like something went wrong.', $response); + $this->assertContains('<h1 class="break-long-words exception-message">Foo</h1>', $response); $this->assertContains('<div class="trace trace-as-html">', $response); + + // taken from https://www.owasp.org/index.php/Cross-site_Scripting_(XSS) + $htmlWithXss = '<body onload=alert(\'test1\')> <b onmouseover=alert(\'Wufff!\')>click me!</b> <img src="jAvascript:alert(\'test2\')"> <meta http-equiv="refresh" +content="0;url=data:text/html;base64,PHNjcmlwdD5hbGVydCgndGVzdDMnKTwvc2NyaXB0Pg">'; + ob_start(); + $handler->sendPhpResponse(new \RuntimeException($htmlWithXss)); + $response = ob_get_clean(); + + $this->assertContains(sprintf('<h1 class="break-long-words exception-message">%s</h1>', htmlspecialchars($htmlWithXss, ENT_COMPAT | ENT_SUBSTITUTE, 'UTF-8')), $response); } public function testStatusCode() diff --git a/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php b/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php index 54abd68efa..86593db124 100644 --- a/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php +++ b/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php @@ -11,4 +11,17 @@ interface InterfaceWithAnnotatedParameters * @param bool $matrix */ public function whereAmI(); + + /** + * @param $noType + * @param callable(\Throwable|null $reason, mixed $value) $callback and a comment + * about this great param + * @param string $param (comment with $dollar) + * @param $defined + * @param callable ($a, $b) $anotherOne + * @param callable (mixed $a, $b) $definedCallable + * @param Type$WithDollarIsStillAType $ccc + * @param \JustAType + */ + public function iAmHere(); } diff --git a/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php b/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php index 20358e96de..5d05d79835 100644 --- a/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php +++ b/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php @@ -21,4 +21,12 @@ class SubClassWithAnnotatedParameters extends ClassWithAnnotatedParameters imple public function whereAmI() { } + + /** + * @param $defined + * @param Type\Does\Not\Matter $definedCallable + */ + public function iAmHere() + { + } } diff --git a/vendor/symfony/debug/Tests/Fixtures/VirtualClass.php b/vendor/symfony/debug/Tests/Fixtures/VirtualClass.php new file mode 100644 index 0000000000..25712519a5 --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/VirtualClass.php @@ -0,0 +1,11 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +/** + * @method string classMethod() + */ +class VirtualClass +{ + use VirtualTrait; +} diff --git a/vendor/symfony/debug/Tests/Fixtures/VirtualClassMagicCall.php b/vendor/symfony/debug/Tests/Fixtures/VirtualClassMagicCall.php new file mode 100644 index 0000000000..de33e8afc5 --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/VirtualClassMagicCall.php @@ -0,0 +1,18 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +/** + * @method string magicMethod() + * @method static string staticMagicMethod() + */ +class VirtualClassMagicCall +{ + public static function __callStatic($name, $arguments) + { + } + + public function __call($name, $arguments) + { + } +} diff --git a/vendor/symfony/debug/Tests/Fixtures/VirtualInterface.php b/vendor/symfony/debug/Tests/Fixtures/VirtualInterface.php new file mode 100644 index 0000000000..943014eefb --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/VirtualInterface.php @@ -0,0 +1,34 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +/** + * @method string interfaceMethod() + * @method sameLineInterfaceMethod($arg) + * @method sameLineInterfaceMethodNoBraces + * + * Ignored + * @method + * @method + * + * Not ignored + * @method newLineInterfaceMethod() Some description! + * @method \stdClass newLineInterfaceMethodNoBraces Description + * + * Invalid + * @method unknownType invalidInterfaceMethod() + * @method unknownType|string invalidInterfaceMethodNoBraces + * + * Complex + * @method complexInterfaceMethod($arg, ...$args) + * @method string[]|int complexInterfaceMethodTyped($arg, int ...$args) Description ... + * + * Static + * @method static Foo&Bar staticMethod() + * @method static staticMethodNoBraces + * @method static \stdClass staticMethodTyped(int $arg) Description + * @method static \stdClass[] staticMethodTypedNoBraces + */ +interface VirtualInterface +{ +} diff --git a/vendor/symfony/debug/Tests/Fixtures/VirtualSubInterface.php b/vendor/symfony/debug/Tests/Fixtures/VirtualSubInterface.php new file mode 100644 index 0000000000..dee19731dc --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/VirtualSubInterface.php @@ -0,0 +1,10 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +/** + * @method string subInterfaceMethod() + */ +interface VirtualSubInterface extends VirtualInterface +{ +} diff --git a/vendor/symfony/debug/Tests/Fixtures/VirtualTrait.php b/vendor/symfony/debug/Tests/Fixtures/VirtualTrait.php new file mode 100644 index 0000000000..f584a8aa8f --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/VirtualTrait.php @@ -0,0 +1,10 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +/** + * @method string traitMethod() + */ +trait VirtualTrait +{ +} diff --git a/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt b/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt index b3f0e0eb09..1736a3b5f2 100644 --- a/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt +++ b/vendor/symfony/debug/Tests/phpt/fatal_with_nested_handlers.phpt @@ -24,7 +24,7 @@ var_dump([ $eHandler[0]->setExceptionHandler('print_r'); if (true) { - class Broken implements \Serializable + class Broken implements \JsonSerializable { } } @@ -37,6 +37,6 @@ array(1) { } 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)" + string(179) "Error: Class Symfony\Component\Debug\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" %a } diff --git a/vendor/symfony/debug/composer.json b/vendor/symfony/debug/composer.json index 45799e2e60..7fd5ff9c93 100644 --- a/vendor/symfony/debug/composer.json +++ b/vendor/symfony/debug/composer.json @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/contracts/EventDispatcher/Event.php b/vendor/symfony/event-dispatcher-contracts/Event.php index 84f60f3ed0..84f60f3ed0 100644 --- a/vendor/symfony/contracts/EventDispatcher/Event.php +++ b/vendor/symfony/event-dispatcher-contracts/Event.php diff --git a/vendor/symfony/contracts/EventDispatcher/EventDispatcherInterface.php b/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php index 9b1a69add2..9b1a69add2 100644 --- a/vendor/symfony/contracts/EventDispatcher/EventDispatcherInterface.php +++ b/vendor/symfony/event-dispatcher-contracts/EventDispatcherInterface.php diff --git a/vendor/symfony/event-dispatcher-contracts/LICENSE b/vendor/symfony/event-dispatcher-contracts/LICENSE new file mode 100644 index 0000000000..3f853aaf35 --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-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/event-dispatcher-contracts/README.md b/vendor/symfony/event-dispatcher-contracts/README.md new file mode 100644 index 0000000000..fb051c73fc --- /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/master/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 0000000000..55802a491d --- /dev/null +++ b/vendor/symfony/event-dispatcher-contracts/composer.json @@ -0,0 +1,34 @@ +{ + "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-master": "1.1-dev" + } + } +} diff --git a/vendor/symfony/event-dispatcher/CHANGELOG.md b/vendor/symfony/event-dispatcher/CHANGELOG.md index b581d31433..7653cad1c0 100644 --- a/vendor/symfony/event-dispatcher/CHANGELOG.md +++ b/vendor/symfony/event-dispatcher/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +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 ----- diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php index 9ec9a34696..7716d86631 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\BrowserKit\Request; 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\RequestStack; use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; /** * Collects some data about event listeners. @@ -33,14 +39,17 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface 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; } /** @@ -121,37 +130,52 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface /** * {@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); } @@ -160,18 +184,22 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface /** * {@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); + list($eventName, $requestHash) = $this->callStack->getInfo(); + if (null === $hash || $hash === $requestHash) { + $called[] = $listener->getInfo($eventName); + } } return $called; @@ -179,8 +207,10 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface /** * {@inheritdoc} + * + * @param Request|null $request The request to get listeners for */ - public function getNotCalledListeners() + public function getNotCalledListeners(/* Request $request = null */) { try { $allListeners = $this->getListeners(); @@ -193,13 +223,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface return []; } + $hash = 1 <= \func_num_args() && null !== ($request = \func_get_arg(0)) ? spl_object_hash($request) : null; $notCalled = []; foreach ($allListeners as $eventName => $listeners) { foreach ($listeners as $listener) { $called = false; if (null !== $this->callStack) { foreach ($this->callStack as $calledListener) { - if ($calledListener->getWrappedListener() === $listener) { + list(, $requestHash) = $this->callStack->getInfo(); + if ((null === $hash || $hash === $requestHash) && $calledListener->getWrappedListener() === $listener) { $called = true; break; @@ -221,15 +253,27 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface return $notCalled; } - public function getOrphanedEvents(): array + /** + * @param Request|null $request The request to get orphaned events for + */ + public function getOrphanedEvents(/* Request $request = null */): array { - return $this->orphanedEvents; + 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 = ''; } /** @@ -248,18 +292,32 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface /** * 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) { @@ -268,7 +326,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface private function preProcess($eventName) { if (!$this->dispatcher->hasListeners($eventName)) { - $this->orphanedEvents[] = $eventName; + $this->orphanedEvents[$this->currentRequestHash][] = $eventName; return; } @@ -279,7 +337,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface $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]); } } diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php index cd4d7470af..4fedb9a413 100644 --- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php @@ -12,6 +12,7 @@ namespace Symfony\Component\EventDispatcher\Debug; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; use Symfony\Contracts\Service\ResetInterface; /** @@ -24,14 +25,18 @@ interface TraceableEventDispatcherInterface extends EventDispatcherInterface, Re /** * 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 24e2bb4324..e047639081 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 <fabien@symfony.com> + * + * @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; @@ -105,6 +112,10 @@ class WrappedListener 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 @@ class WrappedListener $e = $this->stopwatch->start($this->name, 'event_listener'); - ($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/RegisterListenersPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php index cf2e93aec0..3e6493eb83 100644 --- a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php +++ b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -27,15 +27,17 @@ class RegisterListenersPass implements CompilerPassInterface protected $dispatcherService; protected $listenerTag; protected $subscriberTag; + protected $eventAliasesParameter; private $hotPathEvents = []; private $hotPathTagName; - public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $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') @@ -52,6 +54,12 @@ class RegisterListenersPass implements CompilerPassInterface return; } + if ($container->hasParameter($this->eventAliasesParameter)) { + $aliases = $container->getParameter($this->eventAliasesParameter); + $container->getParameterBag()->remove($this->eventAliasesParameter); + } else { + $aliases = []; + } $definition = $container->findDefinition($this->dispatcherService); foreach ($container->findTaggedServiceIds($this->listenerTag, true) as $id => $events) { @@ -61,6 +69,7 @@ class RegisterListenersPass implements CompilerPassInterface if (!isset($event['event'])) { throw new InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag)); } + $event['event'] = $aliases[$event['event']] ?? $event['event']; if (!isset($event['method'])) { $event['method'] = 'on'.preg_replace_callback([ @@ -98,6 +107,7 @@ class RegisterListenersPass implements CompilerPassInterface } $class = $r->name; + ExtractingEventDispatcher::$aliases = $aliases; ExtractingEventDispatcher::$subscriber = $class; $extractingDispatcher->addSubscriber($extractingDispatcher); foreach ($extractingDispatcher->listeners as $args) { @@ -109,6 +119,7 @@ class RegisterListenersPass implements CompilerPassInterface } } $extractingDispatcher->listeners = []; + ExtractingEventDispatcher::$aliases = []; } } } @@ -120,6 +131,7 @@ class ExtractingEventDispatcher extends EventDispatcher implements EventSubscrib { public $listeners = []; + public static $aliases = []; public static $subscriber; public function addListener($eventName, $listener, $priority = 0) @@ -129,8 +141,12 @@ class ExtractingEventDispatcher extends EventDispatcher implements EventSubscrib public static function getSubscribedEvents() { - $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 9c56b2f55b..307c4be5de 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 <guilhermeblanco@hotmail.com> - * @author Jonathan Wage <jonwage@gmail.com> - * @author Roman Borschel <roman@code-factory.org> - * @author Bernhard Schussek <bschussek@gmail.com> + * @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 @@ class Event } /** - * 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 afc443b283..e68918c31c 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,45 @@ class EventDispatcher implements EventDispatcherInterface { private $listeners = []; private $sorted = []; + private $optimized; + + public function __construct() + { + if (__CLASS__ === \get_class($this)) { + $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); + } 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 ($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; @@ -86,11 +117,10 @@ class EventDispatcher implements EventDispatcherInterface $listener[0] = $listener[0](); } - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $v) { + foreach ($this->listeners[$eventName] as $priority => &$listeners) { + foreach ($listeners as &$v) { if ($v !== $listener && \is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) { $v[0] = $v[0](); - $this->listeners[$eventName][$priority][$k] = $v; } if ($v === $listener) { return $priority; @@ -123,7 +153,7 @@ class EventDispatcher implements EventDispatcherInterface public function addListener($eventName, $listener, $priority = 0) { $this->listeners[$eventName][$priority][] = $listener; - unset($this->sorted[$eventName]); + unset($this->sorted[$eventName], $this->optimized[$eventName]); } /** @@ -139,21 +169,17 @@ class EventDispatcher implements EventDispatcherInterface $listener[0] = $listener[0](); } - foreach ($this->listeners[$eventName] as $priority => $listeners) { - foreach ($listeners as $k => $v) { + 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) { $v[0] = $v[0](); } if ($v === $listener) { - unset($listeners[$k], $this->sorted[$eventName]); - } else { - $listeners[$k] = $v; + unset($listeners[$k], $this->sorted[$eventName], $this->optimized[$eventName]); } } - if ($listeners) { - $this->listeners[$eventName][$priority] = $listeners; - } else { + if (!$listeners) { unset($this->listeners[$eventName][$priority]); } } @@ -201,7 +227,29 @@ class EventDispatcher implements EventDispatcherInterface * * @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) { @@ -215,22 +263,46 @@ class EventDispatcher implements EventDispatcherInterface /** * 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 ($this->listeners[$eventName] as &$listeners) { foreach ($listeners as $k => $listener) { if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { $listener[0] = $listener[0](); - $this->listeners[$eventName][$priority][$k] = $listener; } $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) { + $closure = static function (...$args) use (&$listener, &$closure) { + if ($listener[0] instanceof \Closure) { + $listener[0] = $listener[0](); + } + ($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 bde753a12f..ceaa62aeb0 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,22 +20,9 @@ namespace Symfony\Component\EventDispatcher; * * @author Bernhard Schussek <bschussek@gmail.com> */ -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. * * @param string $eventName The event to listen on diff --git a/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php b/vendor/symfony/event-dispatcher/ImmutableEventDispatcher.php index b3cf56c502..082e2a05d4 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/LegacyEventDispatcherProxy.php b/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php new file mode 100644 index 0000000000..3ae3735e23 --- /dev/null +++ b/vendor/symfony/event-dispatcher/LegacyEventDispatcherProxy.php @@ -0,0 +1,147 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; + +/** + * An 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 <p@tchwork.com> + */ +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 + */ + 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); + } 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.', ContractsEventDispatcherInterface::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.', ContractsEventDispatcherInterface::class, Event::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) + { + return $this->dispatcher->getListeners($eventName); + } + + /** + * {@inheritdoc} + */ + public function getListenerPriority($eventName, $listener) + { + return $this->dispatcher->getListenerPriority($eventName, $listener); + } + + /** + * {@inheritdoc} + */ + public function hasListeners($eventName = null) + { + 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 0000000000..cad8cfaedb --- /dev/null +++ b/vendor/symfony/event-dispatcher/LegacyEventProxy.php @@ -0,0 +1,62 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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() + { + 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/Tests/AbstractEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php deleted file mode 100644 index b157659dc0..0000000000 --- a/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php +++ /dev/null @@ -1,442 +0,0 @@ -<?php - -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * 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/bug.php?id=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/ChildEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ChildEventDispatcherTest.php new file mode 100644 index 0000000000..442b88fbb3 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/ChildEventDispatcherTest.php @@ -0,0 +1,26 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 ChildEventDispatcherTest extends EventDispatcherTest +{ + protected function createEventDispatcher() + { + return new ChildEventDispatcher(); + } +} + +class ChildEventDispatcher extends EventDispatcher +{ +} diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php index 9a3697a36f..ea476eee04 100644 --- a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -18,6 +18,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\Stopwatch\Stopwatch; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; class TraceableEventDispatcherTest extends TestCase { @@ -69,7 +70,7 @@ class TraceableEventDispatcherTest extends TestCase // Verify that priority is preserved when listener is removed and re-added // in preProcess() and postProcess(). - $tdispatcher->dispatch('foo', new Event()); + $tdispatcher->dispatch(new Event(), 'foo'); $listeners = $dispatcher->getListeners('foo'); $this->assertSame(123, $tdispatcher->getListenerPriority('foo', $listeners[0])); } @@ -84,7 +85,7 @@ class TraceableEventDispatcherTest extends TestCase }; $tdispatcher->addListener('bar', $listener, 5); - $tdispatcher->dispatch('bar'); + $tdispatcher->dispatch(new Event(), 'bar'); $this->assertSame(5, $priorityWhileDispatching); } @@ -115,7 +116,7 @@ class TraceableEventDispatcherTest extends TestCase $this->assertEquals([], $tdispatcher->getCalledListeners()); $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $listeners = $tdispatcher->getCalledListeners(); $this->assertArrayHasKey('stub', $listeners[0]); @@ -129,7 +130,7 @@ class TraceableEventDispatcherTest extends TestCase $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); $tdispatcher->addListener('foo', function () {}, 5); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $tdispatcher->reset(); $listeners = $tdispatcher->getNotCalledListeners(); @@ -139,13 +140,26 @@ class TraceableEventDispatcherTest extends TestCase $this->assertEquals([['event' => 'foo', 'pretty' => 'closure', 'priority' => 5]], $listeners); } + public function testDispatchContractsEvent() + { + $expectedEvent = new ContractsEvent(); + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $tdispatcher->addListener('foo', function ($event) use ($expectedEvent) { + $this->assertSame($event, $expectedEvent); + }, 5); + $tdispatcher->dispatch($expectedEvent, 'foo'); + + $listeners = $tdispatcher->getCalledListeners(); + $this->assertArrayHasKey('stub', $listeners[0]); + } + public function testDispatchAfterReset() { $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); $tdispatcher->addListener('foo', function () {}, 5); $tdispatcher->reset(); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $listeners = $tdispatcher->getCalledListeners(); $this->assertArrayHasKey('stub', $listeners[0]); @@ -157,10 +171,10 @@ class TraceableEventDispatcherTest extends TestCase $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); $dispatcher->addListener('foo', function (Event $event, $eventName, $dispatcher) use (&$tdispatcher) { $tdispatcher = $dispatcher; - $dispatcher->dispatch('bar'); + $dispatcher->dispatch(new Event(), 'bar'); }); $dispatcher->addListener('bar', function (Event $event) {}); - $dispatcher->dispatch('foo'); + $dispatcher->dispatch(new Event(), 'foo'); $this->assertSame($dispatcher, $tdispatcher); $this->assertCount(2, $dispatcher->getCalledListeners()); } @@ -175,7 +189,7 @@ class TraceableEventDispatcherTest extends TestCase public function testItReturnsOrphanedEventsAfterDispatch() { $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $events = $tdispatcher->getOrphanedEvents(); $this->assertCount(1, $events); $this->assertEquals(['foo'], $events); @@ -185,7 +199,7 @@ class TraceableEventDispatcherTest extends TestCase { $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); $tdispatcher->addListener('foo', function () {}); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $events = $tdispatcher->getOrphanedEvents(); $this->assertEmpty($events); } @@ -202,7 +216,7 @@ class TraceableEventDispatcherTest extends TestCase $logger->expects($this->at(0))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']); $logger->expects($this->at(1))->method('debug')->with('Notified event "{event}" to listener "{listener}".', ['event' => 'foo', 'listener' => 'closure']); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); } public function testLoggerWithStoppedEvent() @@ -218,7 +232,7 @@ class TraceableEventDispatcherTest extends TestCase $logger->expects($this->at(1))->method('debug')->with('Listener "{listener}" stopped propagation of the event "{event}".', ['event' => 'foo', 'listener' => 'closure']); $logger->expects($this->at(2))->method('debug')->with('Listener "{listener}" was not called for event "{event}".', ['event' => 'foo', 'listener' => 'closure']); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); } public function testDispatchCallListeners() @@ -230,7 +244,7 @@ class TraceableEventDispatcherTest extends TestCase $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo1'; }, 10); $tdispatcher->addListener('foo', function () use (&$called) { $called[] = 'foo2'; }, 20); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $this->assertSame(['foo2', 'foo1'], $called); } @@ -243,14 +257,14 @@ class TraceableEventDispatcherTest extends TestCase $dispatcher->addListener('foo', $listener1 = function () use ($dispatcher, &$loop) { ++$loop; if (2 == $loop) { - $dispatcher->dispatch('foo'); + $dispatcher->dispatch(new Event(), 'foo'); } }); $dispatcher->addListener('foo', function () use (&$dispatchedEvents) { ++$dispatchedEvents; }); - $dispatcher->dispatch('foo'); + $dispatcher->dispatch(new Event(), 'foo'); $this->assertSame(2, $dispatchedEvents); } @@ -260,14 +274,14 @@ class TraceableEventDispatcherTest extends TestCase $nestedCall = false; $dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); $dispatcher->addListener('foo', function (Event $e) use ($dispatcher) { - $dispatcher->dispatch('bar', $e); + $dispatcher->dispatch(new Event(), 'bar', $e); }); $dispatcher->addListener('bar', function (Event $e) use (&$nestedCall) { $nestedCall = true; }); $this->assertFalse($nestedCall); - $dispatcher->dispatch('foo'); + $dispatcher->dispatch(new Event(), 'foo'); $this->assertTrue($nestedCall); } @@ -279,7 +293,7 @@ class TraceableEventDispatcherTest extends TestCase }; $eventDispatcher->addListener('foo', $listener1); $eventDispatcher->addListener('foo', function () {}); - $eventDispatcher->dispatch('foo'); + $eventDispatcher->dispatch(new Event(), 'foo'); $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); } @@ -287,7 +301,7 @@ class TraceableEventDispatcherTest extends TestCase public function testClearOrphanedEvents() { $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); - $tdispatcher->dispatch('foo'); + $tdispatcher->dispatch(new Event(), 'foo'); $events = $tdispatcher->getOrphanedEvents(); $this->assertCount(1, $events); $tdispatcher->reset(); diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php index 56792fe33a..75e9012073 100644 --- a/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php +++ b/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php @@ -21,7 +21,7 @@ class WrappedListenerTest extends TestCase /** * @dataProvider provideListenersToDescribe */ - public function testListenerDescription(callable $listener, $expected) + public function testListenerDescription($listener, $expected) { $wrappedListener = new WrappedListener($listener, null, $this->getMockBuilder(Stopwatch::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock()); @@ -34,6 +34,7 @@ class WrappedListenerTest extends TestCase [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'], + [['Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'invalidMethod'], 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::invalidMethod'], ['var_dump', 'var_dump'], [function () {}, 'closure'], [\Closure::fromCallable([new FooListener(), 'listen']), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen'], diff --git a/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php index 5faa5c8be8..e89f78cda8 100644 --- a/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php +++ b/vendor/symfony/event-dispatcher/Tests/EventDispatcherTest.php @@ -11,12 +11,476 @@ namespace Symfony\Component\EventDispatcher\Tests; +use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Contracts\EventDispatcher\Event as ContractsEvent; -class EventDispatcherTest extends AbstractEventDispatcherTest +class EventDispatcherTest 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; + } + protected function createEventDispatcher() { return new EventDispatcher(); } + + 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(new Event(), self::preFoo); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), 'noevent')); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), self::preFoo)); + $event = new Event(); + $return = $this->dispatcher->dispatch($event, self::preFoo); + $this->assertSame($event, $return); + } + + public function testDispatchContractsEvent() + { + $this->dispatcher->addListener('pre.foo', [$this->listener, 'preFoo']); + $this->dispatcher->addListener('post.foo', [$this->listener, 'postFoo']); + $this->dispatcher->dispatch(new ContractsEvent(), self::preFoo); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), 'noevent')); + $this->assertInstanceOf('Symfony\Component\EventDispatcher\Event', $this->dispatcher->dispatch(new Event(), self::preFoo)); + $event = new Event(); + $return = $this->dispatcher->dispatch($event, self::preFoo); + $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(new Event(), 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(new Event(), 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(new Event(), 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(new Event(), 'test'); + $this->assertEquals('test', $listener->name); + $this->assertSame($this->dispatcher, $listener->dispatcher); + } + + /** + * @see https://bugs.php.net/bug.php?id=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(new Event(), 'foo'); + $this->dispatcher->dispatch(new Event(), 'foo'); + $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()); + } + + public function testMutatingWhilePropagationIsStopped() + { + $testLoaded = false; + $test = new TestEventListener(); + $this->dispatcher->addListener('foo', [$test, 'postFoo']); + $this->dispatcher->addListener('foo', [function () use ($test, &$testLoaded) { + $testLoaded = true; + + return $test; + }, 'preFoo']); + + $this->dispatcher->dispatch(new Event(), 'foo'); + + $this->assertTrue($test->postFooInvoked); + $this->assertFalse($test->preFooInvoked); + + $this->assertsame(0, $this->dispatcher->getListenerPriority('foo', [$test, 'preFoo'])); + + $test->preFoo(new Event()); + $this->dispatcher->dispatch(new Event(), 'foo'); + + $this->assertTrue($testLoaded); + } +} + +class CallableClass +{ + public function __invoke() + { + } +} + +class TestEventListener +{ + public $preFooInvoked = false; + public $postFooInvoked = false; + + /* Listener methods */ + + public function preFoo($e) + { + $this->preFooInvoked = true; + } + + public function postFoo($e) + { + $this->postFooInvoked = true; + + if (!$this->preFooInvoked) { + $e->stopPropagation(); + } + } +} + +class TestWithDispatcher +{ + public $name; + public $dispatcher; + + public function foo($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/EventTest.php b/vendor/symfony/event-dispatcher/Tests/EventTest.php index 5be2ea09f9..ca8e945c64 100644 --- a/vendor/symfony/event-dispatcher/Tests/EventTest.php +++ b/vendor/symfony/event-dispatcher/Tests/EventTest.php @@ -15,7 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\Event; /** - * Test class for Event. + * @group legacy */ class EventTest extends TestCase { diff --git a/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php b/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php index 461f86161e..e9e011a29d 100644 --- a/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php +++ b/vendor/symfony/event-dispatcher/Tests/GenericEventTest.php @@ -92,7 +92,7 @@ class GenericEventTest extends TestCase $this->assertEquals('Event', $this->event['name']); // test getting invalid arg - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $this->assertFalse($this->event['nameNotExist']); } diff --git a/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php index 04f2861e33..c896facc14 100644 --- a/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php +++ b/vendor/symfony/event-dispatcher/Tests/ImmutableEventDispatcherTest.php @@ -42,10 +42,10 @@ class ImmutableEventDispatcherTest extends TestCase $this->innerDispatcher->expects($this->once()) ->method('dispatch') - ->with('event', $event) + ->with($event, 'event') ->will($this->returnValue('result')); - $this->assertSame('result', $this->dispatcher->dispatch('event', $event)); + $this->assertSame('result', $this->dispatcher->dispatch($event, 'event')); } public function testGetListenersDelegates() diff --git a/vendor/symfony/event-dispatcher/Tests/LegacyEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/LegacyEventDispatcherTest.php new file mode 100644 index 0000000000..49aa2f9ff3 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/LegacyEventDispatcherTest.php @@ -0,0 +1,35 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\Event; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; + +/** + * @group legacy + */ +class LegacyEventDispatcherTest extends EventDispatcherTest +{ + protected function createEventDispatcher() + { + return LegacyEventDispatcherProxy::decorate(new TestLegacyEventDispatcher()); + } +} + +class TestLegacyEventDispatcher extends EventDispatcher +{ + public function dispatch($eventName, Event $event = null) + { + return parent::dispatch($event, $eventName); + } +} diff --git a/vendor/symfony/event-dispatcher/composer.json b/vendor/symfony/event-dispatcher/composer.json index 6c75dfbb00..8449c4785d 100644 --- a/vendor/symfony/event-dispatcher/composer.json +++ b/vendor/symfony/event-dispatcher/composer.json @@ -17,18 +17,24 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0" + "symfony/event-dispatcher-contracts": "^1.1" }, "require-dev": { "symfony/dependency-injection": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/config": "~3.4|~4.0", + "symfony/http-foundation": "^3.4|^4.0", + "symfony/service-contracts": "^1.1", "symfony/stopwatch": "~3.4|~4.0", "psr/log": "~1.0" }, "conflict": { "symfony/dependency-injection": "<3.4" }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "1.1" + }, "suggest": { "symfony/dependency-injection": "", "symfony/http-kernel": "" @@ -42,7 +48,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/expression-language/composer.json b/vendor/symfony/expression-language/composer.json index 2e699629e8..bcab816043 100644 --- a/vendor/symfony/expression-language/composer.json +++ b/vendor/symfony/expression-language/composer.json @@ -18,7 +18,7 @@ "require": { "php": "^7.1.3", "symfony/cache": "~3.4|~4.0", - "symfony/contracts": "^1.0" + "symfony/service-contracts": "^1.1" }, "autoload": { "psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" }, @@ -29,7 +29,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/http-foundation/BinaryFileResponse.php b/vendor/symfony/http-foundation/BinaryFileResponse.php index 115f486f02..e217820950 100644 --- a/vendor/symfony/http-foundation/BinaryFileResponse.php +++ b/vendor/symfony/http-foundation/BinaryFileResponse.php @@ -223,12 +223,17 @@ class BinaryFileResponse extends Response list($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 { + $this->headers->set($type, $path); + $this->maxlen = 0; } - $this->headers->set($type, $path); - $this->maxlen = 0; } elseif ($request->headers->has('Range')) { // Process the range headers. if (!$request->headers->has('If-Range') || $this->hasValidIfRangeHeader($request->headers->get('If-Range'))) { diff --git a/vendor/symfony/http-foundation/CHANGELOG.md b/vendor/symfony/http-foundation/CHANGELOG.md index 88ebc33a5d..54acd6ae10 100644 --- a/vendor/symfony/http-foundation/CHANGELOG.md +++ b/vendor/symfony/http-foundation/CHANGELOG.md @@ -1,6 +1,17 @@ CHANGELOG ========= +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 ----- diff --git a/vendor/symfony/http-foundation/Cookie.php b/vendor/symfony/http-foundation/Cookie.php index 0ba6037d7c..e6b8b798f2 100644 --- a/vendor/symfony/http-foundation/Cookie.php +++ b/vendor/symfony/http-foundation/Cookie.php @@ -29,6 +29,7 @@ class Cookie private $sameSite; private $secureDefault = false; + const SAMESITE_NONE = 'none'; const SAMESITE_LAX = 'lax'; const SAMESITE_STRICT = 'strict'; @@ -126,7 +127,7 @@ class Cookie $sameSite = strtolower($sameSite); } - if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, null], true)) { + if (!\in_array($sameSite, [self::SAMESITE_LAX, self::SAMESITE_STRICT, self::SAMESITE_NONE, null], true)) { throw new \InvalidArgumentException('The "sameSite" parameter value is not valid.'); } diff --git a/vendor/symfony/http-foundation/File/File.php b/vendor/symfony/http-foundation/File/File.php index de7b080973..396ff3450e 100644 --- a/vendor/symfony/http-foundation/File/File.php +++ b/vendor/symfony/http-foundation/File/File.php @@ -13,8 +13,7 @@ namespace Symfony\Component\HttpFoundation\File; 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. @@ -50,33 +49,28 @@ class File extends \SplFileInfo * * @return string|null The guessed extension or null if it cannot be guessed * - * @see ExtensionGuesser + * @see MimeTypes * @see getMimeType() */ public function guessExtension() { - $type = $this->getMimeType(); - $guesser = ExtensionGuesser::getInstance(); - - 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") * - * @see MimeTypeGuesser + * @see MimeTypes */ public function getMimeType() { - $guesser = MimeTypeGuesser::getInstance(); - - return $guesser->guess($this->getPathname()); + return MimeTypes::getDefault()->guessMimeType($this->getPathname()); } /** diff --git a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php b/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php index 80f4d47f76..06e5b4620c 100644 --- a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesser.php @@ -11,6 +11,10 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; +use Symfony\Component\Mime\MimeTypes; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', ExtensionGuesser::class, MimeTypes::class), E_USER_DEPRECATED); + /** * A singleton mime type to file extension guesser. * @@ -22,6 +26,8 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; * $guesser->register(new MyCustomExtensionGuesser()); * * The last registered guesser is preferred over previously registered ones. + * + * @deprecated since Symfony 4.3, use {@link MimeTypes} instead */ class ExtensionGuesser implements ExtensionGuesserInterface { diff --git a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php b/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php index d19a0e5371..69fe6efb28 100644 --- a/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php +++ b/vendor/symfony/http-foundation/File/MimeType/ExtensionGuesserInterface.php @@ -11,8 +11,12 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; +use Symfony\Component\Mime\MimeTypesInterface; + /** * Guesses the file extension corresponding to a given mime type. + * + * @deprecated since Symfony 4.3, use {@link MimeTypesInterface} instead */ interface ExtensionGuesserInterface { diff --git a/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php index 313000195d..b4d51023cb 100644 --- a/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php @@ -13,11 +13,16 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; +use Symfony\Component\Mime\FileBinaryMimeTypeGuesser as NewFileBinaryMimeTypeGuesser; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', FileBinaryMimeTypeGuesser::class, NewFileBinaryMimeTypeGuesser::class), E_USER_DEPRECATED); /** * Guesses the mime type with the binary "file" (only available on *nix). * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, use {@link NewFileBinaryMimeTypeGuesser} instead */ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface { diff --git a/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php index cee9ef3f72..bb32370175 100644 --- a/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php @@ -13,11 +13,16 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; +use Symfony\Component\Mime\FileinfoMimeTypeGuesser as NewFileinfoMimeTypeGuesser; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', FileinfoMimeTypeGuesser::class, NewFileinfoMimeTypeGuesser::class), E_USER_DEPRECATED); /** * Guesses the mime type using the PECL extension FileInfo. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, use {@link NewFileinfoMimeTypeGuesser} instead */ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface { diff --git a/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php b/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php index c0f9140c80..651be070e1 100644 --- a/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/MimeTypeExtensionGuesser.php @@ -11,8 +11,14 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; +use Symfony\Component\Mime\MimeTypes; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', MimeTypeExtensionGuesser::class, MimeTypes::class), E_USER_DEPRECATED); + /** * Provides a best-guess mapping of mime type to file extension. + * + * @deprecated since Symfony 4.3, use {@link MimeTypes} instead */ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface { @@ -639,6 +645,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'audio/x-aiff' => 'aif', 'audio/x-caf' => 'caf', 'audio/x-flac' => 'flac', + 'audio/x-hx-aac-adts' => 'aac', 'audio/x-matroska' => 'mka', 'audio/x-mpegurl' => 'm3u', 'audio/x-ms-wax' => 'wax', diff --git a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php index 95d1ee2676..2b30a62a5e 100644 --- a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesser.php @@ -13,6 +13,9 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; +use Symfony\Component\Mime\MimeTypes; + +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', MimeTypeGuesser::class, MimeTypes::class), E_USER_DEPRECATED); /** * A singleton mime type guesser. diff --git a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php b/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php index 5ac1acb823..0f048b5332 100644 --- a/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php +++ b/vendor/symfony/http-foundation/File/MimeType/MimeTypeGuesserInterface.php @@ -13,11 +13,14 @@ namespace Symfony\Component\HttpFoundation\File\MimeType; use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; +use Symfony\Component\Mime\MimeTypesInterface; /** * Guesses the mime type of a file. * * @author Bernhard Schussek <bschussek@gmail.com> + * + * @deprecated since Symfony 4.3, use {@link MimeTypesInterface} instead */ interface MimeTypeGuesserInterface { diff --git a/vendor/symfony/http-foundation/File/UploadedFile.php b/vendor/symfony/http-foundation/File/UploadedFile.php index efe00d64cc..568d192fc7 100644 --- a/vendor/symfony/http-foundation/File/UploadedFile.php +++ b/vendor/symfony/http-foundation/File/UploadedFile.php @@ -20,7 +20,7 @@ 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\HttpFoundation\File\MimeType\ExtensionGuesser; +use Symfony\Component\Mime\MimeTypes; /** * A file uploaded through a form. @@ -140,10 +140,7 @@ class UploadedFile extends File */ public function guessClientExtension() { - $type = $this->getClientMimeType(); - $guesser = ExtensionGuesser::getInstance(); - - return $guesser->guess($type); + return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null; } /** diff --git a/vendor/symfony/http-foundation/FileBag.php b/vendor/symfony/http-foundation/FileBag.php index 14fbc7aa9d..efd83ffeb8 100644 --- a/vendor/symfony/http-foundation/FileBag.php +++ b/vendor/symfony/http-foundation/FileBag.php @@ -84,7 +84,7 @@ class FileBag extends ParameterBag if (UPLOAD_ERR_NO_FILE == $file['error']) { $file = null; } else { - $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); + $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error'], false); } } else { $file = array_map([$this, 'convertFileInformation'], $file); diff --git a/vendor/symfony/http-foundation/Request.php b/vendor/symfony/http-foundation/Request.php index 2b4fc0c02e..fffe2ab81e 100644 --- a/vendor/symfony/http-foundation/Request.php +++ b/vendor/symfony/http-foundation/Request.php @@ -1907,7 +1907,7 @@ class Request } } - /* + /** * Returns the prefix as encoded in the string when the string starts with * the given prefix, false otherwise. * diff --git a/vendor/symfony/http-foundation/ResponseHeaderBag.php b/vendor/symfony/http-foundation/ResponseHeaderBag.php index 9e07221933..cf44d0eceb 100644 --- a/vendor/symfony/http-foundation/ResponseHeaderBag.php +++ b/vendor/symfony/http-foundation/ResponseHeaderBag.php @@ -122,8 +122,7 @@ class ResponseHeaderBag extends HeaderBag 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); diff --git a/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php b/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php index 2bd1d62bdb..99e8074214 100644 --- a/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php +++ b/vendor/symfony/http-foundation/Session/Flash/FlashBagInterface.php @@ -21,7 +21,7 @@ use Symfony\Component\HttpFoundation\Session\SessionBagInterface; interface FlashBagInterface extends SessionBagInterface { /** - * Adds a flash message for type. + * Adds a flash message for the given type. * * @param string $type * @param mixed $message @@ -29,12 +29,12 @@ interface FlashBagInterface extends SessionBagInterface public function add($type, $message); /** - * Registers a message for a given type. + * Registers one or more messages for a given type. * * @param string $type - * @param string|array $message + * @param string|array $messages */ - public function set($type, $message); + public function set($type, $messages); /** * Gets flash messages for a given type. 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 0000000000..2d10562786 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/RequestAttributeValueSame.php @@ -0,0 +1,54 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; + +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 0000000000..554e1a1602 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseCookieValueSame.php @@ -0,0 +1,85 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 === $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/ResponseHasCookie.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php new file mode 100644 index 0000000000..bd792b0d87 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasCookie.php @@ -0,0 +1,77 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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(); + } + + 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/ResponseHasHeader.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php new file mode 100644 index 0000000000..68ad8273fd --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseHasHeader.php @@ -0,0 +1,53 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 0000000000..acdea71d15 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseHeaderSame.php @@ -0,0 +1,55 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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, true); + } + + /** + * @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 0000000000..8c4b883f0b --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsRedirected.php @@ -0,0 +1,56 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 0000000000..9c66558907 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseIsSuccessful.php @@ -0,0 +1,56 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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/ResponseStatusCodeSame.php b/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php new file mode 100644 index 0000000000..72bb000b85 --- /dev/null +++ b/vendor/symfony/http-foundation/Test/Constraint/ResponseStatusCodeSame.php @@ -0,0 +1,63 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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/BinaryFileResponseTest.php b/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php index 9f3beb08d1..effffe925b 100644 --- a/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php +++ b/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php @@ -339,6 +339,7 @@ class BinaryFileResponseTest extends ResponseTestCase ['/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'], ['/home/Foo/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', '/baz/bar.txt'], + ['/tmp/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', null], ]; } diff --git a/vendor/symfony/http-foundation/Tests/File/FileTest.php b/vendor/symfony/http-foundation/Tests/File/FileTest.php index fb82dae768..9c1854d902 100644 --- a/vendor/symfony/http-foundation/Tests/File/FileTest.php +++ b/vendor/symfony/http-foundation/Tests/File/FileTest.php @@ -13,8 +13,10 @@ namespace Symfony\Component\HttpFoundation\Tests\File; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\File\File; -use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; +/** + * @requires extension fileinfo + */ class FileTest extends TestCase { protected $file; @@ -22,50 +24,24 @@ class FileTest extends TestCase 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->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); - + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); new File(__DIR__.'/Fixtures/not_here'); } @@ -164,17 +140,4 @@ class FileTest extends TestCase @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)) - ->will($this->returnValue($mimeType)) - ; - - return $guesser; - } } diff --git a/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php b/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php index bb88807ab0..f990a4f3b5 100644 --- a/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php +++ b/vendor/symfony/http-foundation/Tests/File/MimeType/MimeTypeTest.php @@ -17,11 +17,10 @@ use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; /** * @requires extension fileinfo + * @group legacy */ class MimeTypeTest extends TestCase { - protected $path; - public function testGuessImageWithoutExtension() { $this->assertEquals('image/gif', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test')); @@ -29,7 +28,7 @@ class MimeTypeTest extends TestCase public function testGuessImageWithDirectory() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/directory'); } @@ -53,7 +52,7 @@ class MimeTypeTest extends TestCase public function testGuessWithIncorrectPath() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/not_here'); } @@ -72,7 +71,7 @@ class MimeTypeTest extends TestCase @chmod($path, 0333); if ('0333' == substr(sprintf('%o', fileperms($path)), -4)) { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException'); + $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'); diff --git a/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php b/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php index 8f5f48a066..8518df266e 100644 --- a/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php +++ b/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php @@ -33,7 +33,7 @@ class UploadedFileTest extends TestCase public function testConstructWhenFileNotExists() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); + $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); new UploadedFile( __DIR__.'/Fixtures/not_here', diff --git a/vendor/symfony/http-foundation/Tests/JsonResponseTest.php b/vendor/symfony/http-foundation/Tests/JsonResponseTest.php index 03a7b7d9b8..261c9d3e05 100644 --- a/vendor/symfony/http-foundation/Tests/JsonResponseTest.php +++ b/vendor/symfony/http-foundation/Tests/JsonResponseTest.php @@ -43,7 +43,8 @@ class JsonResponseTest extends TestCase $this->assertSame('0', $response->getContent()); $response = new JsonResponse(0.1); - $this->assertSame('0.1', $response->getContent()); + $this->assertEquals('0.1', $response->getContent()); + $this->assertInternalType('string', $response->getContent()); $response = new JsonResponse(true); $this->assertSame('true', $response->getContent()); @@ -131,7 +132,8 @@ class JsonResponseTest extends TestCase $response = JsonResponse::create(0.1); $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); - $this->assertSame('0.1', $response->getContent()); + $this->assertEquals('0.1', $response->getContent()); + $this->assertInternalType('string', $response->getContent()); $response = JsonResponse::create(true); $this->assertInstanceOf('Symfony\Component\HttpFoundation\JsonResponse', $response); diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php new file mode 100644 index 0000000000..eca8aed263 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/RequestAttributeValueSameTest.php @@ -0,0 +1,41 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Test\Constraint\RequestAttributeValueSame; + +class RequestAttributeValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $request = new Request(); + $request->attributes->set('foo', 'bar'); + $constraint = new RequestAttributeValueSame('foo', 'bar'); + $this->assertTrue($constraint->evaluate($request, '', true)); + $constraint = new RequestAttributeValueSame('bar', 'foo'); + $this->assertFalse($constraint->evaluate($request, '', true)); + + try { + $constraint->evaluate($request); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Request has attribute \"bar\" with value \"foo\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php new file mode 100644 index 0000000000..778879c328 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseCookieValueSameTest.php @@ -0,0 +1,44 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseCookieValueSame; + +class ResponseCookieValueSameTest extends TestCase +{ + public function testConstraint(): void + { + $response = new Response(); + $response->headers->setCookie(Cookie::create('foo', 'bar', 0, '/path')); + $constraint = new ResponseCookieValueSame('foo', 'bar', '/path'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseCookieValueSame('foo', 'bar', '/path'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseCookieValueSame('foo', 'babar', '/path'); + $this->assertFalse($constraint->evaluate($response, '', true)); + + try { + $constraint->evaluate($response); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has cookie \"foo\" with path \"/path\" with value \"babar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHasCookieTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHasCookieTest.php new file mode 100644 index 0000000000..05ca95fb46 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHasCookieTest.php @@ -0,0 +1,42 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Cookie; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasCookie; + +class ResponseHasCookieTest extends TestCase +{ + public function testConstraint(): void + { + $response = new Response(); + $response->headers->setCookie(Cookie::create('foo', 'bar')); + $constraint = new ResponseHasCookie('foo'); + $this->assertTrue($constraint->evaluate($response, '', true)); + $constraint = new ResponseHasCookie('bar'); + $this->assertFalse($constraint->evaluate($response, '', true)); + + try { + $constraint->evaluate($response); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has cookie \"bar\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHasHeaderTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHasHeaderTest.php new file mode 100644 index 0000000000..7b811a64a2 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHasHeaderTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHasHeader; + +class ResponseHasHeaderTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseHasHeader('Date'); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $constraint = new ResponseHasHeader('X-Date'); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has header \"X-Date\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHeaderSameTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHeaderSameTest.php new file mode 100644 index 0000000000..d527f35de8 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseHeaderSameTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseHeaderSame; + +class ResponseHeaderSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseHeaderSame('Cache-Control', 'no-cache, private'); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $constraint = new ResponseHeaderSame('Cache-Control', 'public'); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertEquals("Failed asserting that the Response has header \"Cache-Control\" with value \"public\".\n", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php new file mode 100644 index 0000000000..a3a460636a --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseIsRedirectedTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsRedirected; + +class ResponseIsRedirectedTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseIsRedirected(); + + $this->assertTrue($constraint->evaluate(new Response('', 301), '', true)); + $this->assertFalse($constraint->evaluate(new Response(), '', true)); + + try { + $constraint->evaluate(new Response()); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response is redirected.\nHTTP/1.0 200 OK", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php new file mode 100644 index 0000000000..0c99a5e484 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseIsSuccessfulTest.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseIsSuccessful; + +class ResponseIsSuccessfulTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseIsSuccessful(); + + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $this->assertFalse($constraint->evaluate(new Response('', 404), '', true)); + + try { + $constraint->evaluate(new Response('', 404)); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response is successful.\nHTTP/1.0 404 Not Found", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php new file mode 100644 index 0000000000..3e15e90673 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Test/Constraint/ResponseStatusCodeSameTest.php @@ -0,0 +1,41 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Test\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestFailure; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\Test\Constraint\ResponseStatusCodeSame; + +class ResponseStatusCodeSameTest extends TestCase +{ + public function testConstraint(): void + { + $constraint = new ResponseStatusCodeSame(200); + $this->assertTrue($constraint->evaluate(new Response(), '', true)); + $this->assertFalse($constraint->evaluate(new Response('', 404), '', true)); + $constraint = new ResponseStatusCodeSame(404); + $this->assertTrue($constraint->evaluate(new Response('', 404), '', true)); + + $constraint = new ResponseStatusCodeSame(200); + try { + $constraint->evaluate(new Response('', 404)); + } catch (ExpectationFailedException $e) { + $this->assertContains("Failed asserting that the Response status code is 200.\nHTTP/1.0 404 Not Found", TestFailure::exceptionToString($e)); + + return; + } + + $this->fail(); + } +} diff --git a/vendor/symfony/http-foundation/Tests/UrlHelperTest.php b/vendor/symfony/http-foundation/Tests/UrlHelperTest.php new file mode 100644 index 0000000000..9a750bd8a3 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/UrlHelperTest.php @@ -0,0 +1,143 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; +use Symfony\Component\HttpFoundation\UrlHelper; +use Symfony\Component\Routing\RequestContext; + +class UrlHelperTest extends TestCase +{ + /** + * @dataProvider getGenerateAbsoluteUrlData() + */ + public function testGenerateAbsoluteUrl($expected, $path, $pathinfo) + { + $stack = new RequestStack(); + $stack->push(Request::create($pathinfo)); + $helper = new UrlHelper($stack); + + $this->assertEquals($expected, $helper->getAbsoluteUrl($path)); + } + + public function getGenerateAbsoluteUrlData() + { + return [ + ['http://localhost/foo.png', '/foo.png', '/foo/bar.html'], + ['http://localhost/foo/foo.png', 'foo.png', '/foo/bar.html'], + ['http://localhost/foo/foo.png', 'foo.png', '/foo/bar'], + ['http://localhost/foo/bar/foo.png', 'foo.png', '/foo/bar/'], + + ['http://example.com/baz', 'http://example.com/baz', '/'], + ['https://example.com/baz', 'https://example.com/baz', '/'], + ['//example.com/baz', '//example.com/baz', '/'], + + ['http://localhost/foo/bar?baz', '?baz', '/foo/bar'], + ['http://localhost/foo/bar?baz=1', '?baz=1', '/foo/bar?foo=1'], + ['http://localhost/foo/baz?baz=1', 'baz?baz=1', '/foo/bar?foo=1'], + + ['http://localhost/foo/bar#baz', '#baz', '/foo/bar'], + ['http://localhost/foo/bar?0#baz', '#baz', '/foo/bar?0'], + ['http://localhost/foo/bar?baz=1#baz', '?baz=1#baz', '/foo/bar?foo=1'], + ['http://localhost/foo/baz?baz=1#baz', 'baz?baz=1#baz', '/foo/bar?foo=1'], + ]; + } + + /** + * @dataProvider getGenerateAbsoluteUrlRequestContextData + */ + public function testGenerateAbsoluteUrlWithRequestContext($path, $baseUrl, $host, $scheme, $httpPort, $httpsPort, $expected) + { + if (!class_exists('Symfony\Component\Routing\RequestContext')) { + $this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.'); + } + + $requestContext = new RequestContext($baseUrl, 'GET', $host, $scheme, $httpPort, $httpsPort, $path); + $helper = new UrlHelper(new RequestStack(), $requestContext); + + $this->assertEquals($expected, $helper->getAbsoluteUrl($path)); + } + + /** + * @dataProvider getGenerateAbsoluteUrlRequestContextData + */ + public function testGenerateAbsoluteUrlWithoutRequestAndRequestContext($path) + { + if (!class_exists('Symfony\Component\Routing\RequestContext')) { + $this->markTestSkipped('The Routing component is needed to run tests that depend on its request context.'); + } + + $helper = new UrlHelper(new RequestStack()); + + $this->assertEquals($path, $helper->getAbsoluteUrl($path)); + } + + public function getGenerateAbsoluteUrlRequestContextData() + { + return [ + ['/foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo.png'], + ['foo.png', '/foo', 'localhost', 'http', 80, 443, 'http://localhost/foo/foo.png'], + ['foo.png', '/foo/bar/', 'localhost', 'http', 80, 443, 'http://localhost/foo/bar/foo.png'], + ['/foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo.png'], + ['foo.png', '/foo', 'localhost', 'https', 80, 443, 'https://localhost/foo/foo.png'], + ['foo.png', '/foo/bar/', 'localhost', 'https', 80, 443, 'https://localhost/foo/bar/foo.png'], + ['/foo.png', '/foo', 'localhost', 'http', 443, 80, 'http://localhost:443/foo.png'], + ['/foo.png', '/foo', 'localhost', 'https', 443, 80, 'https://localhost:80/foo.png'], + ]; + } + + public function testGenerateAbsoluteUrlWithScriptFileName() + { + $request = Request::create('http://localhost/app/web/app_dev.php'); + $request->server->set('SCRIPT_FILENAME', '/var/www/app/web/app_dev.php'); + + $stack = new RequestStack(); + $stack->push($request); + $helper = new UrlHelper($stack); + + $this->assertEquals( + 'http://localhost/app/web/bundles/framework/css/structure.css', + $helper->getAbsoluteUrl('/app/web/bundles/framework/css/structure.css') + ); + } + + /** + * @dataProvider getGenerateRelativePathData() + */ + public function testGenerateRelativePath($expected, $path, $pathinfo) + { + if (!method_exists('Symfony\Component\HttpFoundation\Request', 'getRelativeUriForPath')) { + $this->markTestSkipped('Your version of Symfony HttpFoundation is too old.'); + } + + $stack = new RequestStack(); + $stack->push(Request::create($pathinfo)); + $urlHelper = new UrlHelper($stack); + + $this->assertEquals($expected, $urlHelper->getRelativePath($path)); + } + + public function getGenerateRelativePathData() + { + return [ + ['../foo.png', '/foo.png', '/foo/bar.html'], + ['../baz/foo.png', '/baz/foo.png', '/foo/bar.html'], + ['baz/foo.png', 'baz/foo.png', '/foo/bar.html'], + + ['http://example.com/baz', 'http://example.com/baz', '/'], + ['https://example.com/baz', 'https://example.com/baz', '/'], + ['//example.com/baz', '//example.com/baz', '/'], + ]; + } +} diff --git a/vendor/symfony/http-foundation/UrlHelper.php b/vendor/symfony/http-foundation/UrlHelper.php new file mode 100644 index 0000000000..3c06e93217 --- /dev/null +++ b/vendor/symfony/http-foundation/UrlHelper.php @@ -0,0 +1,102 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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; + +/** + * A helper service for manipulating URLs within and outside the request scope. + * + * @author Valentin Udaltsov <udaltsov.valentin@gmail.com> + */ +final class UrlHelper +{ + private $requestStack; + private $requestContext; + + public function __construct(RequestStack $requestStack, ?RequestContext $requestContext = null) + { + $this->requestStack = $requestStack; + $this->requestContext = $requestContext; + } + + public function getAbsoluteUrl(string $path): string + { + if (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) { + return $path; + } + + if (null === $request = $this->requestStack->getMasterRequest()) { + 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 (false !== strpos($path, '://') || '//' === substr($path, 0, 2)) { + return $path; + } + + if (null === $request = $this->requestStack->getMasterRequest()) { + return $path; + } + + return $request->getRelativeUriForPath($path); + } + + private function getAbsoluteUrlFromContext(string $path): string + { + if (null === $this->requestContext || '' === $host = $this->requestContext->getHost()) { + return $path; + } + + $scheme = $this->requestContext->getScheme(); + $port = ''; + + if ('http' === $scheme && 80 !== $this->requestContext->getHttpPort()) { + $port = ':'.$this->requestContext->getHttpPort(); + } elseif ('https' === $scheme && 443 !== $this->requestContext->getHttpsPort()) { + $port = ':'.$this->requestContext->getHttpsPort(); + } + + if ('#' === $path[0]) { + $queryString = $this->requestContext->getQueryString(); + $path = $this->requestContext->getPathInfo().($queryString ? '?'.$queryString : '').$path; + } elseif ('?' === $path[0]) { + $path = $this->requestContext->getPathInfo().$path; + } + + if ('/' !== $path[0]) { + $path = rtrim($this->requestContext->getBaseUrl(), '/').'/'.$path; + } + + return $scheme.'://'.$host.$port.$path; + } +} diff --git a/vendor/symfony/http-foundation/composer.json b/vendor/symfony/http-foundation/composer.json index 76381a7c46..f30975114f 100644 --- a/vendor/symfony/http-foundation/composer.json +++ b/vendor/symfony/http-foundation/composer.json @@ -17,6 +17,7 @@ ], "require": { "php": "^7.1.3", + "symfony/mime": "^4.3", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { @@ -32,7 +33,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/http-kernel/CHANGELOG.md b/vendor/symfony/http-kernel/CHANGELOG.md index b96b4aefa1..b1a5f5101b 100644 --- a/vendor/symfony/http-kernel/CHANGELOG.md +++ b/vendor/symfony/http-kernel/CHANGELOG.md @@ -1,6 +1,31 @@ CHANGELOG ========= +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 ----- diff --git a/vendor/symfony/http-kernel/Client.php b/vendor/symfony/http-kernel/Client.php index 51b853c6e1..ed1e1382ea 100644 --- a/vendor/symfony/http-kernel/Client.php +++ b/vendor/symfony/http-kernel/Client.php @@ -11,194 +11,8 @@ namespace Symfony\Component\HttpKernel; -use Symfony\Component\BrowserKit\Client as BaseClient; -use Symfony\Component\BrowserKit\CookieJar; -use Symfony\Component\BrowserKit\History; -use Symfony\Component\BrowserKit\Request as DomRequest; -use Symfony\Component\BrowserKit\Response as DomResponse; -use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', Client::class, HttpKernelBrowser::class), E_USER_DEPRECATED); -/** - * Client simulates a browser and makes requests to a Kernel object. - * - * @author Fabien Potencier <fabien@symfony.com> - * - * @method Request getRequest() A Request instance - * @method Response getResponse() A Response instance - */ -class Client extends BaseClient +class Client extends HttpKernelBrowser { - 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 - */ - public function __construct(HttpKernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) - { - // These class properties must be set before calling the parent constructor, as it may depend on it. - $this->kernel = $kernel; - $this->followRedirects = false; - - parent::__construct($server, $history, $cookieJar); - } - - /** - * Sets whether to catch exceptions when the kernel is handling a request. - * - * @param bool $catchExceptions Whether to catch exceptions - */ - public function catchExceptions($catchExceptions) - { - $this->catchExceptions = $catchExceptions; - } - - /** - * Makes a request. - * - * @return Response A Response instance - */ - protected function doRequest($request) - { - $response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $this->catchExceptions); - - if ($this->kernel instanceof TerminableInterface) { - $this->kernel->terminate($request, $response); - } - - return $response; - } - - /** - * Returns the script to execute when the request must be insulated. - * - * @return string - */ - protected function getScript($request) - { - $kernel = var_export(serialize($this->kernel), true); - $request = var_export(serialize($request), true); - - $errorReporting = error_reporting(); - - $requires = ''; - foreach (get_declared_classes() as $class) { - if (0 === strpos($class, 'ComposerAutoloaderInit')) { - $r = new \ReflectionClass($class); - $file = \dirname(\dirname($r->getFileName())).'/autoload.php'; - if (file_exists($file)) { - $requires .= 'require_once '.var_export($file, true).";\n"; - } - } - } - - if (!$requires) { - throw new \RuntimeException('Composer autoloader not found.'); - } - - $code = <<<EOF -<?php - -error_reporting($errorReporting); - -$requires - -\$kernel = unserialize($kernel); -\$request = unserialize($request); -EOF; - - return $code.$this->getHandleScript(); - } - - protected function getHandleScript() - { - return <<<'EOF' -$response = $kernel->handle($request); - -if ($kernel instanceof Symfony\Component\HttpKernel\TerminableInterface) { - $kernel->terminate($request, $response); -} - -echo serialize($response); -EOF; - } - - /** - * Converts the BrowserKit request to a HttpKernel request. - * - * @return Request A Request instance - */ - protected function filterRequest(DomRequest $request) - { - $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent()); - - foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) { - $httpRequest->files->set($key, $value); - } - - return $httpRequest; - } - - /** - * Filters an array of files. - * - * This method created test instances of UploadedFile so that the move() - * method can be called on those instances. - * - * If the size of a file is greater than the allowed size (from php.ini) then - * an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE. - * - * @see UploadedFile - * - * @return array An array with all uploaded files marked as already moved - */ - protected function filterFiles(array $files) - { - $filtered = []; - foreach ($files as $key => $value) { - if (\is_array($value)) { - $filtered[$key] = $this->filterFiles($value); - } elseif ($value instanceof UploadedFile) { - if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) { - $filtered[$key] = new UploadedFile( - '', - $value->getClientOriginalName(), - $value->getClientMimeType(), - UPLOAD_ERR_INI_SIZE, - true - ); - } else { - $filtered[$key] = new UploadedFile( - $value->getPathname(), - $value->getClientOriginalName(), - $value->getClientMimeType(), - $value->getError(), - true - ); - } - } - } - - return $filtered; - } - - /** - * Converts the HttpKernel response to a BrowserKit response. - * - * @return DomResponse A DomResponse instance - */ - protected function filterResponse($response) - { - // this is needed to support StreamedResponse - ob_start(); - $response->sendContent(); - $content = ob_get_clean(); - - return new DomResponse($content, $response->getStatusCode(), $response->headers->all()); - } } 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 0000000000..19e324dc24 --- /dev/null +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/NotTaggedControllerValueResolver.php @@ -0,0 +1,81 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <simeon.kolev9@gmail.com> + */ +final class NotTaggedControllerValueResolver implements ArgumentValueResolverInterface +{ + private $container; + + public function __construct(ContainerInterface $container) + { + $this->container = $container; + } + + /** + * {@inheritdoc} + */ + public function supports(Request $request, ArgumentMetadata $argument) + { + $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) + { + if (\is_array($controller = $request->attributes->get('_controller'))) { + $controller = $controller[0].'::'.$controller[1]; + } + + if ('\\' === $controller[0]) { + $controller = ltrim($controller, '\\'); + } + + if (!$this->container->has($controller)) { + $i = strrpos($controller, ':'); + $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); + } + + $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/ControllerResolverInterface.php b/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php index a54f8b518b..8b70a88f63 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php +++ b/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php @@ -29,7 +29,7 @@ interface ControllerResolverInterface * As several resolvers can exist for a single application, a resolver must * return false when it is not able to determine the controller. * - * The resolver must only throw an exception when it should be able to load + * The resolver must only throw an exception when it should be able to load a * controller but cannot because of some errors made by the developer. * * @return callable|false A PHP callable representing the Controller, diff --git a/vendor/symfony/http-kernel/DataCollector/DataCollector.php b/vendor/symfony/http-kernel/DataCollector/DataCollector.php index efe1705179..d3020a312e 100644 --- a/vendor/symfony/http-kernel/DataCollector/DataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DataCollector.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\DataCollector; 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; @@ -25,7 +26,7 @@ use Symfony\Component\VarDumper\Cloner\VarCloner; * @author Fabien Potencier <fabien@symfony.com> * @author Bernhard Schussek <bschussek@symfony.com> */ -abstract class DataCollector implements DataCollectorInterface, \Serializable +abstract class DataCollector implements DataCollectorInterface { protected $data = []; @@ -34,16 +35,26 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable */ 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); } @@ -79,7 +90,7 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable */ protected function getCasters() { - return [ + $casters = [ '*' => function ($v, array $a, Stub $s, $isNested) { if (!$v instanceof Stub) { foreach ($a as $k => $v) { @@ -92,5 +103,29 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable return $a; }, ]; + + if (method_exists(ReflectionCaster::class, 'unsetClosureFileInfo')) { + $casters += ReflectionCaster::UNSET_CLOSURE_FILE_INFO; + } + + return $casters; + } + + 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) { + @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/DumpDataCollector.php b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php index 323ebf2054..577eb2ca2e 100644 --- a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php @@ -25,6 +25,8 @@ use Symfony\Component\VarDumper\Server\Connection; /** * @author Nicolas Grekas <p@tchwork.com> + * + * @final since Symfony 4.3 */ class DumpDataCollector extends DataCollector implements DataDumperInterface { @@ -85,6 +87,9 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $this->isCollected = false; } + if (!$this->dataCount) { + $this->data = []; + } $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt'); ++$this->dataCount; @@ -95,6 +100,10 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface public function collect(Request $request, Response $response, \Exception $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; @@ -113,6 +122,9 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { $dumper = new CliDumper('php://output', $this->charset); + if (method_exists($dumper, 'setDisplayOptions')) { + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); + } } foreach ($this->data as $dump) { @@ -133,28 +145,38 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $this->clonesIndex = 0; } - public function serialize() + /** + * @internal + */ + public function __sleep() { + 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; - 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); } @@ -175,6 +197,10 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface } $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); @@ -193,7 +219,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface 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; @@ -215,6 +241,9 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); } else { $dumper = new CliDumper('php://output', $this->charset); + if (method_exists($dumper, 'setDisplayOptions')) { + $dumper->setDisplayOptions(['fileLinkFormat' => $this->fileLinkFormat]); + } } foreach ($this->data as $i => $dump) { diff --git a/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php b/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php index c0de250940..d918ddf786 100644 --- a/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php @@ -13,9 +13,10 @@ 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; /** @@ -26,10 +27,13 @@ use Symfony\Contracts\Service\ResetInterface; 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) { $this->dispatcher = $dispatcher; + $this->requestStack = $requestStack; } /** @@ -37,6 +41,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter */ public function collect(Request $request, Response $response, \Exception $exception = null) { + $this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null; $this->data = [ 'called_listeners' => [], 'not_called_listeners' => [], @@ -56,12 +61,12 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter 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->setOrphanedEvents($this->dispatcher->getOrphanedEvents($this->currentRequest)); } $this->data = $this->cloneVar($this->data); diff --git a/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php b/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php index 00a7874e3c..4091b6760f 100644 --- a/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php @@ -66,7 +66,9 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte if (null !== $this->logger) { $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); - $this->data['compiler_logs'] = $this->getContainerCompilerLogs(); + // 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); } @@ -110,7 +112,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte public function getCompilerLogs() { - return isset($this->data['compiler_logs']) ? $this->data['compiler_logs'] : []; + return $this->cloneVar($this->getContainerCompilerLogs($this->data['compiler_logs_filepath'] ?? null)); } /** @@ -147,14 +149,14 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte 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)]; diff --git a/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php b/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php index 2df5f94fd4..32624c963f 100644 --- a/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php @@ -252,6 +252,18 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter 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']; @@ -338,11 +350,17 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter return isset($this->data['forward_token']) ? $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()) { diff --git a/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php b/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php index 432dc3618f..65fc90dc19 100644 --- a/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/RouterDataCollector.php @@ -17,8 +17,6 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\FilterControllerEvent; /** - * RouterDataCollector. - * * @author Fabien Potencier <fabien@symfony.com> */ class RouterDataCollector extends DataCollector @@ -68,6 +66,8 @@ class RouterDataCollector extends DataCollector /** * Remembers the controller associated to each request. + * + * @final since Symfony 4.3 */ public function onKernelController(FilterControllerEvent $event) { diff --git a/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php b/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php index 9476d50486..54defbf1d1 100644 --- a/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php +++ b/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php @@ -20,8 +20,10 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface; * Formats debug file links. * * @author Jérémy Romey <jeremy@free-agent.fr> + * + * @final since Symfony 4.3 */ -class FileLinkFormatter implements \Serializable +class FileLinkFormatter { private $fileLinkFormat; private $requestStack; @@ -64,17 +66,11 @@ class FileLinkFormatter implements \Serializable /** * @internal */ - public function serialize() + public function __sleep(): array { - return serialize($this->getFileLinkFormat()); - } + $this->getFileLinkFormat(); - /** - * @internal - */ - public function unserialize($serialized) - { - $this->fileLinkFormat = unserialize($serialized, ['allowed_classes' => false]); + return ['fileLinkFormat']; } /** @@ -91,21 +87,17 @@ class FileLinkFormatter implements \Serializable 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 = ($this->urlFormat)()) { - return; - } - return [ + if ($request instanceof Request && (!$this->urlFormat instanceof \Closure || $this->urlFormat = ($this->urlFormat)())) { + $this->fileLinkFormat = [ $request->getSchemeAndHttpHost().$request->getBasePath().$this->urlFormat, $this->baseDir.\DIRECTORY_SEPARATOR, '', ]; } } + + return $this->fileLinkFormat; } } diff --git a/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php b/vendor/symfony/http-kernel/Debug/TraceableEventDispatcher.php index ddf4fa7cec..6c96afdff3 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,7 +26,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher /** * {@inheritdoc} */ - protected function preDispatch($eventName, Event $event) + protected function beforeDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::REQUEST: @@ -58,7 +57,7 @@ class TraceableEventDispatcher extends BaseTraceableEventDispatcher /** * {@inheritdoc} */ - protected function postDispatch($eventName, Event $event) + protected function afterDispatch(string $eventName, $event) { switch ($eventName) { case KernelEvents::CONTROLLER_ARGUMENTS: diff --git a/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index 64d5e02473..a3f5012e32 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -34,17 +34,19 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface private $resolverServiceId; private $controllerTag; private $controllerLocator; + private $notTaggedControllerResolverServiceId; - public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator') + 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; } @@ -137,8 +139,8 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface } elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) { $binding = $bindings[$bindingName]; - list($bindingValue, $bindingId) = $binding->getValues(); - $binding->setValues([$bindingValue, $bindingId, true]); + list($bindingValue, $bindingId, , $bindingType, $bindingFile) = $binding->getValues(); + $binding->setValues([$bindingValue, $bindingId, true, $bindingType, $bindingFile]); if (!$bindingValue instanceof Reference) { $args[$p->name] = new Reference('.value.'.$container->hash($bindingValue)); @@ -181,8 +183,17 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface } } - $container->getDefinition($this->resolverServiceId) - ->replaceArgument(0, $controllerLocatorRef = 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 0000000000..0efb164b72 --- /dev/null +++ b/vendor/symfony/http-kernel/DependencyInjection/RegisterLocaleAwareServicesPass.php @@ -0,0 +1,58 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <pierrebobiet@gmail.com> + */ +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/Event/ControllerArgumentsEvent.php b/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php new file mode 100644 index 0000000000..3dc6ea50ed --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ControllerArgumentsEvent.php @@ -0,0 +1,28 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <stof@notk.org> + */ +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 0000000000..9afb818a1d --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ControllerEvent.php @@ -0,0 +1,27 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <bschussek@gmail.com> + */ +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 0000000000..d3b2d8f606 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ExceptionEvent.php @@ -0,0 +1,29 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 setException() to replace the thrown exception. This + * exception will be thrown if no response is set during processing of this + * event. + * + * @author Bernhard Schussek <bschussek@gmail.com> + */ +class ExceptionEvent extends GetResponseForExceptionEvent +{ +} diff --git a/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php b/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php index 5e178f2b0b..ac8e0263ca 100644 --- a/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php @@ -15,18 +15,9 @@ use Symfony\Component\HttpFoundation\Request; 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 <stof@notk.org> + * @deprecated since Symfony 4.3, use ControllerArgumentsEvent instead */ -class FilterControllerArgumentsEvent extends FilterControllerEvent +class FilterControllerArgumentsEvent extends ControllerEvent { private $arguments; diff --git a/vendor/symfony/http-kernel/Event/FilterControllerEvent.php b/vendor/symfony/http-kernel/Event/FilterControllerEvent.php index 7eab449376..74fa681f80 100644 --- a/vendor/symfony/http-kernel/Event/FilterControllerEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterControllerEvent.php @@ -15,15 +15,7 @@ use Symfony\Component\HttpFoundation\Request; 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 <bschussek@gmail.com> + * @deprecated since Symfony 4.3, use ControllerEvent instead */ class FilterControllerEvent extends KernelEvent { diff --git a/vendor/symfony/http-kernel/Event/FilterResponseEvent.php b/vendor/symfony/http-kernel/Event/FilterResponseEvent.php index 04589f7b5c..eaa2e82565 100644 --- a/vendor/symfony/http-kernel/Event/FilterResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterResponseEvent.php @@ -16,13 +16,7 @@ use Symfony\Component\HttpFoundation\Response; 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 <bschussek@gmail.com> + * @deprecated since Symfony 4.3, use ResponseEvent instead */ class FilterResponseEvent extends KernelEvent { diff --git a/vendor/symfony/http-kernel/Event/GetResponseEvent.php b/vendor/symfony/http-kernel/Event/GetResponseEvent.php index c25a0f1cf1..fbed7beef5 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseEvent.php @@ -14,13 +14,7 @@ namespace Symfony\Component\HttpKernel\Event; 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 <bschussek@gmail.com> + * @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 a0082821de..4e70dbc63e 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php @@ -15,15 +15,9 @@ use Symfony\Component\HttpFoundation\Request; 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 <bschussek@gmail.com> + * @deprecated since Symfony 4.3, use ViewEvent instead */ -class GetResponseForControllerResultEvent extends GetResponseEvent +class GetResponseForControllerResultEvent extends RequestEvent { /** * The return value of the controller. diff --git a/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php b/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php index 7fab006d13..3476c7e62a 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php @@ -15,19 +15,9 @@ 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 <bschussek@gmail.com> + * @deprecated since Symfony 4.3, use ExceptionEvent instead */ -class GetResponseForExceptionEvent extends GetResponseEvent +class GetResponseForExceptionEvent extends RequestEvent { /** * The exception object. diff --git a/vendor/symfony/http-kernel/Event/PostResponseEvent.php b/vendor/symfony/http-kernel/Event/PostResponseEvent.php index 0981e64c92..b86bf07742 100644 --- a/vendor/symfony/http-kernel/Event/PostResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/PostResponseEvent.php @@ -16,12 +16,7 @@ use Symfony\Component\HttpFoundation\Response; 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 <j.boggiano@seld.be> + * @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 0000000000..c1beb929f3 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/RequestEvent.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <bschussek@gmail.com> + */ +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 0000000000..88c1996eaa --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ResponseEvent.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <bschussek@gmail.com> + */ +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 0000000000..6ce23e43f3 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/TerminateEvent.php @@ -0,0 +1,24 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <j.boggiano@seld.be> + */ +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 0000000000..1cb7e23980 --- /dev/null +++ b/vendor/symfony/http-kernel/Event/ViewEvent.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <bschussek@gmail.com> + */ +class ViewEvent extends GetResponseForControllerResultEvent +{ +} diff --git a/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php b/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php index 80d57e506a..d89bc813f7 100644 --- a/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php @@ -32,6 +32,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * * @author Johannes M. Schmitt <schmittjoh@gmail.com> * @author Tobias Schultze <http://tobion.de> + * + * @internal since Symfony 4.3 */ abstract class AbstractSessionListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php b/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php index 58b3580024..054695e6f2 100644 --- a/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php @@ -26,6 +26,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * * @author Bulat Shakirzyanov <mallluhuct@gmail.com> * @author Fabien Potencier <fabien@symfony.com> + * + * @internal since Symfony 4.3 */ abstract class AbstractTestSessionListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php b/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php index 68d806af01..47c7069c9e 100644 --- a/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php +++ b/vendor/symfony/http-kernel/EventListener/AddRequestFormatsListener.php @@ -19,6 +19,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * Adds configured formats to each request. * * @author Gildas Quemener <gildas.quemener@gmail.com> + * + * @final since Symfony 4.3 */ class AddRequestFormatsListener implements EventSubscriberInterface { @@ -45,6 +47,6 @@ class AddRequestFormatsListener implements EventSubscriberInterface */ public static function getSubscribedEvents() { - return [KernelEvents::REQUEST => ['onKernelRequest', 1]]; + return [KernelEvents::REQUEST => ['onKernelRequest', 100]]; } } diff --git a/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php b/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php new file mode 100644 index 0000000000..6607e49e99 --- /dev/null +++ b/vendor/symfony/http-kernel/EventListener/DisallowRobotsIndexingListener.php @@ -0,0 +1,43 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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 <garypegeot@gmail.com> + */ +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/ExceptionListener.php b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php index 811f99bd9d..8e31ecc944 100644 --- a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php +++ b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php @@ -18,7 +18,6 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -26,9 +25,9 @@ use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; /** - * ExceptionListener. - * * @author Fabien Potencier <fabien@symfony.com> + * + * @final since Symfony 4.3 */ class ExceptionListener implements EventSubscriberInterface { @@ -55,6 +54,10 @@ class ExceptionListener implements EventSubscriberInterface $this->logException($event->getException(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine())); } + /** + * @param string $eventName + * @param EventDispatcherInterface $eventDispatcher + */ public function onKernelException(GetResponseForExceptionEvent $event) { if (null === $this->controller) { @@ -96,7 +99,7 @@ class ExceptionListener implements EventSubscriberInterface $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); }; diff --git a/vendor/symfony/http-kernel/EventListener/FragmentListener.php b/vendor/symfony/http-kernel/EventListener/FragmentListener.php index 5a789a3eb9..fc4ba56d9b 100644 --- a/vendor/symfony/http-kernel/EventListener/FragmentListener.php +++ b/vendor/symfony/http-kernel/EventListener/FragmentListener.php @@ -24,10 +24,12 @@ use Symfony\Component\HttpKernel\UriSigner; * All URL paths starting with /_fragment are handled as * content fragments by this listener. * - * If throws an AccessDeniedHttpException exception if the request + * Throws an AccessDeniedHttpException exception if the request * is not signed or if it is not an internal sub-request. * * @author Fabien Potencier <fabien@symfony.com> + * + * @final since Symfony 4.3 */ class FragmentListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php b/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php new file mode 100644 index 0000000000..325b8cbc0d --- /dev/null +++ b/vendor/symfony/http-kernel/EventListener/LocaleAwareListener.php @@ -0,0 +1,76 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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\Request; +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 <pierrebobiet@gmail.com> + */ +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()) { + $this->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 = null): 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 a60bc69f0a..cb8a194d49 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\Request; 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 @@ use Symfony\Component\Routing\RequestContextAwareInterface; * Initializes the locale based on the current request. * * @author Fabien Potencier <fabien@symfony.com> + * + * @final since Symfony 4.3 */ class LocaleListener implements EventSubscriberInterface { @@ -42,10 +45,14 @@ class LocaleListener implements EventSubscriberInterface $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 +82,11 @@ class LocaleListener implements EventSubscriberInterface 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 df0e5cf8a6..85a0aacb61 100644 --- a/vendor/symfony/http-kernel/EventListener/ProfilerListener.php +++ b/vendor/symfony/http-kernel/EventListener/ProfilerListener.php @@ -24,6 +24,8 @@ use Symfony\Component\HttpKernel\Profiler\Profiler; * ProfilerListener collects data for the current request by listening to the kernel events. * * @author Fabien Potencier <fabien@symfony.com> + * + * @final since Symfony 4.3 */ class ProfilerListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/ResponseListener.php b/vendor/symfony/http-kernel/EventListener/ResponseListener.php index 331694b176..01973e222a 100644 --- a/vendor/symfony/http-kernel/EventListener/ResponseListener.php +++ b/vendor/symfony/http-kernel/EventListener/ResponseListener.php @@ -19,6 +19,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * ResponseListener fixes the Response headers based on the Request. * * @author Fabien Potencier <fabien@symfony.com> + * + * @final since Symfony 4.3 */ class ResponseListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/RouterListener.php b/vendor/symfony/http-kernel/EventListener/RouterListener.php index 3098657760..01a95ebffb 100644 --- a/vendor/symfony/http-kernel/EventListener/RouterListener.php +++ b/vendor/symfony/http-kernel/EventListener/RouterListener.php @@ -37,6 +37,8 @@ use Symfony\Component\Routing\RequestContextAwareInterface; * * @author Fabien Potencier <fabien@symfony.com> * @author Yonel Ceruto <yonelceruto@gmail.com> + * + * @final since Symfony 4.3 */ class RouterListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php b/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php index 895176a931..f28f5d868a 100644 --- a/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php +++ b/vendor/symfony/http-kernel/EventListener/StreamedResponseListener.php @@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * to the client. * * @author Fabien Potencier <fabien@symfony.com> + * + * @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 0fddddde42..9c3e960b00 100644 --- a/vendor/symfony/http-kernel/EventListener/SurrogateListener.php +++ b/vendor/symfony/http-kernel/EventListener/SurrogateListener.php @@ -21,6 +21,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * SurrogateListener adds a Surrogate-Control HTTP header when the Response needs to be parsed for Surrogates. * * @author Fabien Potencier <fabien@symfony.com> + * + * @final since Symfony 4.3 */ class SurrogateListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/TranslatorListener.php b/vendor/symfony/http-kernel/EventListener/TranslatorListener.php index 361b11fcec..d28eee2b1a 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; @@ -24,6 +26,8 @@ use Symfony\Contracts\Translation\LocaleAwareInterface; * Synchronizes the locale between the request and the translator. * * @author Fabien Potencier <fabien@symfony.com> + * + * @deprecated since Symfony 4.3, use LocaleAwareListener instead */ class TranslatorListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php b/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php index 2e921869b9..69c86b4095 100644 --- a/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php +++ b/vendor/symfony/http-kernel/EventListener/ValidateRequestListener.php @@ -19,6 +19,8 @@ use Symfony\Component\HttpKernel\KernelEvents; * Validates Requests. * * @author Magnus Nordlander <magnus@fervo.se> + * + * @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 f6f4ff53f0..326e9361ef 100644 --- a/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php @@ -19,11 +19,11 @@ class AccessDeniedHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 4b25adcba3..db031bea7d 100644 --- a/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php +++ b/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php @@ -18,11 +18,11 @@ class BadRequestHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 6c8a1b3c53..e1542cd056 100644 --- a/vendor/symfony/http-kernel/Exception/ConflictHttpException.php +++ b/vendor/symfony/http-kernel/Exception/ConflictHttpException.php @@ -18,11 +18,11 @@ class ConflictHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 index 517313db60..1e87690ff1 100644 --- a/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php +++ b/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php @@ -67,9 +67,15 @@ class ControllerDoesNotReturnResponseException extends \LogicException 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' => $r->getEndLine(), + 'line' => $line, ]; } diff --git a/vendor/symfony/http-kernel/Exception/GoneHttpException.php b/vendor/symfony/http-kernel/Exception/GoneHttpException.php index de0d5f2c2c..5d75f92b19 100644 --- a/vendor/symfony/http-kernel/Exception/GoneHttpException.php +++ b/vendor/symfony/http-kernel/Exception/GoneHttpException.php @@ -18,11 +18,11 @@ class GoneHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 3acb52ac35..d822cd5d49 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(int $statusCode, string $message = null, \Exception $previous = null, array $headers = [], ?int $code = 0) + public function __construct(int $statusCode, string $message = null, \Throwable $previous = null, array $headers = [], ?int $code = 0) { $this->statusCode = $statusCode; $this->headers = $headers; diff --git a/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php b/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php index 287c07a0c1..5e6eda04db 100644 --- a/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php +++ b/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php @@ -18,11 +18,11 @@ class LengthRequiredHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 e9a3f069f1..388c8c704e 100644 --- a/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php @@ -19,11 +19,11 @@ 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 \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(array $allow, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct(array $allow, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { $headers['Allow'] = strtoupper(implode(', ', $allow)); diff --git a/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php b/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php index 5596330881..5bdacf6914 100644 --- a/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php +++ b/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php @@ -18,11 +18,11 @@ class NotAcceptableHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 551b3edc59..c52587d37f 100644 --- a/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php +++ b/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php @@ -18,11 +18,11 @@ class NotFoundHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 c1a59fb8df..9bd895c88f 100644 --- a/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php @@ -18,11 +18,11 @@ class PreconditionFailedHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 fd95b042c5..6aed73406e 100644 --- a/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php +++ b/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php @@ -20,11 +20,11 @@ class PreconditionRequiredHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 18b12d83cc..34a749fa47 100644 --- a/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php +++ b/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php @@ -19,11 +19,11 @@ 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 \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct($retryAfter = null, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct($retryAfter = null, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { if ($retryAfter) { $headers['Retry-After'] = $retryAfter; diff --git a/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php b/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php index 91e65e2d70..e69961b7de 100644 --- a/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php +++ b/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php @@ -21,11 +21,11 @@ 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 \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct($retryAfter = null, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct($retryAfter = null, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { if ($retryAfter) { $headers['Retry-After'] = $retryAfter; diff --git a/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php b/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php index bc42877fe8..7f7d0b4739 100644 --- a/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php @@ -19,11 +19,11 @@ 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 \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $challenge, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = []) + public function __construct(string $challenge, string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { $headers['WWW-Authenticate'] = $challenge; diff --git a/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php b/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php index 9cad444c6c..7fbc7eff0c 100644 --- a/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php @@ -18,11 +18,11 @@ class UnprocessableEntityHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { 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 e52e1d88d2..3bfac7f481 100644 --- a/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php @@ -18,11 +18,11 @@ class UnsupportedMediaTypeHttpException extends HttpException { /** * @param string $message The internal exception message - * @param \Exception $previous The previous exception + * @param \Throwable $previous The previous exception * @param int $code The internal exception code * @param array $headers */ - public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = []) + public function __construct(string $message = null, \Throwable $previous = null, int $code = 0, array $headers = []) { parent::__construct(415, $message, $previous, $headers, $code); } diff --git a/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php index 7b8e761922..9a700a9b11 100644 --- a/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php @@ -59,6 +59,10 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer 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; } diff --git a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php index c01b09559a..7d6243552a 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 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer // 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 diff --git a/vendor/symfony/http-kernel/HttpCache/HttpCache.php b/vendor/symfony/http-kernel/HttpCache/HttpCache.php index 84b01659f9..051285aeba 100644 --- a/vendor/symfony/http-kernel/HttpCache/HttpCache.php +++ b/vendor/symfony/http-kernel/HttpCache/HttpCache.php @@ -40,7 +40,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 +94,13 @@ class HttpCache implements HttpKernelInterface, TerminableInterface '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['debug']) { + $this->options['trace_level'] = 'full'; + } } /** @@ -110,6 +123,23 @@ class HttpCache implements HttpKernelInterface, TerminableInterface 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. * @@ -194,8 +224,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface $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) { diff --git a/vendor/symfony/http-kernel/HttpClientKernel.php b/vendor/symfony/http-kernel/HttpClientKernel.php new file mode 100644 index 0000000000..f60a84eabe --- /dev/null +++ b/vendor/symfony/http-kernel/HttpClientKernel.php @@ -0,0 +1,106 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +use Symfony\Component\HttpClient\HttpClient; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Component\Mime\Part\TextPart; +use Symfony\Contracts\HttpClient\HttpClientInterface; + +/** + * An implementation of a Symfony HTTP kernel using a "real" HTTP client. + * + * @author Fabien Potencier <fabien@symfony.com> + */ +final class HttpClientKernel implements HttpKernelInterface +{ + private $client; + + public function __construct(HttpClientInterface $client = null) + { + if (!class_exists(HttpClient::class)) { + throw new \LogicException(sprintf('You cannot use "%s" as the HttpClient component is not installed. Try running "composer require symfony/http-client".', __CLASS__)); + } + + $this->client = $client ?? HttpClient::create(); + } + + public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) + { + $headers = $this->getHeaders($request); + $body = ''; + if (null !== $part = $this->getBody($request)) { + $headers = array_merge($headers, $part->getPreparedHeaders()->toArray()); + $body = $part->bodyToIterable(); + } + $response = $this->client->request($request->getMethod(), $request->getUri(), [ + 'headers' => $headers, + 'body' => $body, + 'max_redirects' => 0, + ] + $request->attributes->get('http_client_options', [])); + + $response = new Response($response->getContent(!$catch), $response->getStatusCode(), $response->getHeaders(!$catch)); + + $response->headers = new class($response->headers->all()) extends ResponseHeaderBag { + protected function computeCacheControlValue() + { + return $this->getCacheControlHeader(); // preserve the original value + } + }; + + return $response; + } + + private function getBody(Request $request): ?AbstractPart + { + if (\in_array($request->getMethod(), ['GET', 'HEAD'])) { + return null; + } + + if (!class_exists(AbstractPart::class)) { + throw new \LogicException('You cannot pass non-empty bodies as the Mime component is not installed. Try running "composer require symfony/mime".'); + } + + if ($content = $request->getContent()) { + return new TextPart($content, 'utf-8', 'plain', '8bit'); + } + + $fields = $request->request->all(); + foreach ($request->files->all() as $name => $file) { + $fields[$name] = DataPart::fromPath($file->getPathname(), $file->getClientOriginalName(), $file->getClientMimeType()); + } + + return new FormDataPart($fields); + } + + private function getHeaders(Request $request): array + { + $headers = []; + foreach ($request->headers as $key => $value) { + $headers[$key] = $value; + } + $cookies = []; + foreach ($request->cookies->all() as $name => $value) { + $cookies[] = $name.'='.$value; + } + if ($cookies) { + $headers['cookie'] = implode('; ', $cookies); + } + + return $headers; + } +} diff --git a/vendor/symfony/http-kernel/HttpKernel.php b/vendor/symfony/http-kernel/HttpKernel.php index 11eb718aff..64e931f2bd 100644 --- a/vendor/symfony/http-kernel/HttpKernel.php +++ b/vendor/symfony/http-kernel/HttpKernel.php @@ -11,7 +11,7 @@ namespace Symfony\Component\HttpKernel; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy; use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -19,18 +19,19 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; -use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent; -use Symfony\Component\HttpKernel\Event\FilterControllerEvent; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; +use Symfony\Component\HttpKernel\Event\ControllerEvent; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; -use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; -use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; -use Symfony\Component\HttpKernel\Event\PostResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\Event\TerminateEvent; +use Symfony\Component\HttpKernel\Event\ViewEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; /** * HttpKernel notifies events to convert a Request object to a Response one. @@ -46,7 +47,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface public function __construct(EventDispatcherInterface $dispatcher, ControllerResolverInterface $resolver, RequestStack $requestStack = null, ArgumentResolverInterface $argumentResolver = null) { - $this->dispatcher = $dispatcher; + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); $this->resolver = $resolver; $this->requestStack = $requestStack ?: new RequestStack(); $this->argumentResolver = $argumentResolver; @@ -84,7 +85,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface */ public function terminate(Request $request, Response $response) { - $this->dispatcher->dispatch(KernelEvents::TERMINATE, new PostResponseEvent($this, $request, $response)); + $this->dispatcher->dispatch(new TerminateEvent($this, $request, $response), KernelEvents::TERMINATE); } /** @@ -122,8 +123,8 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface $this->requestStack->push($request); // request - $event = new GetResponseEvent($this, $request, $type); - $this->dispatcher->dispatch(KernelEvents::REQUEST, $event); + $event = new RequestEvent($this, $request, $type); + $this->dispatcher->dispatch($event, KernelEvents::REQUEST); if ($event->hasResponse()) { return $this->filterResponse($event->getResponse(), $request, $type); @@ -134,15 +135,15 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface throw new NotFoundHttpException(sprintf('Unable to find the controller for path "%s". The route is wrongly configured.', $request->getPathInfo())); } - $event = new FilterControllerEvent($this, $controller, $request, $type); - $this->dispatcher->dispatch(KernelEvents::CONTROLLER, $event); + $event = new ControllerEvent($this, $controller, $request, $type); + $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER); $controller = $event->getController(); // controller arguments $arguments = $this->argumentResolver->getArguments($request, $controller); - $event = new FilterControllerArgumentsEvent($this, $controller, $arguments, $request, $type); - $this->dispatcher->dispatch(KernelEvents::CONTROLLER_ARGUMENTS, $event); + $event = new ControllerArgumentsEvent($this, $controller, $arguments, $request, $type); + $this->dispatcher->dispatch($event, KernelEvents::CONTROLLER_ARGUMENTS); $controller = $event->getController(); $arguments = $event->getArguments(); @@ -151,8 +152,8 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface // view if (!$response instanceof Response) { - $event = new GetResponseForControllerResultEvent($this, $request, $type, $response); - $this->dispatcher->dispatch(KernelEvents::VIEW, $event); + $event = new ViewEvent($this, $request, $type, $response); + $this->dispatcher->dispatch($event, KernelEvents::VIEW); if ($event->hasResponse()) { $response = $event->getResponse(); @@ -184,9 +185,9 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface */ private function filterResponse(Response $response, Request $request, int $type) { - $event = new FilterResponseEvent($this, $request, $type, $response); + $event = new ResponseEvent($this, $request, $type, $response); - $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->finishRequest($request, $type); @@ -202,7 +203,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface */ private function finishRequest(Request $request, int $type) { - $this->dispatcher->dispatch(KernelEvents::FINISH_REQUEST, new FinishRequestEvent($this, $request, $type)); + $this->dispatcher->dispatch(new FinishRequestEvent($this, $request, $type), KernelEvents::FINISH_REQUEST); $this->requestStack->pop(); } @@ -217,8 +218,8 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface */ private function handleException(\Exception $e, Request $request, int $type): Response { - $event = new GetResponseForExceptionEvent($this, $request, $type, $e); - $this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event); + $event = new ExceptionEvent($this, $request, $type, $e); + $this->dispatcher->dispatch($event, KernelEvents::EXCEPTION); // a listener might have replaced the exception $e = $event->getException(); diff --git a/vendor/symfony/http-kernel/HttpKernelBrowser.php b/vendor/symfony/http-kernel/HttpKernelBrowser.php new file mode 100644 index 0000000000..76f964ce6a --- /dev/null +++ b/vendor/symfony/http-kernel/HttpKernelBrowser.php @@ -0,0 +1,204 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel; + +use Symfony\Component\BrowserKit\AbstractBrowser; +use Symfony\Component\BrowserKit\CookieJar; +use Symfony\Component\BrowserKit\History; +use Symfony\Component\BrowserKit\Request as DomRequest; +use Symfony\Component\BrowserKit\Response as DomResponse; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; + +/** + * Client simulates a browser and makes requests to an HttpKernel instance. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @method Request getRequest() A Request instance + * @method Response getResponse() A Response instance + */ +class HttpKernelBrowser 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 + */ + public function __construct(HttpKernelInterface $kernel, array $server = [], History $history = null, CookieJar $cookieJar = null) + { + // These class properties must be set before calling the parent constructor, as it may depend on it. + $this->kernel = $kernel; + $this->followRedirects = false; + + parent::__construct($server, $history, $cookieJar); + } + + /** + * Sets whether to catch exceptions when the kernel is handling a request. + * + * @param bool $catchExceptions Whether to catch exceptions + */ + public function catchExceptions($catchExceptions) + { + $this->catchExceptions = $catchExceptions; + } + + /** + * Makes a request. + * + * @return Response A Response instance + */ + protected function doRequest($request) + { + $response = $this->kernel->handle($request, HttpKernelInterface::MASTER_REQUEST, $this->catchExceptions); + + if ($this->kernel instanceof TerminableInterface) { + $this->kernel->terminate($request, $response); + } + + return $response; + } + + /** + * Returns the script to execute when the request must be insulated. + * + * @return string + */ + protected function getScript($request) + { + $kernel = var_export(serialize($this->kernel), true); + $request = var_export(serialize($request), true); + + $errorReporting = error_reporting(); + + $requires = ''; + foreach (get_declared_classes() as $class) { + if (0 === strpos($class, 'ComposerAutoloaderInit')) { + $r = new \ReflectionClass($class); + $file = \dirname(\dirname($r->getFileName())).'/autoload.php'; + if (file_exists($file)) { + $requires .= 'require_once '.var_export($file, true).";\n"; + } + } + } + + if (!$requires) { + throw new \RuntimeException('Composer autoloader not found.'); + } + + $code = <<<EOF +<?php + +error_reporting($errorReporting); + +$requires + +\$kernel = unserialize($kernel); +\$request = unserialize($request); +EOF; + + return $code.$this->getHandleScript(); + } + + protected function getHandleScript() + { + return <<<'EOF' +$response = $kernel->handle($request); + +if ($kernel instanceof Symfony\Component\HttpKernel\TerminableInterface) { + $kernel->terminate($request, $response); +} + +echo serialize($response); +EOF; + } + + /** + * Converts the BrowserKit request to a HttpKernel request. + * + * @return Request A Request instance + */ + protected function filterRequest(DomRequest $request) + { + $httpRequest = Request::create($request->getUri(), $request->getMethod(), $request->getParameters(), $request->getCookies(), $request->getFiles(), $request->getServer(), $request->getContent()); + + foreach ($this->filterFiles($httpRequest->files->all()) as $key => $value) { + $httpRequest->files->set($key, $value); + } + + return $httpRequest; + } + + /** + * Filters an array of files. + * + * This method created test instances of UploadedFile so that the move() + * method can be called on those instances. + * + * If the size of a file is greater than the allowed size (from php.ini) then + * an invalid UploadedFile is returned with an error set to UPLOAD_ERR_INI_SIZE. + * + * @see UploadedFile + * + * @return array An array with all uploaded files marked as already moved + */ + protected function filterFiles(array $files) + { + $filtered = []; + foreach ($files as $key => $value) { + if (\is_array($value)) { + $filtered[$key] = $this->filterFiles($value); + } elseif ($value instanceof UploadedFile) { + if ($value->isValid() && $value->getSize() > UploadedFile::getMaxFilesize()) { + $filtered[$key] = new UploadedFile( + '', + $value->getClientOriginalName(), + $value->getClientMimeType(), + UPLOAD_ERR_INI_SIZE, + true + ); + } else { + $filtered[$key] = new UploadedFile( + $value->getPathname(), + $value->getClientOriginalName(), + $value->getClientMimeType(), + $value->getError(), + true + ); + } + } + } + + return $filtered; + } + + /** + * Converts the HttpKernel response to a BrowserKit response. + * + * @return DomResponse A DomResponse instance + */ + protected function filterResponse($response) + { + // this is needed to support StreamedResponse + ob_start(); + $response->sendContent(); + $content = ob_get_clean(); + + return new DomResponse($content, $response->getStatusCode(), $response->headers->all()); + } +} diff --git a/vendor/symfony/http-kernel/Kernel.php b/vendor/symfony/http-kernel/Kernel.php index cf8c24fb0f..e0154b7d23 100644 --- a/vendor/symfony/http-kernel/Kernel.php +++ b/vendor/symfony/http-kernel/Kernel.php @@ -73,15 +73,15 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.2.8'; - const VERSION_ID = 40208; + const VERSION = '4.3.0'; + const VERSION_ID = 40300; const MAJOR_VERSION = 4; - const MINOR_VERSION = 2; - const RELEASE_VERSION = 8; + const MINOR_VERSION = 3; + const RELEASE_VERSION = 0; const EXTRA_VERSION = ''; - const END_OF_MAINTENANCE = '07/2019'; - const END_OF_LIFE = '01/2020'; + const END_OF_MAINTENANCE = '01/2020'; + const END_OF_LIFE = '07/2020'; public function __construct(string $environment, bool $debug) { @@ -442,14 +442,21 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl /** * Gets the container class. * + * @throws \InvalidArgumentException If the generated classname is invalid + * * @return string The container class */ protected function getContainerClass() { $class = \get_class($this); $class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).str_replace('.', '_', ContainerBuilder::hash($class)) : $class; + $class = $this->name.str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; + + if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $class)) { + throw new \InvalidArgumentException(sprintf('The environment "%s" contains invalid characters, it can only contain characters allowed in PHP class names.', $this->environment)); + } - return $this->name.str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; + return $class; } /** @@ -826,22 +833,54 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl $output .= $rawChunk; - // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 unset($tokens, $rawChunk); gc_mem_caches(); return $output; } + /** + * @deprecated since Symfony 4.3 + */ public function serialize() { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); + return serialize([$this->environment, $this->debug]); } + /** + * @deprecated since Symfony 4.3 + */ public function unserialize($data) { + @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); list($environment, $debug) = unserialize($data, ['allowed_classes' => false]); $this->__construct($environment, $debug); } + + 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.', $c), E_USER_DEPRECATED); + $this->serialized = $this->serialize(); + + return ['serialized']; + } + + return ['environment', 'debug']; + } + + public function __wakeup() + { + if (__CLASS__ !== $c = (new \ReflectionMethod($this, 'serialize'))->getDeclaringClass()->name) { + @trigger_error(sprintf('Implementing the "%s::serialize()" method is deprecated since Symfony 4.3.', $c), E_USER_DEPRECATED); + $this->unserialize($this->serialized); + unset($this->serialized); + + return; + } + $this->__construct($this->environment, $this->debug); + } } diff --git a/vendor/symfony/http-kernel/KernelEvents.php b/vendor/symfony/http-kernel/KernelEvents.php index 6743763258..682561c324 100644 --- a/vendor/symfony/http-kernel/KernelEvents.php +++ b/vendor/symfony/http-kernel/KernelEvents.php @@ -25,7 +25,7 @@ final class KernelEvents * This event allows you to create a response for a request before any * other code in the framework is executed. * - * @Event("Symfony\Component\HttpKernel\Event\GetResponseEvent") + * @Event("Symfony\Component\HttpKernel\Event\RequestEvent") */ const REQUEST = 'kernel.request'; @@ -35,7 +35,7 @@ final class KernelEvents * This event allows you to create a response for a thrown exception or * to modify the thrown exception. * - * @Event("Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent") + * @Event("Symfony\Component\HttpKernel\Event\ExceptionEvent") */ const EXCEPTION = 'kernel.exception'; @@ -46,7 +46,7 @@ final class KernelEvents * This event allows you to create a response for the return value of the * controller. * - * @Event("Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent") + * @Event("Symfony\Component\HttpKernel\Event\ViewEvent") */ const VIEW = 'kernel.view'; @@ -57,7 +57,7 @@ final class KernelEvents * This event allows you to change the controller that will handle the * request. * - * @Event("Symfony\Component\HttpKernel\Event\FilterControllerEvent") + * @Event("Symfony\Component\HttpKernel\Event\ControllerEvent") */ const CONTROLLER = 'kernel.controller'; @@ -67,7 +67,7 @@ final class KernelEvents * This event allows you to change the arguments that will be passed to * the controller. * - * @Event("Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent") + * @Event("Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent") */ const CONTROLLER_ARGUMENTS = 'kernel.controller_arguments'; @@ -78,7 +78,7 @@ final class KernelEvents * This event allows you to modify or replace the response that will be * replied. * - * @Event("Symfony\Component\HttpKernel\Event\FilterResponseEvent") + * @Event("Symfony\Component\HttpKernel\Event\ResponseEvent") */ const RESPONSE = 'kernel.response'; @@ -87,7 +87,7 @@ final class KernelEvents * * This event allows you to run expensive post-response jobs. * - * @Event("Symfony\Component\HttpKernel\Event\PostResponseEvent") + * @Event("Symfony\Component\HttpKernel\Event\TerminateEvent") */ const TERMINATE = 'kernel.terminate'; diff --git a/vendor/symfony/http-kernel/KernelInterface.php b/vendor/symfony/http-kernel/KernelInterface.php index 93c4190b9b..ead6920e77 100644 --- a/vendor/symfony/http-kernel/KernelInterface.php +++ b/vendor/symfony/http-kernel/KernelInterface.php @@ -24,7 +24,7 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface; * * @method string getProjectDir() Gets the project dir (path of the project's composer file) - not defining it is deprecated since Symfony 4.2 */ -interface KernelInterface extends HttpKernelInterface, \Serializable +interface KernelInterface extends HttpKernelInterface { /** * Returns an array of bundles to register. diff --git a/vendor/symfony/http-kernel/Tests/Config/FileLocatorTest.php b/vendor/symfony/http-kernel/Tests/Config/FileLocatorTest.php index 6265f02755..ca1b3191bd 100644 --- a/vendor/symfony/http-kernel/Tests/Config/FileLocatorTest.php +++ b/vendor/symfony/http-kernel/Tests/Config/FileLocatorTest.php @@ -30,7 +30,7 @@ class FileLocatorTest extends TestCase $kernel ->expects($this->never()) ->method('locateResource'); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('LogicException'); + $this->expectException('LogicException'); $locator->locate('/some/path'); } diff --git a/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php new file mode 100644 index 0000000000..bd22adde91 --- /dev/null +++ b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/NotTaggedControllerValueResolverTest.php @@ -0,0 +1,117 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentResolver\NotTaggedControllerValueResolver; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; + +class NotTaggedControllerValueResolverTest extends TestCase +{ + public function testDoSupportWhenControllerDoNotExists() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'my_controller']); + + $this->assertTrue($resolver->supports($request, $argument)); + } + + public function testDoNotSupportWhenControllerExists() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([ + 'App\\Controller\\Mine::method' => function () { + return new ServiceLocator([ + 'dummy' => function () { + return new \stdClass(); + }, + ]); + }, + ])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']); + + $this->assertFalse($resolver->supports($request, $argument)); + } + + public function testDoNotSupportEmptyController() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => '']); + $this->assertFalse($resolver->supports($request, $argument)); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testController() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testControllerWithATrailingBackSlash() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => '\\App\\Controller\\Mine::method']); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testControllerWithMethodNameStartUppercase() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::Method']); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"? + */ + public function testControllerNameIsAnArray() + { + $resolver = new NotTaggedControllerValueResolver(new ServiceLocator([])); + $argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null); + $request = $this->requestWithAttributes(['_controller' => ['App\\Controller\\Mine', 'method']]); + $this->assertTrue($resolver->supports($request, $argument)); + $resolver->resolve($request, $argument); + } + + private function requestWithAttributes(array $attributes) + { + $request = Request::create('/'); + foreach ($attributes as $name => $value) { + $request->attributes->set($name, $value); + } + + return $request; + } +} diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php index 76c1d96dcc..a40a482278 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php @@ -52,9 +52,9 @@ class DumpDataCollectorTest extends TestCase ]; $this->assertEquals($xDump, $dump); - $this->assertStringMatchesFormat('a:3:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', $collector->serialize()); + $this->assertStringMatchesFormat('%a;a:%d:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', serialize($collector)); $this->assertSame(0, $collector->getDumpsCount()); - $this->assertSame('a:2:{i:0;b:0;i:1;s:5:"UTF-8";}', $collector->serialize()); + $this->assertSame("O:60:\"Symfony\Component\HttpKernel\DataCollector\DumpDataCollector\":1:{s:7:\"\0*\0data\";a:2:{i:0;b:0;i:1;s:5:\"UTF-8\";}}", serialize($collector)); } public function testDumpWithServerConnection() @@ -72,7 +72,7 @@ class DumpDataCollectorTest extends TestCase ob_start(); $collector->collect(new Request(), new Response()); $this->assertEmpty(ob_get_clean()); - $this->assertStringMatchesFormat('a:3:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', $collector->serialize()); + $this->assertStringMatchesFormat('%a;a:%d:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', serialize($collector)); } public function testCollectDefault() @@ -90,7 +90,7 @@ class DumpDataCollectorTest extends TestCase $this->assertSame("DumpDataCollectorTest.php on line {$line}:\n123\n", $output); $this->assertSame(1, $collector->getDumpsCount()); - $collector->serialize(); + serialize($collector); } public function testCollectHtml() @@ -118,7 +118,7 @@ EOTXT; $this->assertSame($xOutput, trim($output)); $this->assertSame(1, $collector->getDumpsCount()); - $collector->serialize(); + serialize($collector); } public function testFlush() diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php index b5541610f6..42215ea0f7 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php @@ -22,8 +22,8 @@ use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface; use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector; -use Symfony\Component\HttpKernel\Event\FilterControllerEvent; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ControllerEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -206,7 +206,7 @@ class RequestDataCollectorTest extends TestCase $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $c = new RequestDataCollector(); - $c->onKernelResponse(new FilterResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $this->createResponse())); + $c->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $this->createResponse())); $this->assertTrue($request->attributes->get('_redirected')); } @@ -290,7 +290,7 @@ class RequestDataCollectorTest extends TestCase { $resolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface')->getMock(); $httpKernel = new HttpKernel(new EventDispatcher(), $resolver, null, $this->getMockBuilder(ArgumentResolverInterface::class)->getMock()); - $event = new FilterControllerEvent($httpKernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new ControllerEvent($httpKernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST); $collector->onKernelController($event); } @@ -333,4 +333,58 @@ class RequestDataCollectorTest extends TestCase throw new \InvalidArgumentException(sprintf('Cookie named "%s" is not in response', $name)); } + + /** + * @dataProvider provideJsonContentTypes + */ + public function testIsJson($contentType, $expected) + { + $response = $this->createResponse(); + $request = $this->createRequest(); + $request->headers->set('Content-Type', $contentType); + + $c = new RequestDataCollector(); + $c->collect($request, $response); + + $this->assertSame($expected, $c->isJsonRequest()); + } + + public function provideJsonContentTypes() + { + return [ + ['text/csv', false], + ['application/json', true], + ['application/JSON', true], + ['application/hal+json', true], + ['application/xml+json', true], + ['application/xml', false], + ['', false], + ]; + } + + /** + * @dataProvider providePrettyJson + */ + public function testGetPrettyJsonValidity($content, $expected) + { + $response = $this->createResponse(); + $request = Request::create('/', 'POST', [], [], [], [], $content); + + $c = new RequestDataCollector(); + $c->collect($request, $response); + + $this->assertSame($expected, $c->getPrettyJson()); + } + + public function providePrettyJson() + { + return [ + ['null', 'null'], + ['{ "foo": "bar" }', '{ + "foo": "bar" +}'], + ['{ "abc" }', null], + ['', null], + ]; + } } diff --git a/vendor/symfony/http-kernel/Tests/Debug/FileLinkFormatterTest.php b/vendor/symfony/http-kernel/Tests/Debug/FileLinkFormatterTest.php index 5c93bd90e3..1f4d298bf3 100644 --- a/vendor/symfony/http-kernel/Tests/Debug/FileLinkFormatterTest.php +++ b/vendor/symfony/http-kernel/Tests/Debug/FileLinkFormatterTest.php @@ -34,18 +34,6 @@ class FileLinkFormatterTest extends TestCase $this->assertSame("debug://open?url=file://$file&line=3", $sut->format($file, 3)); } - public function testWhenFileLinkFormatAndRequest() - { - $file = __DIR__.\DIRECTORY_SEPARATOR.'file.php'; - $requestStack = new RequestStack(); - $request = new Request(); - $requestStack->push($request); - - $sut = new FileLinkFormatter('debug://open?url=file://%f&line=%l', $requestStack, __DIR__, '/_profiler/open?file=%f&line=%l#line%l'); - - $this->assertSame("debug://open?url=file://$file&line=3", $sut->format($file, 3)); - } - public function testWhenNoFileLinkFormatAndRequest() { $file = __DIR__.\DIRECTORY_SEPARATOR.'file.php'; diff --git a/vendor/symfony/http-kernel/Tests/Debug/TraceableEventDispatcherTest.php b/vendor/symfony/http-kernel/Tests/Debug/TraceableEventDispatcherTest.php index 8b8e91aeb4..ef4f4bf66a 100644 --- a/vendor/symfony/http-kernel/Tests/Debug/TraceableEventDispatcherTest.php +++ b/vendor/symfony/http-kernel/Tests/Debug/TraceableEventDispatcherTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\Debug; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\Event; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; @@ -89,10 +90,10 @@ class TraceableEventDispatcherTest extends TestCase $called2 = true; }); }); - $dispatcher->dispatch('my-event'); + $dispatcher->dispatch(new Event(), 'my-event'); $this->assertTrue($called1); $this->assertFalse($called2); - $dispatcher->dispatch('my-event'); + $dispatcher->dispatch(new Event(), 'my-event'); $this->assertTrue($called2); } @@ -104,7 +105,7 @@ class TraceableEventDispatcherTest extends TestCase }; $eventDispatcher->addListener('foo', $listener1); $eventDispatcher->addListener('foo', function () {}); - $eventDispatcher->dispatch('foo'); + $eventDispatcher->dispatch(new Event(), 'foo'); $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); } diff --git a/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index cf685b2ae2..948311556c 100644 --- a/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -376,6 +376,19 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $this->assertInstanceOf(ServiceClosureArgument::class, $locator['someArg']); $this->assertEquals(new Reference('parent'), $locator['someArg']->getValues()[0]); } + + public function testNotTaggedControllerServiceReceivesLocatorArgument() + { + $container = new ContainerBuilder(); + $resolver = $container->register('argument_resolver.not_tagged_controller')->addArgument([]); + + $pass = new RegisterControllerArgumentLocatorsPass(); + $pass->process($container); + + $locatorArgument = $container->getDefinition('argument_resolver.not_tagged_controller')->getArgument(0); + + $this->assertInstanceOf(Reference::class, $locatorArgument); + } } class RegisterTestController diff --git a/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php b/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php new file mode 100644 index 0000000000..aa3c6aa0c4 --- /dev/null +++ b/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterLocaleAwareServicesPassTest.php @@ -0,0 +1,59 @@ +<?php + +namespace Symfony\Component\HttpKernel\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpKernel\DependencyInjection\RegisterLocaleAwareServicesPass; +use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +class RegisterLocaleAwareServicesPassTest extends TestCase +{ + public function testCompilerPass() + { + $container = new ContainerBuilder(); + + $container->register('locale_aware_listener', LocaleAwareListener::class) + ->setPublic(true) + ->setArguments([null, null]); + + $container->register('some_locale_aware_service', LocaleAwareInterface::class) + ->setPublic(true) + ->addTag('kernel.locale_aware'); + + $container->register('another_locale_aware_service', LocaleAwareInterface::class) + ->setPublic(true) + ->addTag('kernel.locale_aware'); + + $container->addCompilerPass(new RegisterLocaleAwareServicesPass()); + $container->compile(); + + $this->assertEquals( + [ + new IteratorArgument([ + 0 => new Reference('some_locale_aware_service'), + 1 => new Reference('another_locale_aware_service'), + ]), + null, + ], + $container->getDefinition('locale_aware_listener')->getArguments() + ); + } + + public function testListenerUnregisteredWhenNoLocaleAwareServices() + { + $container = new ContainerBuilder(); + + $container->register('locale_aware_listener', LocaleAwareListener::class) + ->setPublic(true) + ->setArguments([null, null]); + + $container->addCompilerPass(new RegisterLocaleAwareServicesPass()); + $container->compile(); + + $this->assertFalse($container->hasDefinition('locale_aware_listener')); + } +} diff --git a/vendor/symfony/http-kernel/Tests/Event/ControllerArgumentsEventTest.php b/vendor/symfony/http-kernel/Tests/Event/ControllerArgumentsEventTest.php new file mode 100644 index 0000000000..7758a66667 --- /dev/null +++ b/vendor/symfony/http-kernel/Tests/Event/ControllerArgumentsEventTest.php @@ -0,0 +1,17 @@ +<?php + +namespace Symfony\Component\HttpKernel\Tests\Event; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent; +use Symfony\Component\HttpKernel\Tests\TestHttpKernel; + +class ControllerArgumentsEventTest extends TestCase +{ + public function testControllerArgumentsEvent() + { + $filterController = new ControllerArgumentsEvent(new TestHttpKernel(), function () {}, ['test'], new Request(), 1); + $this->assertEquals($filterController->getArguments(), ['test']); + } +} diff --git a/vendor/symfony/http-kernel/Tests/Event/GetResponseForExceptionEventTest.php b/vendor/symfony/http-kernel/Tests/Event/ExceptionEventTest.php index 7242579301..6b061d3a33 100644 --- a/vendor/symfony/http-kernel/Tests/Event/GetResponseForExceptionEventTest.php +++ b/vendor/symfony/http-kernel/Tests/Event/ExceptionEventTest.php @@ -13,14 +13,14 @@ namespace Symfony\Component\HttpKernel\Tests\Event; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Tests\TestHttpKernel; -class GetResponseForExceptionEventTest extends TestCase +class ExceptionEventTest extends TestCase { public function testAllowSuccessfulResponseIsFalseByDefault() { - $event = new GetResponseForExceptionEvent(new TestHttpKernel(), new Request(), 1, new \Exception()); + $event = new ExceptionEvent(new TestHttpKernel(), new Request(), 1, new \Exception()); $this->assertFalse($event->isAllowingCustomResponseCode()); } diff --git a/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php b/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php deleted file mode 100644 index abc51ac51e..0000000000 --- a/vendor/symfony/http-kernel/Tests/Event/FilterControllerArgumentsEventTest.php +++ /dev/null @@ -1,17 +0,0 @@ -<?php - -namespace Symfony\Component\HttpKernel\Tests\Event; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent; -use Symfony\Component\HttpKernel\Tests\TestHttpKernel; - -class FilterControllerArgumentsEventTest extends TestCase -{ - public function testFilterControllerArgumentsEvent() - { - $filterController = new FilterControllerArgumentsEvent(new TestHttpKernel(), function () {}, ['test'], new Request(), 1); - $this->assertEquals($filterController->getArguments(), ['test']); - } -} diff --git a/vendor/symfony/http-kernel/Tests/EventListener/AddRequestFormatsListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/AddRequestFormatsListenerTest.php index b4ea2f955b..b8b4719206 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/AddRequestFormatsListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/AddRequestFormatsListenerTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener; use Symfony\Component\HttpKernel\KernelEvents; @@ -46,7 +47,7 @@ class AddRequestFormatsListenerTest extends TestCase public function testRegisteredEvent() { $this->assertEquals( - [KernelEvents::REQUEST => ['onKernelRequest', 1]], + [KernelEvents::REQUEST => ['onKernelRequest', 100]], AddRequestFormatsListener::getSubscribedEvents() ); } @@ -54,7 +55,7 @@ class AddRequestFormatsListenerTest extends TestCase public function testSetAdditionalFormats() { $request = $this->getRequestMock(); - $event = $this->getGetResponseEventMock($request); + $event = $this->getRequestEventMock($request); $request->expects($this->once()) ->method('setFormat') @@ -68,10 +69,10 @@ class AddRequestFormatsListenerTest extends TestCase return $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock(); } - protected function getGetResponseEventMock(Request $request) + protected function getRequestEventMock(Request $request) { $event = $this - ->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseEvent') + ->getMockBuilder(RequestEvent::class) ->disableOriginalConstructor() ->getMock(); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/DebugHandlersListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/DebugHandlersListenerTest.php index d9e261d35a..f1a56e537b 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/DebugHandlersListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/DebugHandlersListenerTest.php @@ -112,7 +112,7 @@ class DebugHandlersListenerTest extends TestCase set_error_handler([$eHandler, 'handleError']); set_exception_handler([$eHandler, 'handleException']); try { - $dispatcher->dispatch(ConsoleEvents::COMMAND, $event); + $dispatcher->dispatch($event, ConsoleEvents::COMMAND); } catch (\Exception $exception) { } restore_exception_handler(); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php new file mode 100644 index 0000000000..53b317b761 --- /dev/null +++ b/vendor/symfony/http-kernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php @@ -0,0 +1,47 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\EventListener; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\EventListener\DisallowRobotsIndexingListener; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelInterface; + +class DisallowRobotsIndexingListenerTest extends TestCase +{ + /** + * @dataProvider provideResponses + */ + public function testInvoke(?string $expected, Response $response): void + { + $listener = new DisallowRobotsIndexingListener(); + + $event = new ResponseEvent($this->createMock(HttpKernelInterface::class), $this->createMock(Request::class), KernelInterface::MASTER_REQUEST, $response); + + $listener->onResponse($event); + + $this->assertSame($expected, $response->headers->get('X-Robots-Tag'), 'Header doesn\'t match expectations'); + } + + public function provideResponses(): iterable + { + yield 'No header' => ['noindex', new Response()]; + + yield 'Header already set' => [ + 'something else', + new Response('', 204, ['X-Robots-Tag' => 'something else']), + ]; + } +} diff --git a/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php index b7224ddcea..18763c881b 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php @@ -15,8 +15,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\EventListener\ExceptionListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; @@ -103,8 +103,8 @@ class ExceptionListenerTest extends TestCase $request = new Request(); $exception = new \Exception('foo'); - $event = new GetResponseForExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MASTER_REQUEST, $exception); - $event2 = new GetResponseForExceptionEvent(new TestKernelThatThrowsException(), $request, HttpKernelInterface::MASTER_REQUEST, $exception); + $event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MASTER_REQUEST, $exception); + $event2 = new ExceptionEvent(new TestKernelThatThrowsException(), $request, HttpKernelInterface::MASTER_REQUEST, $exception); return [ [$event, $event2], @@ -123,7 +123,7 @@ class ExceptionListenerTest extends TestCase $request = Request::create('/'); $request->setRequestFormat('xml'); - $event = new GetResponseForExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); + $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); $listener->onKernelException($event); $response = $event->getResponse(); @@ -143,14 +143,14 @@ class ExceptionListenerTest extends TestCase $dispatcher->addSubscriber($listener); $request = Request::create('/'); - $event = new GetResponseForExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); - $dispatcher->dispatch(KernelEvents::EXCEPTION, $event); + $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); + $dispatcher->dispatch($event, KernelEvents::EXCEPTION); $response = new Response('', 200, ['content-security-policy' => "style-src 'self'"]); $this->assertTrue($response->headers->has('content-security-policy')); - $event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response); - $dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response); + $dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertFalse($response->headers->has('content-security-policy'), 'CSP header has been removed'); $this->assertFalse($dispatcher->hasListeners(KernelEvents::RESPONSE), 'CSP removal listener has been removed'); @@ -166,7 +166,7 @@ class ExceptionListenerTest extends TestCase return $controller(); })); $request = Request::create('/'); - $event = new GetResponseForExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); + $event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); $listener->onKernelException($event); $this->assertNull($event->getResponse()); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/FragmentListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/FragmentListenerTest.php index 6408b1b21c..40da65d240 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/FragmentListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/FragmentListenerTest.php @@ -13,7 +13,7 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\EventListener\FragmentListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\UriSigner; @@ -25,7 +25,7 @@ class FragmentListenerTest extends TestCase $request = Request::create('http://example.com/foo?_path=foo%3Dbar%26_controller%3Dfoo'); $listener = new FragmentListener(new UriSigner('foo')); - $event = $this->createGetResponseEvent($request); + $event = $this->createRequestEvent($request); $expected = $request->attributes->all(); @@ -41,7 +41,7 @@ class FragmentListenerTest extends TestCase $request->attributes->set('_controller', 'bar'); $listener = new FragmentListener(new UriSigner('foo')); - $event = $this->createGetResponseEvent($request, HttpKernelInterface::SUB_REQUEST); + $event = $this->createRequestEvent($request, HttpKernelInterface::SUB_REQUEST); $expected = $request->attributes->all(); @@ -58,7 +58,7 @@ class FragmentListenerTest extends TestCase $request = Request::create('http://example.com/_fragment', 'POST'); $listener = new FragmentListener(new UriSigner('foo')); - $event = $this->createGetResponseEvent($request); + $event = $this->createRequestEvent($request); $listener->onKernelRequest($event); } @@ -71,7 +71,7 @@ class FragmentListenerTest extends TestCase $request = Request::create('http://example.com/_fragment', 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']); $listener = new FragmentListener(new UriSigner('foo')); - $event = $this->createGetResponseEvent($request); + $event = $this->createRequestEvent($request); $listener->onKernelRequest($event); } @@ -82,7 +82,7 @@ class FragmentListenerTest extends TestCase $request = Request::create($signer->sign('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo'), 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']); $listener = new FragmentListener($signer); - $event = $this->createGetResponseEvent($request); + $event = $this->createRequestEvent($request); $listener->onKernelRequest($event); @@ -95,7 +95,7 @@ class FragmentListenerTest extends TestCase $request = Request::create('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo'); $listener = new FragmentListener(new UriSigner('foo')); - $event = $this->createGetResponseEvent($request, HttpKernelInterface::SUB_REQUEST); + $event = $this->createRequestEvent($request, HttpKernelInterface::SUB_REQUEST); $listener->onKernelRequest($event); @@ -108,15 +108,15 @@ class FragmentListenerTest extends TestCase $request = Request::create($signer->sign('http://example.com/_fragment?_path=foo%3Dbar'), 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']); $listener = new FragmentListener($signer); - $event = $this->createGetResponseEvent($request); + $event = $this->createRequestEvent($request); $listener->onKernelRequest($event); $this->assertFalse($request->query->has('_path')); } - private function createGetResponseEvent(Request $request, $requestType = HttpKernelInterface::MASTER_REQUEST) + private function createRequestEvent(Request $request, $requestType = HttpKernelInterface::MASTER_REQUEST) { - return new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, $requestType); + return new RequestEvent($this->getMockBuilder(HttpKernelInterface::class)->getMock(), $request, $requestType); } } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/LocaleAwareListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/LocaleAwareListenerTest.php new file mode 100644 index 0000000000..489b02151c --- /dev/null +++ b/vendor/symfony/http-kernel/Tests/EventListener/LocaleAwareListenerTest.php @@ -0,0 +1,119 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\EventListener; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpKernel\Event\FinishRequestEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Contracts\Translation\LocaleAwareInterface; + +class LocaleAwareListenerTest extends TestCase +{ + private $listener; + private $localeAwareService; + private $requestStack; + + protected function setUp() + { + $this->localeAwareService = $this->getMockBuilder(LocaleAwareInterface::class)->getMock(); + $this->requestStack = new RequestStack(); + $this->listener = new LocaleAwareListener(new \ArrayIterator([$this->localeAwareService]), $this->requestStack); + } + + public function testLocaleIsSetInOnKernelRequest() + { + $this->localeAwareService + ->expects($this->once()) + ->method('setLocale') + ->with($this->equalTo('fr')); + + $event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); + $this->listener->onKernelRequest($event); + } + + public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest() + { + $this->localeAwareService + ->expects($this->at(0)) + ->method('setLocale') + ->will($this->throwException(new \InvalidArgumentException())); + $this->localeAwareService + ->expects($this->at(1)) + ->method('setLocale') + ->with($this->equalTo('en')); + + $event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); + $this->listener->onKernelRequest($event); + } + + public function testLocaleIsSetInOnKernelFinishRequestWhenParentRequestExists() + { + $this->localeAwareService + ->expects($this->once()) + ->method('setLocale') + ->with($this->equalTo('fr')); + + $this->requestStack->push($this->createRequest('fr')); + $this->requestStack->push($subRequest = $this->createRequest('de')); + + $event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST); + $this->listener->onKernelFinishRequest($event); + } + + public function testLocaleIsSetToDefaultOnKernelFinishRequestWhenParentRequestDoesNotExist() + { + $this->localeAwareService + ->expects($this->once()) + ->method('setLocale') + ->with($this->equalTo('en')); + + $this->requestStack->push($subRequest = $this->createRequest('de')); + + $event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST); + $this->listener->onKernelFinishRequest($event); + } + + public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest() + { + $this->localeAwareService + ->expects($this->at(0)) + ->method('setLocale') + ->will($this->throwException(new \InvalidArgumentException())); + $this->localeAwareService + ->expects($this->at(1)) + ->method('setLocale') + ->with($this->equalTo('en')); + + $this->requestStack->push($this->createRequest('fr')); + $this->requestStack->push($subRequest = $this->createRequest('de')); + + $event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST); + $this->listener->onKernelFinishRequest($event); + } + + private function createHttpKernel() + { + return $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + } + + private function createRequest($locale) + { + $request = new Request(); + $request->setLocale($locale); + + return $request; + } +} diff --git a/vendor/symfony/http-kernel/Tests/EventListener/LocaleListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/LocaleListenerTest.php index 1cf4b72c69..1e9fbe23b3 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/LocaleListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/LocaleListenerTest.php @@ -12,10 +12,12 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\EventListener\LocaleListener; use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; class LocaleListenerTest extends TestCase { @@ -26,12 +28,28 @@ class LocaleListenerTest extends TestCase $this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->disableOriginalConstructor()->getMock(); } - public function testDefaultLocaleWithoutSession() + public function testIsAnEventSubscriber() + { + $this->assertInstanceOf(EventSubscriberInterface::class, new LocaleListener($this->requestStack)); + } + + public function testRegisteredEvent() + { + $this->assertEquals( + [ + KernelEvents::REQUEST => [['setDefaultLocale', 100], ['onKernelRequest', 16]], + KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]], + ], + LocaleListener::getSubscribedEvents() + ); + } + + public function testDefaultLocale() { $listener = new LocaleListener($this->requestStack, 'fr'); $event = $this->getEvent($request = Request::create('/')); - $listener->onKernelRequest($event); + $listener->setDefaultLocale($event); $this->assertEquals('fr', $request->getLocale()); } @@ -95,8 +113,8 @@ class LocaleListenerTest extends TestCase $this->assertEquals('de', $request->getLocale()); } - private function getEvent(Request $request) + private function getEvent(Request $request): RequestEvent { - return new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); + return new RequestEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); } } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/ProfilerListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/ProfilerListenerTest.php index 392aa2fc35..6e73d0e9b0 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/ProfilerListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/ProfilerListenerTest.php @@ -13,9 +13,9 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\RequestStack; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; -use Symfony\Component\HttpKernel\Event\PostResponseEvent; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; +use Symfony\Component\HttpKernel\Event\TerminateEvent; use Symfony\Component\HttpKernel\EventListener\ProfilerListener; use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Kernel; @@ -59,12 +59,12 @@ class ProfilerListenerTest extends TestCase $listener = new ProfilerListener($profiler, $requestStack, null, $onlyException); // master request - $listener->onKernelResponse(new FilterResponseEvent($kernel, $masterRequest, Kernel::MASTER_REQUEST, $response)); + $listener->onKernelResponse(new ResponseEvent($kernel, $masterRequest, Kernel::MASTER_REQUEST, $response)); // sub request - $listener->onKernelException(new GetResponseForExceptionEvent($kernel, $subRequest, Kernel::SUB_REQUEST, new HttpException(404))); - $listener->onKernelResponse(new FilterResponseEvent($kernel, $subRequest, Kernel::SUB_REQUEST, $response)); + $listener->onKernelException(new ExceptionEvent($kernel, $subRequest, Kernel::SUB_REQUEST, new HttpException(404))); + $listener->onKernelResponse(new ResponseEvent($kernel, $subRequest, Kernel::SUB_REQUEST, $response)); - $listener->onKernelTerminate(new PostResponseEvent($kernel, $masterRequest, $response)); + $listener->onKernelTerminate(new TerminateEvent($kernel, $masterRequest, $response)); } } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/ResponseListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/ResponseListenerTest.php index aeab68f3e9..fbb2512c53 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/ResponseListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/ResponseListenerTest.php @@ -15,7 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\EventListener\ResponseListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; @@ -45,8 +45,8 @@ class ResponseListenerTest extends TestCase { $response = new Response('foo'); - $event = new FilterResponseEvent($this->kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response); - $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($this->kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response); + $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('', $event->getResponse()->headers->get('content-type')); } @@ -58,8 +58,8 @@ class ResponseListenerTest extends TestCase $response = new Response('foo'); - $event = new FilterResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $response); - $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $response); + $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('ISO-8859-15', $response->getCharset()); } @@ -72,8 +72,8 @@ class ResponseListenerTest extends TestCase $response = new Response('foo'); $response->setCharset('ISO-8859-1'); - $event = new FilterResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $response); - $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $response); + $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('ISO-8859-1', $response->getCharset()); } @@ -87,8 +87,8 @@ class ResponseListenerTest extends TestCase $request = Request::create('/'); $request->setRequestFormat('application/json'); - $event = new FilterResponseEvent($this->kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response); - $this->dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response); + $this->dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('ISO-8859-15', $response->getCharset()); } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php index c27b341300..7621ed8e65 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php @@ -18,7 +18,7 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ControllerResolver; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\EventListener\ExceptionListener; use Symfony\Component\HttpKernel\EventListener\RouterListener; use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener; @@ -52,7 +52,7 @@ class RouterListenerTest extends TestCase ->will($this->returnValue($context)); $listener = new RouterListener($urlMatcher, $this->requestStack); - $event = $this->createGetResponseEventForUri($uri); + $event = $this->createRequestEventForUri($uri); $listener->onKernelRequest($event); $this->assertEquals($expectedHttpPort, $context->getHttpPort()); @@ -70,13 +70,13 @@ class RouterListenerTest extends TestCase ]; } - private function createGetResponseEventForUri(string $uri): GetResponseEvent + private function createRequestEventForUri(string $uri): RequestEvent { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create($uri); $request->attributes->set('_controller', null); // Prevents going in to routing process - return new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + return new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); } /** @@ -89,9 +89,9 @@ class RouterListenerTest extends TestCase public function testRequestMatcher() { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('http://localhost/'); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); $requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock(); $requestMatcher->expects($this->once()) @@ -105,9 +105,9 @@ class RouterListenerTest extends TestCase public function testSubRequestWithDifferentMethod() { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('http://localhost/', 'post'); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); $requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock(); $requestMatcher->expects($this->any()) @@ -121,9 +121,9 @@ class RouterListenerTest extends TestCase $listener->onKernelRequest($event); // sub-request with another HTTP method - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('http://localhost/', 'get'); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST); $listener->onKernelRequest($event); @@ -145,11 +145,11 @@ class RouterListenerTest extends TestCase ->method('info') ->with($this->equalTo($log), $this->equalTo($parameters)); - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('http://localhost/'); $listener = new RouterListener($requestMatcher, $this->requestStack, new RequestContext(), $logger); - $listener->onKernelRequest(new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); + $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); } public function getLoggingParameterData() @@ -209,9 +209,9 @@ class RouterListenerTest extends TestCase */ public function testRequestWithBadHost() { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('http://bad host %22/'); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); $requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock(); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php index a903fd5891..6cdd7476c9 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php @@ -15,7 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\EventListener\SaveSessionListener; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -27,7 +27,7 @@ class SaveSessionListenerTest extends TestCase public function testOnlyTriggeredOnMasterRequest() { $listener = new SaveSessionListener(); - $event = $this->getMockBuilder(FilterResponseEvent::class)->disableOriginalConstructor()->getMock(); + $event = $this->getMockBuilder(ResponseEvent::class)->disableOriginalConstructor()->getMock(); $event->expects($this->once())->method('isMasterRequest')->willReturn(false); $event->expects($this->never())->method('getRequest'); @@ -47,6 +47,6 @@ class SaveSessionListenerTest extends TestCase $request = new Request(); $request->setSession($session); $response = new Response(); - $listener->onKernelResponse(new FilterResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response)); + $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response)); } } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php index f931f6dacd..5073e8e3c2 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php @@ -19,9 +19,9 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener; use Symfony\Component\HttpKernel\EventListener\SessionListener; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -31,7 +31,7 @@ class SessionListenerTest extends TestCase public function testOnlyTriggeredOnMasterRequest() { $listener = $this->getMockForAbstractClass(AbstractSessionListener::class); - $event = $this->getMockBuilder(GetResponseEvent::class)->disableOriginalConstructor()->getMock(); + $event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock(); $event->expects($this->once())->method('isMasterRequest')->willReturn(false); $event->expects($this->never())->method('getRequest'); @@ -57,7 +57,7 @@ class SessionListenerTest extends TestCase $request = new Request(); $listener = new SessionListener($container); - $event = $this->getMockBuilder(GetResponseEvent::class)->disableOriginalConstructor()->getMock(); + $event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock(); $event->expects($this->once())->method('isMasterRequest')->willReturn(true); $event->expects($this->once())->method('getRequest')->willReturn($request); @@ -79,10 +79,10 @@ class SessionListenerTest extends TestCase $kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock(); $request = new Request(); - $listener->onKernelRequest(new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); + $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); $response = new Response(); - $listener->onKernelResponse(new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); + $listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); $this->assertTrue($response->headers->hasCacheControlDirective('private')); $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate')); @@ -102,12 +102,12 @@ class SessionListenerTest extends TestCase $kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock(); $request = new Request(); - $listener->onKernelRequest(new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); + $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); $response = new Response(); $response->setSharedMaxAge(60); $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true'); - $listener->onKernelResponse(new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); + $listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); $this->assertTrue($response->headers->hasCacheControlDirective('public')); $this->assertFalse($response->headers->hasCacheControlDirective('private')); @@ -128,7 +128,7 @@ class SessionListenerTest extends TestCase ]); $listener = new SessionListener($container); - $listener->onKernelResponse(new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); + $listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); $this->assertTrue($response->headers->hasCacheControlDirective('public')); $this->assertFalse($response->headers->hasCacheControlDirective('private')); $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate')); @@ -151,20 +151,20 @@ class SessionListenerTest extends TestCase $request = new Request(); $response = new Response(); $response->setCache(['public' => true, 'max_age' => '30']); - $listener->onKernelRequest(new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); + $listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); $this->assertTrue($request->hasSession()); $subRequest = clone $request; $this->assertSame($request->getSession(), $subRequest->getSession()); - $listener->onKernelRequest(new GetResponseEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST)); - $listener->onKernelResponse(new FilterResponseEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST, $response)); + $listener->onKernelRequest(new RequestEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST)); + $listener->onKernelResponse(new ResponseEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST, $response)); $listener->onFinishRequest(new FinishRequestEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST)); $this->assertFalse($response->headers->hasCacheControlDirective('private')); $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate')); $this->assertSame('30', $response->headers->getCacheControlDirective('max-age')); - $listener->onKernelResponse(new FilterResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response)); + $listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response)); $this->assertTrue($response->headers->hasCacheControlDirective('private')); $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate')); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/SurrogateListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/SurrogateListenerTest.php index 66e119f123..fc51de252e 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/SurrogateListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/SurrogateListenerTest.php @@ -15,7 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\EventListener\SurrogateListener; use Symfony\Component\HttpKernel\HttpCache\Esi; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -31,8 +31,8 @@ class SurrogateListenerTest extends TestCase $listener = new SurrogateListener(new Esi()); $dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']); - $event = new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response); - $dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response); + $dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('', $event->getResponse()->headers->get('Surrogate-Control')); } @@ -45,8 +45,8 @@ class SurrogateListenerTest extends TestCase $listener = new SurrogateListener(new Esi()); $dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']); - $event = new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response); - $dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response); + $dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('content="ESI/1.0"', $event->getResponse()->headers->get('Surrogate-Control')); } @@ -59,8 +59,8 @@ class SurrogateListenerTest extends TestCase $listener = new SurrogateListener(new Esi()); $dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']); - $event = new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response); - $dispatcher->dispatch(KernelEvents::RESPONSE, $event); + $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response); + $dispatcher->dispatch($event, KernelEvents::RESPONSE); $this->assertEquals('', $event->getResponse()->headers->get('Surrogate-Control')); } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php index 9f6a5ef759..0eaa63f06a 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php @@ -15,8 +15,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; -use Symfony\Component\HttpKernel\Event\FilterResponseEvent; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\Event\ResponseEvent; use Symfony\Component\HttpKernel\EventListener\SessionListener; use Symfony\Component\HttpKernel\EventListener\TestSessionListener; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -95,9 +95,9 @@ class TestSessionListenerTest extends TestCase $this->sessionIsEmpty(); $this->fixSessionId('456'); - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('/', 'GET', [], ['MOCKSESSID' => '123']); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); $this->listener->onKernelRequest($event); $response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST); @@ -114,9 +114,9 @@ class TestSessionListenerTest extends TestCase $this->sessionIsEmpty(); $this->fixSessionId('456'); - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); $request = Request::create('/', 'GET', [], ['MOCKSESSID' => '123']); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); $this->listener->onKernelRequest($event); $response = new Response('', 200, ['Set-Cookie' => $existing]); @@ -145,8 +145,8 @@ class TestSessionListenerTest extends TestCase public function testDoesNotThrowIfRequestDoesNotHaveASession() { - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); - $event = new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, new Response()); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); + $event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, new Response()); $this->listener->onKernelResponse($event); @@ -157,8 +157,8 @@ class TestSessionListenerTest extends TestCase { $request->setSession($this->session); $response = $response ?: new Response(); - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); - $event = new FilterResponseEvent($kernel, $request, $type, $response); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); + $event = new ResponseEvent($kernel, $request, $type, $response); $this->listener->onKernelResponse($event); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php index c75e7b980f..1627a2b191 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php @@ -14,11 +14,14 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\EventListener\TranslatorListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Contracts\Translation\LocaleAwareInterface; +/** + * @group legacy + */ class TranslatorListenerTest extends TestCase { private $listener; @@ -39,7 +42,7 @@ class TranslatorListenerTest extends TestCase ->method('setLocale') ->with($this->equalTo('fr')); - $event = new GetResponseEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); $this->listener->onKernelRequest($event); } @@ -54,7 +57,7 @@ class TranslatorListenerTest extends TestCase ->method('setLocale') ->with($this->equalTo('en')); - $event = new GetResponseEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST); $this->listener->onKernelRequest($event); } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/ValidateRequestListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/ValidateRequestListenerTest.php index fb7a4379bf..bbd596bc78 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/ValidateRequestListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/ValidateRequestListenerTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Event\GetResponseEvent; +use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; @@ -41,8 +41,8 @@ class ValidateRequestListenerTest extends TestCase $request->headers->set('X_FORWARDED_FOR', '3.3.3.3'); $dispatcher->addListener(KernelEvents::REQUEST, [new ValidateRequestListener(), 'onKernelRequest']); - $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); + $event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST); - $dispatcher->dispatch(KernelEvents::REQUEST, $event); + $dispatcher->dispatch($event, KernelEvents::REQUEST); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/AccessDeniedHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/AccessDeniedHttpExceptionTest.php index 2bfcb2bf80..3a34cc47bc 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/AccessDeniedHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/AccessDeniedHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class AccessDeniedHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new AccessDeniedHttpException(); + return new AccessDeniedHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/BadRequestHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/BadRequestHttpExceptionTest.php index 5fd54ccf44..462fd9cb1d 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/BadRequestHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/BadRequestHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; class BadRequestHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new BadRequestHttpException(); + return new BadRequestHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/ConflictHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/ConflictHttpExceptionTest.php index 63cb49e6e0..760600a10f 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/ConflictHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/ConflictHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\ConflictHttpException; class ConflictHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new ConflictHttpException(); + return new ConflictHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/GoneHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/GoneHttpExceptionTest.php index ec5339d2af..30dafe4922 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/GoneHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/GoneHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\GoneHttpException; class GoneHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new GoneHttpException(); + return new GoneHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/HttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/HttpExceptionTest.php index f5fe97255b..a9431f4b5a 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/HttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/HttpExceptionTest.php @@ -46,8 +46,16 @@ class HttpExceptionTest extends TestCase $this->assertSame($headers, $exception->getHeaders()); } - protected function createException() + public function testThrowableIsAllowedForPrevious() { - return new HttpException(200); + $previous = new class('Error of PHP 7+') extends \Error { + }; + $exception = $this->createException(null, $previous); + $this->assertSame($previous, $exception->getPrevious()); + } + + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) + { + return new HttpException(200, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/LengthRequiredHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/LengthRequiredHttpExceptionTest.php index 462d3ca4fc..8676d67238 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/LengthRequiredHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/LengthRequiredHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException; class LengthRequiredHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new LengthRequiredHttpException(); + return new LengthRequiredHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php index 991f97582d..efb0b50caf 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php @@ -34,4 +34,9 @@ class MethodNotAllowedHttpExceptionTest extends HttpExceptionTest $exception->setHeaders($headers); $this->assertSame($headers, $exception->getHeaders()); } + + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) + { + return new MethodNotAllowedHttpException(['get'], $message, $previous, $code, $headers); + } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/NotAcceptableHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/NotAcceptableHttpExceptionTest.php index 4c0db7a3cb..021c69e289 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/NotAcceptableHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/NotAcceptableHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException; class NotAcceptableHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new NotAcceptableHttpException(); + return new NotAcceptableHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/NotFoundHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/NotFoundHttpExceptionTest.php index 62ede5b4b8..0bf369b1a0 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/NotFoundHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/NotFoundHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class NotFoundHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new NotFoundHttpException(); + return new NotFoundHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php index 809252b757..04d79c499d 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/PreconditionFailedHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException; class PreconditionFailedHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new PreconditionFailedHttpException(); + return new PreconditionFailedHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php index 69d362e3f6..82076617a8 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/PreconditionRequiredHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException; class PreconditionRequiredHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new PreconditionRequiredHttpException(); + return new PreconditionRequiredHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php index daa4fa407a..fac197c852 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php @@ -35,8 +35,8 @@ class ServiceUnavailableHttpExceptionTest extends HttpExceptionTest $this->assertSame($headers, $exception->getHeaders()); } - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new ServiceUnavailableHttpException(); + return new ServiceUnavailableHttpException(null, $message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php index 0048ec85c0..8b59e9894a 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php @@ -35,8 +35,8 @@ class TooManyRequestsHttpExceptionTest extends HttpExceptionTest $this->assertSame($headers, $exception->getHeaders()); } - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new TooManyRequestsHttpException(); + return new TooManyRequestsHttpException(null, $message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php index c7239e70b3..92d427b6e4 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php @@ -34,4 +34,9 @@ class UnauthorizedHttpExceptionTest extends HttpExceptionTest $exception->setHeaders($headers); $this->assertSame($headers, $exception->getHeaders()); } + + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) + { + return new UnauthorizedHttpException('Challenge', $message, $previous, $code, $headers); + } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php index 05d8d787aa..ffa4e177ee 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/UnprocessableEntityHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException; class UnprocessableEntityHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new UnprocessableEntityHttpException(); + return new UnprocessableEntityHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php index 4dae039c11..fa28bbd19b 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/UnsupportedMediaTypeHttpExceptionTest.php @@ -6,8 +6,8 @@ use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException; class UnsupportedMediaTypeHttpExceptionTest extends HttpExceptionTest { - protected function createException() + protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = []) { - return new UnsupportedMediaTypeHttpException(); + return new UnsupportedMediaTypeHttpException($message, $previous, $code, $headers); } } diff --git a/vendor/symfony/http-kernel/Tests/Fixtures/TestClient.php b/vendor/symfony/http-kernel/Tests/Fixtures/TestClient.php index e7d60cff3d..140cbfbf51 100644 --- a/vendor/symfony/http-kernel/Tests/Fixtures/TestClient.php +++ b/vendor/symfony/http-kernel/Tests/Fixtures/TestClient.php @@ -11,9 +11,9 @@ namespace Symfony\Component\HttpKernel\Tests\Fixtures; -use Symfony\Component\HttpKernel\Client; +use Symfony\Component\HttpKernel\HttpKernelBrowser; -class TestClient extends Client +class TestClient extends HttpKernelBrowser { protected function getScript($request) { diff --git a/vendor/symfony/http-kernel/Tests/Fragment/HIncludeFragmentRendererTest.php b/vendor/symfony/http-kernel/Tests/Fragment/HIncludeFragmentRendererTest.php index 6125d95ff4..f80f5f811a 100644 --- a/vendor/symfony/http-kernel/Tests/Fragment/HIncludeFragmentRendererTest.php +++ b/vendor/symfony/http-kernel/Tests/Fragment/HIncludeFragmentRendererTest.php @@ -16,6 +16,8 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerReference; use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer; use Symfony\Component\HttpKernel\UriSigner; +use Twig\Environment; +use Twig\Loader\ArrayLoader; class HIncludeFragmentRendererTest extends TestCase { @@ -74,29 +76,26 @@ class HIncludeFragmentRendererTest extends TestCase $this->assertEquals('<hx:include src="/foo" p1="v1" p2="v2" id="bar">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'id' => 'bar', 'attributes' => ['p1' => 'v1', 'p2' => 'v2']])->getContent()); } - public function testRenderWithDefaultText() + public function testRenderWithTwigAndDefaultText() { - $engine = $this->getMockBuilder('Symfony\\Component\\Templating\\EngineInterface')->getMock(); - $engine->expects($this->once()) - ->method('exists') - ->with('default') - ->willThrowException(new \InvalidArgumentException()); - - // only default - $strategy = new HIncludeFragmentRenderer($engine); - $this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent()); + $twig = new Environment($loader = new ArrayLoader()); + $strategy = new HIncludeFragmentRenderer($twig); + $this->assertEquals('<hx:include src="/foo">loading...</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'loading...'])->getContent()); } - public function testRenderWithEngineAndDefaultText() + /** + * @group legacy + */ + public function testRenderWithDefaultTextLegacy() { $engine = $this->getMockBuilder('Symfony\\Component\\Templating\\EngineInterface')->getMock(); $engine->expects($this->once()) ->method('exists') - ->with('loading...') - ->willThrowException(new \RuntimeException()); + ->with('default') + ->willThrowException(new \InvalidArgumentException()); // only default $strategy = new HIncludeFragmentRenderer($engine); - $this->assertEquals('<hx:include src="/foo">loading...</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'loading...'])->getContent()); + $this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent()); } } diff --git a/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php b/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php index 155493d7f4..d6f0ff7771 100644 --- a/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -17,9 +17,11 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Controller\ControllerReference; +use Symfony\Component\HttpKernel\Event\ExceptionEvent; use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class InlineFragmentRendererTest extends TestCase { @@ -72,7 +74,7 @@ class InlineFragmentRendererTest extends TestCase */ public function testRenderExceptionNoIgnoreErrors() { - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); $dispatcher->expects($this->never())->method('dispatch'); $strategy = new InlineFragmentRenderer($this->getKernel($this->throwException(new \RuntimeException('foo'))), $dispatcher); @@ -82,12 +84,16 @@ class InlineFragmentRendererTest extends TestCase public function testRenderExceptionIgnoreErrors() { - $dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $dispatcher->expects($this->once())->method('dispatch')->with(KernelEvents::EXCEPTION); + $exception = new \RuntimeException('foo'); + $kernel = $this->getKernel($this->throwException($exception)); + $request = Request::create('/'); + $expectedEvent = new ExceptionEvent($kernel, $request, $kernel::SUB_REQUEST, $exception); + $dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock(); + $dispatcher->expects($this->once())->method('dispatch')->with($expectedEvent, KernelEvents::EXCEPTION); - $strategy = new InlineFragmentRenderer($this->getKernel($this->throwException(new \RuntimeException('foo'))), $dispatcher); + $strategy = new InlineFragmentRenderer($kernel, $dispatcher); - $this->assertEmpty($strategy->render('/', Request::create('/'), ['ignore_errors' => true])->getContent()); + $this->assertEmpty($strategy->render('/', $request, ['ignore_errors' => true])->getContent()); } public function testRenderExceptionIgnoreErrorsWithAlt() diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php index 7b3cac78c7..309e8aaaec 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTest.php @@ -1508,6 +1508,44 @@ class HttpCacheTest extends HttpCacheTestCase // Surrogate request $cache->handle($request, HttpKernelInterface::SUB_REQUEST); } + + public function testTraceHeaderNameCanBeChanged() + { + $this->cacheConfig['trace_header'] = 'X-My-Header'; + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertTrue($this->response->headers->has('X-My-Header')); + } + + public function testTraceLevelDefaultsToFullIfDebug() + { + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertTrue($this->response->headers->has('X-Symfony-Cache')); + $this->assertEquals('GET /: miss', $this->response->headers->get('X-Symfony-Cache')); + } + + public function testTraceLevelDefaultsToNoneIfNotDebug() + { + $this->cacheConfig['debug'] = false; + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertFalse($this->response->headers->has('X-Symfony-Cache')); + } + + public function testTraceLevelShort() + { + $this->cacheConfig['trace_level'] = 'short'; + + $this->setNextResponse(); + $this->request('GET', '/'); + + $this->assertTrue($this->response->headers->has('X-Symfony-Cache')); + $this->assertEquals('miss', $this->response->headers->get('X-Symfony-Cache')); + } } class TestKernel implements HttpKernelInterface diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php index 1eb4617447..fde389c28f 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/HttpCacheTestCase.php @@ -122,7 +122,9 @@ class HttpCacheTestCase extends TestCase $this->store = new Store(sys_get_temp_dir().'/http_cache'); - $this->cacheConfig['debug'] = true; + if (!isset($this->cacheConfig['debug'])) { + $this->cacheConfig['debug'] = true; + } $this->esi = $esi ? new Esi() : null; $this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig); diff --git a/vendor/symfony/http-kernel/Tests/ClientTest.php b/vendor/symfony/http-kernel/Tests/HttpKernelBrowserTest.php index c260727849..4447e951f6 100644 --- a/vendor/symfony/http-kernel/Tests/ClientTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpKernelBrowserTest.php @@ -16,17 +16,17 @@ use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\StreamedResponse; -use Symfony\Component\HttpKernel\Client; +use Symfony\Component\HttpKernel\HttpKernelBrowser; use Symfony\Component\HttpKernel\Tests\Fixtures\TestClient; /** * @group time-sensitive */ -class ClientTest extends TestCase +class HttpKernelBrowserTest extends TestCase { public function testDoRequest() { - $client = new Client(new TestHttpKernel()); + $client = new HttpKernelBrowser(new TestHttpKernel()); $client->request('GET', '/'); $this->assertEquals('Request: /', $client->getResponse()->getContent(), '->doRequest() uses the request handler to make the request'); @@ -54,7 +54,7 @@ class ClientTest extends TestCase public function testFilterResponseConvertsCookies() { - $client = new Client(new TestHttpKernel()); + $client = new HttpKernelBrowser(new TestHttpKernel()); $r = new \ReflectionObject($client); $m = $r->getMethod('filterResponse'); @@ -75,7 +75,7 @@ class ClientTest extends TestCase public function testFilterResponseSupportsStreamedResponses() { - $client = new Client(new TestHttpKernel()); + $client = new HttpKernelBrowser(new TestHttpKernel()); $r = new \ReflectionObject($client); $m = $r->getMethod('filterResponse'); @@ -97,7 +97,7 @@ class ClientTest extends TestCase @unlink($target); $kernel = new TestHttpKernel(); - $client = new Client($kernel); + $client = new HttpKernelBrowser($kernel); $files = [ ['tmp_name' => $source, 'name' => 'original', 'type' => 'mime/original', 'size' => null, 'error' => UPLOAD_ERR_OK], @@ -128,7 +128,7 @@ class ClientTest extends TestCase public function testUploadedFileWhenNoFileSelected() { $kernel = new TestHttpKernel(); - $client = new Client($kernel); + $client = new HttpKernelBrowser($kernel); $file = ['tmp_name' => '', 'name' => '', 'type' => '', 'size' => 0, 'error' => UPLOAD_ERR_NO_FILE]; @@ -145,7 +145,7 @@ class ClientTest extends TestCase $source = tempnam(sys_get_temp_dir(), 'source'); $kernel = new TestHttpKernel(); - $client = new Client($kernel); + $client = new HttpKernelBrowser($kernel); $file = $this ->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile') diff --git a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php index 4d1e267e3a..d1162f0431 100644 --- a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php @@ -20,8 +20,6 @@ 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\ControllerDoesNotReturnResponseException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; @@ -128,7 +126,7 @@ class HttpKernelTest extends TestCase public function testHandleWhenAnExceptionIsHandledWithASpecificStatusCode($expectedStatusCode) { $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function (GetResponseForExceptionEvent $event) use ($expectedStatusCode) { + $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) use ($expectedStatusCode) { $event->allowCustomResponseCode(); $event->setResponse(new Response('', $expectedStatusCode)); }); @@ -215,20 +213,19 @@ class HttpKernelTest extends TestCase public function testHandleWhenTheControllerDoesNotReturnAResponse() { $dispatcher = new EventDispatcher(); - $kernel = $this->getHttpKernel($dispatcher, function () { return 'foo'; }); + $kernel = $this->getHttpKernel($dispatcher, function () {}); try { $kernel->handle(new Request()); $this->fail('The kernel should throw an exception.'); } catch (ControllerDoesNotReturnResponseException $e) { - } + $first = $e->getTrace()[0]; - $first = $e->getTrace()[0]; - - // `file` index the array starting at 0, and __FILE__ starts at 1 - $line = file($first['file'])[$first['line'] - 2]; - $this->assertContains('// call controller', $line); + // `file` index the array starting at 0, and __FILE__ starts at 1 + $line = file($first['file'])[$first['line'] - 2]; + $this->assertContains('// call controller', $line); + } } public function testHandleWhenTheControllerDoesNotReturnAResponseButAViewIsRegistered() @@ -257,7 +254,7 @@ class HttpKernelTest extends TestCase public function testHandleAllowChangingControllerArguments() { $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function (FilterControllerArgumentsEvent $event) { + $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function ($event) { $event->setArguments(['foo']); }); @@ -269,7 +266,7 @@ class HttpKernelTest extends TestCase public function testHandleAllowChangingControllerAndArguments() { $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function (FilterControllerArgumentsEvent $event) { + $dispatcher->addListener(KernelEvents::CONTROLLER_ARGUMENTS, function ($event) { $oldController = $event->getController(); $oldArguments = $event->getArguments(); diff --git a/vendor/symfony/http-kernel/Tests/KernelTest.php b/vendor/symfony/http-kernel/Tests/KernelTest.php index 57bd704c92..5be4fc8d83 100644 --- a/vendor/symfony/http-kernel/Tests/KernelTest.php +++ b/vendor/symfony/http-kernel/Tests/KernelTest.php @@ -64,6 +64,20 @@ class KernelTest extends TestCase $this->assertNull($clone->getContainer()); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage The environment "test.env" contains invalid characters, it can only contain characters allowed in PHP class names. + */ + public function testClassNameValidityGetter() + { + // We check the classname that will be generated by using a $env that + // contains invalid characters. + $env = 'test.env'; + $kernel = new KernelForTest($env, false); + + $kernel->boot(); + } + public function testInitializeContainerClearsOldContainers() { $fs = new Filesystem(); @@ -330,9 +344,8 @@ EOF; $env = 'test_env'; $debug = true; $kernel = new KernelForTest($env, $debug); - - $expected = serialize([$env, $debug]); - $this->assertEquals($expected, $kernel->serialize()); + $expected = "O:57:\"Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest\":2:{s:14:\"\0*\0environment\";s:8:\"test_env\";s:8:\"\0*\0debug\";b:1;}"; + $this->assertEquals($expected, serialize($kernel)); } /** diff --git a/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php b/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php index 7354000b16..17865203f2 100644 --- a/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php +++ b/vendor/symfony/http-kernel/Tests/Log/LoggerTest.php @@ -34,7 +34,7 @@ class LoggerTest extends TestCase protected function setUp() { - $this->tmpFile = sys_get_temp_dir().\DIRECTORY_SEPARATOR.'log'; + $this->tmpFile = tempnam(sys_get_temp_dir(), 'log'); $this->logger = new Logger(LogLevel::DEBUG, $this->tmpFile); } diff --git a/vendor/symfony/http-kernel/composer.json b/vendor/symfony/http-kernel/composer.json index 1e5684d579..e07b453b48 100644 --- a/vendor/symfony/http-kernel/composer.json +++ b/vendor/symfony/http-kernel/composer.json @@ -17,19 +17,19 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0.2", - "symfony/event-dispatcher": "~4.1", + "symfony/event-dispatcher": "^4.3", "symfony/http-foundation": "^4.1.1", "symfony/debug": "~3.4|~4.0", "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php73": "^1.9", "psr/log": "~1.0" }, "require-dev": { - "symfony/browser-kit": "~3.4|~4.0", + "symfony/browser-kit": "^4.3", "symfony/config": "~3.4|~4.0", "symfony/console": "~3.4|~4.0", "symfony/css-selector": "~3.4|~4.0", - "symfony/dependency-injection": "^4.2", + "symfony/dependency-injection": "^4.3", "symfony/dom-crawler": "~3.4|~4.0", "symfony/expression-language": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", @@ -38,15 +38,18 @@ "symfony/stopwatch": "~3.4|~4.0", "symfony/templating": "~3.4|~4.0", "symfony/translation": "~4.2", + "symfony/translation-contracts": "^1.1", "symfony/var-dumper": "^4.1.1", - "psr/cache": "~1.0" + "psr/cache": "~1.0", + "twig/twig": "^1.34|^2.4" }, "provide": { "psr/log-implementation": "1.0" }, "conflict": { + "symfony/browser-kit": "<4.3", "symfony/config": "<3.4", - "symfony/dependency-injection": "<4.2", + "symfony/dependency-injection": "<4.3", "symfony/translation": "<4.2", "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" @@ -67,7 +70,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/contracts/.gitignore b/vendor/symfony/mime/.gitignore index 5414c2c655..5414c2c655 100644 --- a/vendor/symfony/contracts/.gitignore +++ b/vendor/symfony/mime/.gitignore diff --git a/vendor/symfony/mime/Address.php b/vendor/symfony/mime/Address.php new file mode 100644 index 0000000000..86a80426db --- /dev/null +++ b/vendor/symfony/mime/Address.php @@ -0,0 +1,98 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Egulias\EmailValidator\EmailValidator; +use Egulias\EmailValidator\Validation\RFCValidation; +use Symfony\Component\Mime\Encoder\IdnAddressEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class Address +{ + private static $validator; + private static $encoder; + + private $address; + + public function __construct(string $address) + { + if (!class_exists(EmailValidator::class)) { + throw new LogicException(sprintf('The "%s" class cannot be used as it needs "%s"; try running "composer require egulias/email-validator".', __CLASS__, EmailValidator::class)); + } + + if (null === self::$validator) { + self::$validator = new EmailValidator(); + } + + if (!self::$validator->isValid($address, new RFCValidation())) { + throw new RfcComplianceException(sprintf('Email "%s" does not comply with addr-spec of RFC 2822.', $address)); + } + + $this->address = $address; + } + + public function getAddress(): string + { + return $this->address; + } + + public function getEncodedAddress(): string + { + if (null === self::$encoder) { + self::$encoder = new IdnAddressEncoder(); + } + + return self::$encoder->encodeString($this->address); + } + + public function toString(): string + { + return $this->getEncodedAddress(); + } + + /** + * @param Address|string $address + */ + public static function create($address): self + { + if ($address instanceof self) { + return $address; + } + if (\is_string($address)) { + return new self($address); + } + + throw new InvalidArgumentException(sprintf('An address can be an instance of Address or a string ("%s") given).', \is_object($address) ? \get_class($address) : \gettype($address))); + } + + /** + * @param (Address|string)[] $addresses + * + * @return Address[] + */ + public static function createArray(array $addresses): array + { + $addrs = []; + foreach ($addresses as $address) { + $addrs[] = self::create($address); + } + + return $addrs; + } +} diff --git a/vendor/symfony/contracts/HttpClient/Exception/ServerExceptionInterface.php b/vendor/symfony/mime/BodyRendererInterface.php index f994ba2ddc..8fcc401595 100644 --- a/vendor/symfony/contracts/HttpClient/Exception/ServerExceptionInterface.php +++ b/vendor/symfony/mime/BodyRendererInterface.php @@ -9,15 +9,14 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\HttpClient\Exception; +namespace Symfony\Component\Mime; /** - * When a 5xx response is returned. + * @author Fabien Potencier <fabien@symfony.com> * - * @author Nicolas Grekas <p@tchwork.com> - * - * @experimental in 1.1 + * @experimental in 4.3 */ -interface ServerExceptionInterface extends HttpExceptionInterface +interface BodyRendererInterface { + public function render(Message $message): void; } diff --git a/vendor/symfony/mime/CharacterStream.php b/vendor/symfony/mime/CharacterStream.php new file mode 100644 index 0000000000..9b80b2efa4 --- /dev/null +++ b/vendor/symfony/mime/CharacterStream.php @@ -0,0 +1,224 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * @author Xavier De Cock <xdecock@gmail.com> + * + * @internal + * + * @experimental in 4.3 + */ +final class CharacterStream +{ + /** Pre-computed for optimization */ + private const UTF8_LENGTH_MAP = [ + "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1, + "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1, + "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1, + "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1, + "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1, + "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1, + "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1, + "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1, + "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1, + "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1, + "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1, + "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1, + "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1, + "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1, + "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1, + "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1, + "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0, + "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0, + "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0, + "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0, + "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0, + "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0, + "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0, + "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0, + "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2, + "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2, + "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2, + "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2, + "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3, + "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3, + "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4, + "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0, + ]; + + private $data = ''; + private $dataSize = 0; + private $map = []; + private $charCount = 0; + private $currentPos = 0; + private $fixedWidth = 0; + + /** + * @param resource|string $input + */ + public function __construct($input, ?string $charset = 'utf-8') + { + $charset = strtolower(trim($charset)) ?: 'utf-8'; + if ('utf-8' === $charset || 'utf8' === $charset) { + $this->fixedWidth = 0; + $this->map = ['p' => [], 'i' => []]; + } else { + switch ($charset) { + // 16 bits + case 'ucs2': + case 'ucs-2': + case 'utf16': + case 'utf-16': + $this->fixedWidth = 2; + break; + + // 32 bits + case 'ucs4': + case 'ucs-4': + case 'utf32': + case 'utf-32': + $this->fixedWidth = 4; + break; + + // 7-8 bit charsets: (us-)?ascii, (iso|iec)-?8859-?[0-9]+, windows-?125[0-9], cp-?[0-9]+, ansi, macintosh, + // koi-?7, koi-?8-?.+, mik, (cork|t1), v?iscii + // and fallback + default: + $this->fixedWidth = 1; + } + } + if (\is_resource($input)) { + $blocks = 512; + if (stream_get_meta_data($input)['seekable'] ?? false) { + rewind($input); + } + while (false !== $read = fread($input, $blocks)) { + $this->write($read); + } + } else { + $this->write($input); + } + } + + public function read(int $length): ?string + { + if ($this->currentPos >= $this->charCount) { + return null; + } + $ret = null; + $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length; + if ($this->fixedWidth > 0) { + $len = $length * $this->fixedWidth; + $ret = substr($this->data, $this->currentPos * $this->fixedWidth, $len); + $this->currentPos += $length; + } else { + $end = $this->currentPos + $length; + $end = $end > $this->charCount ? $this->charCount : $end; + $ret = ''; + $start = 0; + if ($this->currentPos > 0) { + $start = $this->map['p'][$this->currentPos - 1]; + } + $to = $start; + for (; $this->currentPos < $end; ++$this->currentPos) { + if (isset($this->map['i'][$this->currentPos])) { + $ret .= substr($this->data, $start, $to - $start).'?'; + $start = $this->map['p'][$this->currentPos]; + } else { + $to = $this->map['p'][$this->currentPos]; + } + } + $ret .= substr($this->data, $start, $to - $start); + } + + return $ret; + } + + public function readBytes(int $length): ?array + { + if (null !== $read = $this->read($length)) { + return array_map('ord', str_split($read, 1)); + } + + return null; + } + + public function setPointer(int $charOffset): void + { + if ($this->charCount < $charOffset) { + $charOffset = $this->charCount; + } + $this->currentPos = $charOffset; + } + + public function write(string $chars): void + { + $ignored = ''; + $this->data .= $chars; + if ($this->fixedWidth > 0) { + $strlen = \strlen($chars); + $ignoredL = $strlen % $this->fixedWidth; + $ignored = $ignoredL ? substr($chars, -$ignoredL) : ''; + $this->charCount += ($strlen - $ignoredL) / $this->fixedWidth; + } else { + $this->charCount += $this->getUtf8CharPositions($chars, $this->dataSize, $ignored); + } + $this->dataSize = \strlen($this->data) - \strlen($ignored); + } + + private function getUtf8CharPositions(string $string, int $startOffset, &$ignoredChars): int + { + $strlen = \strlen($string); + $charPos = \count($this->map['p']); + $foundChars = 0; + $invalid = false; + for ($i = 0; $i < $strlen; ++$i) { + $char = $string[$i]; + $size = self::UTF8_LENGTH_MAP[$char]; + if (0 == $size) { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue; + } + + if ($invalid) { + /* We mark the chars as invalid and start a new char */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i; + $this->map['i'][$charPos + $foundChars] = true; + ++$foundChars; + $invalid = false; + } + if (($i + $size) > $strlen) { + $ignoredChars = substr($string, $i); + break; + } + for ($j = 1; $j < $size; ++$j) { + $char = $string[$i + $j]; + if ($char > "\x7F" && $char < "\xC0") { + // Valid - continue parsing + } else { + /* char is invalid, we must wait for a resync */ + $invalid = true; + continue 2; + } + } + /* Ok we got a complete char here */ + $this->map['p'][$charPos + $foundChars] = $startOffset + $i + $size; + $i += $j - 1; + ++$foundChars; + } + + return $foundChars; + } +} diff --git a/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php b/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php new file mode 100644 index 0000000000..78450b91bd --- /dev/null +++ b/vendor/symfony/mime/DependencyInjection/AddMimeTypeGuesserPass.php @@ -0,0 +1,48 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Registers custom mime types guessers. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class AddMimeTypeGuesserPass implements CompilerPassInterface +{ + private $mimeTypesService; + private $mimeTypeGuesserTag; + + public function __construct(string $mimeTypesService = 'mime_types', string $mimeTypeGuesserTag = 'mime.mime_type_guesser') + { + $this->mimeTypesService = $mimeTypesService; + $this->mimeTypeGuesserTag = $mimeTypeGuesserTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if ($container->has($this->mimeTypesService)) { + $definition = $container->findDefinition($this->mimeTypesService); + foreach ($container->findTaggedServiceIds($this->mimeTypeGuesserTag, true) as $id => $attributes) { + $definition->addMethodCall('registerGuesser', [new Reference($id)]); + } + } + } +} diff --git a/vendor/symfony/mime/Email.php b/vendor/symfony/mime/Email.php new file mode 100644 index 0000000000..7812372d53 --- /dev/null +++ b/vendor/symfony/mime/Email.php @@ -0,0 +1,589 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class Email extends Message +{ + const PRIORITY_HIGHEST = 1; + const PRIORITY_HIGH = 2; + const PRIORITY_NORMAL = 3; + const PRIORITY_LOW = 4; + const PRIORITY_LOWEST = 5; + + private const PRIORITY_MAP = [ + self::PRIORITY_HIGHEST => 'Highest', + self::PRIORITY_HIGH => 'High', + self::PRIORITY_NORMAL => 'Normal', + self::PRIORITY_LOW => 'Low', + self::PRIORITY_LOWEST => 'Lowest', + ]; + + private $text; + private $textCharset; + private $html; + private $htmlCharset; + private $attachments = []; + + /** + * @return $this + */ + public function subject(string $subject) + { + return $this->setHeaderBody('Text', 'Subject', $subject); + } + + public function getSubject(): ?string + { + return $this->getHeaders()->getHeaderBody('Subject'); + } + + /** + * @return $this + */ + public function date(\DateTimeInterface $dateTime) + { + return $this->setHeaderBody('Date', 'Date', $dateTime); + } + + public function getDate(): ?\DateTimeImmutable + { + return $this->getHeaders()->getHeaderBody('Date'); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function returnPath($address) + { + return $this->setHeaderBody('Path', 'Return-Path', Address::create($address)); + } + + public function getReturnPath(): ?Address + { + return $this->getHeaders()->getHeaderBody('Return-Path'); + } + + /** + * @param Address|string $address + * + * @return $this + */ + public function sender($address) + { + return $this->setHeaderBody('Mailbox', 'Sender', Address::create($address)); + } + + public function getSender(): ?Address + { + return $this->getHeaders()->getHeaderBody('Sender'); + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addFrom(...$addresses) + { + return $this->addListAddressHeaderBody('From', $addresses); + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function from(...$addresses) + { + return $this->setListAddressHeaderBody('From', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getFrom(): array + { + return $this->getHeaders()->getHeaderBody('From') ?: []; + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function addReplyTo(...$addresses) + { + return $this->addListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function replyTo(...$addresses) + { + return $this->setListAddressHeaderBody('Reply-To', $addresses); + } + + /** + * @return Address[] + */ + public function getReplyTo(): array + { + return $this->getHeaders()->getHeaderBody('Reply-To') ?: []; + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addTo(...$addresses) + { + return $this->addListAddressHeaderBody('To', $addresses); + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function to(...$addresses) + { + return $this->setListAddressHeaderBody('To', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getTo(): array + { + return $this->getHeaders()->getHeaderBody('To') ?: []; + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addCc(...$addresses) + { + return $this->addListAddressHeaderBody('Cc', $addresses); + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function cc(...$addresses) + { + return $this->setListAddressHeaderBody('Cc', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getCc(): array + { + return $this->getHeaders()->getHeaderBody('Cc') ?: []; + } + + /** + * @param Address|NamedAddress|string $addresses + * + * @return $this + */ + public function addBcc(...$addresses) + { + return $this->addListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @param Address|string $addresses + * + * @return $this + */ + public function bcc(...$addresses) + { + return $this->setListAddressHeaderBody('Bcc', $addresses); + } + + /** + * @return (Address|NamedAddress)[] + */ + public function getBcc(): array + { + return $this->getHeaders()->getHeaderBody('Bcc') ?: []; + } + + /** + * Sets the priority of this message. + * + * The value is an integer where 1 is the highest priority and 5 is the lowest. + * + * @return $this + */ + public function priority(int $priority) + { + if ($priority > 5) { + $priority = 5; + } elseif ($priority < 1) { + $priority = 1; + } + + return $this->setHeaderBody('Text', 'X-Priority', sprintf('%d (%s)', $priority, self::PRIORITY_MAP[$priority])); + } + + /** + * Get the priority of this message. + * + * The returned value is an integer where 1 is the highest priority and 5 + * is the lowest. + */ + public function getPriority(): int + { + list($priority) = sscanf($this->getHeaders()->getHeaderBody('X-Priority'), '%[1-5]'); + + return $priority ?? 3; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function text($body, string $charset = 'utf-8') + { + $this->text = $body; + $this->textCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getTextBody() + { + return $this->text; + } + + public function getTextCharset(): ?string + { + return $this->textCharset; + } + + /** + * @param resource|string|null $body + * + * @return $this + */ + public function html($body, string $charset = 'utf-8') + { + $this->html = $body; + $this->htmlCharset = $charset; + + return $this; + } + + /** + * @return resource|string|null + */ + public function getHtmlBody() + { + return $this->html; + } + + public function getHtmlCharset(): ?string + { + return $this->htmlCharset; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function attach($body, string $name = null, string $contentType = null) + { + $this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => false]; + + return $this; + } + + /** + * @return $this + */ + public function attachFromPath(string $path, string $name = null, string $contentType = null) + { + $this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => false]; + + return $this; + } + + /** + * @param resource|string $body + * + * @return $this + */ + public function embed($body, string $name = null, string $contentType = null) + { + $this->attachments[] = ['body' => $body, 'name' => $name, 'content-type' => $contentType, 'inline' => true]; + + return $this; + } + + /** + * @return $this + */ + public function embedFromPath(string $path, string $name = null, string $contentType = null) + { + $this->attachments[] = ['path' => $path, 'name' => $name, 'content-type' => $contentType, 'inline' => true]; + + return $this; + } + + /** + * @return $this + */ + public function attachPart(DataPart $part) + { + $this->attachments[] = ['part' => $part]; + + return $this; + } + + /** + * @return DataPart[] + */ + public function getAttachments(): array + { + $parts = []; + foreach ($this->attachments as $attachment) { + $parts[] = $this->createDataPart($attachment); + } + + return $parts; + } + + public function getBody(): AbstractPart + { + if (null !== $body = parent::getBody()) { + return $body; + } + + return $this->generateBody(); + } + + /** + * Generates an AbstractPart based on the raw body of a message. + * + * The most "complex" part generated by this method is when there is text and HTML bodies + * with related images for the HTML part and some attachments: + * + * multipart/mixed + * | + * |------------> multipart/related + * | | + * | |------------> multipart/alternative + * | | | + * | | ------------> text/plain (with content) + * | | | + * | | ------------> text/html (with content) + * | | + * | ------------> image/png (with content) + * | + * ------------> application/pdf (with content) + */ + private function generateBody(): AbstractPart + { + if (null === $this->text && null === $this->html) { + throw new LogicException('A message must have a text and/or an HTML part.'); + } + + $part = null === $this->text ? null : new TextPart($this->text, $this->textCharset); + [$htmlPart, $attachmentParts, $inlineParts] = $this->prepareParts(); + if (null !== $htmlPart) { + if (null !== $part) { + $part = new AlternativePart($part, $htmlPart); + } else { + $part = $htmlPart; + } + } + + if ($inlineParts) { + $part = new RelatedPart($part, ...$inlineParts); + } + + if ($attachmentParts) { + $part = new MixedPart($part, ...$attachmentParts); + } + + return $part; + } + + private function prepareParts(): ?array + { + $names = []; + $htmlPart = null; + $html = $this->html; + if (null !== $this->html) { + if (\is_resource($html)) { + if (stream_get_meta_data($html)['seekable'] ?? false) { + rewind($html); + } + + $html = stream_get_contents($html); + } + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + preg_match_all('(<img\s+[^>]*src\s*=\s*(?:([\'"])cid:([^"]+)\\1|cid:([^>\s]+)))i', $html, $names); + $names = array_filter(array_unique(array_merge($names[2], $names[3]))); + } + + $attachmentParts = $inlineParts = []; + foreach ($this->attachments as $attachment) { + foreach ($names as $name) { + if (isset($attachment['part'])) { + continue; + } + if ($name !== $attachment['name']) { + continue; + } + if (isset($inlineParts[$name])) { + continue 2; + } + $attachment['inline'] = true; + $inlineParts[$name] = $part = $this->createDataPart($attachment); + $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html); + continue 2; + } + $attachmentParts[] = $this->createDataPart($attachment); + } + if (null !== $htmlPart) { + $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); + } + + return [$htmlPart, $attachmentParts, array_values($inlineParts)]; + } + + private function createDataPart(array $attachment): DataPart + { + if (isset($attachment['part'])) { + return $attachment['part']; + } + + if (isset($attachment['body'])) { + $part = new DataPart($attachment['body'], $attachment['name'] ?? null, $attachment['content-type'] ?? null); + } else { + $part = DataPart::fromPath($attachment['path'] ?? '', $attachment['name'] ?? null, $attachment['content-type'] ?? null); + } + if ($attachment['inline']) { + $part->asInline(); + } + + return $part; + } + + /** + * @return $this + */ + private function setHeaderBody(string $type, string $name, $body) + { + $this->getHeaders()->setHeaderBody($type, $name, $body); + + return $this; + } + + private function addListAddressHeaderBody($name, array $addresses) + { + if (!$to = $this->getHeaders()->get($name)) { + return $this->setListAddressHeaderBody($name, $addresses); + } + $to->addAddresses(Address::createArray($addresses)); + + return $this; + } + + private function setListAddressHeaderBody($name, array $addresses) + { + $addresses = Address::createArray($addresses); + $headers = $this->getHeaders(); + if ($to = $headers->get($name)) { + $to->setAddresses($addresses); + } else { + $headers->addMailboxListHeader($name, $addresses); + } + + return $this; + } + + /** + * @internal + */ + public function __serialize(): array + { + if (\is_resource($this->text)) { + if (stream_get_meta_data($this->text)['seekable'] ?? false) { + rewind($this->text); + } + + $this->text = stream_get_contents($this->text); + } + + if (\is_resource($this->html)) { + if (stream_get_meta_data($this->html)['seekable'] ?? false) { + rewind($this->html); + } + + $this->html = stream_get_contents($this->html); + } + + foreach ($this->attachments as $i => $attachment) { + if (isset($attachment['body']) && \is_resource($attachment['body'])) { + if (stream_get_meta_data($attachment['body'])['seekable'] ?? false) { + rewind($attachment['body']); + } + + $this->attachments[$i]['body'] = stream_get_contents($attachment['body']); + } + } + + return [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, parent::__serialize()]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->text, $this->textCharset, $this->html, $this->htmlCharset, $this->attachments, $parentData] = $data; + + parent::__unserialize($parentData); + } +} diff --git a/vendor/symfony/mime/Encoder/AddressEncoderInterface.php b/vendor/symfony/mime/Encoder/AddressEncoderInterface.php new file mode 100644 index 0000000000..5d6ea3c66a --- /dev/null +++ b/vendor/symfony/mime/Encoder/AddressEncoderInterface.php @@ -0,0 +1,30 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\AddressEncoderException; + +/** + * @author Christian Schmidt + * + * @experimental in 4.3 + */ +interface AddressEncoderInterface +{ + /** + * Encodes an email address. + * + * @throws AddressEncoderException if the email cannot be represented in + * the encoding implemented by this class + */ + public function encodeString(string $address): string; +} diff --git a/vendor/symfony/mime/Encoder/Base64ContentEncoder.php b/vendor/symfony/mime/Encoder/Base64ContentEncoder.php new file mode 100644 index 0000000000..e9c352e20e --- /dev/null +++ b/vendor/symfony/mime/Encoder/Base64ContentEncoder.php @@ -0,0 +1,50 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\RuntimeException; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class Base64ContentEncoder extends Base64Encoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + $filter = stream_filter_append($stream, 'convert.base64-encode', \STREAM_FILTER_READ, [ + 'line-length' => 0 >= $maxLineLength || 76 < $maxLineLength ? 76 : $maxLineLength, + 'line-break-chars' => "\r\n", + ]); + if (!\is_resource($filter)) { + throw new RuntimeException('Unable to set the base64 content encoder to the filter.'); + } + + if (stream_get_meta_data($stream)['seekable'] ?? false) { + rewind($stream); + } + while (!feof($stream)) { + yield fread($stream, 8192); + } + stream_filter_remove($filter); + } + + public function getName(): string + { + return 'base64'; + } +} diff --git a/vendor/symfony/mime/Encoder/Base64Encoder.php b/vendor/symfony/mime/Encoder/Base64Encoder.php new file mode 100644 index 0000000000..25dae670b1 --- /dev/null +++ b/vendor/symfony/mime/Encoder/Base64Encoder.php @@ -0,0 +1,43 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class Base64Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * Base64 encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if (0 >= $maxLineLength || 76 < $maxLineLength) { + $maxLineLength = 76; + } + + $encodedString = base64_encode($string); + $firstLine = ''; + if (0 !== $firstLineOffset) { + $firstLine = substr($encodedString, 0, $maxLineLength - $firstLineOffset)."\r\n"; + $encodedString = substr($encodedString, $maxLineLength - $firstLineOffset); + } + + return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n")); + } +} diff --git a/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php b/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php new file mode 100644 index 0000000000..8baee5b02e --- /dev/null +++ b/vendor/symfony/mime/Encoder/Base64MimeHeaderEncoder.php @@ -0,0 +1,45 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class Base64MimeHeaderEncoder extends Base64Encoder implements MimeHeaderEncoderInterface +{ + public function getName(): string + { + return 'B'; + } + + /** + * Takes an unencoded string and produces a Base64 encoded string from it. + * + * If the charset is iso-2022-jp, it uses mb_encode_mimeheader instead of + * default encodeString, otherwise pass to the parent method. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if ('iso-2022-jp' === strtolower($charset)) { + $old = mb_internal_encoding(); + mb_internal_encoding('utf-8'); + $newstring = mb_encode_mimeheader($string, 'iso-2022-jp', $this->getName(), "\r\n"); + mb_internal_encoding($old); + + return $newstring; + } + + return parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength); + } +} diff --git a/vendor/symfony/mime/Encoder/ContentEncoderInterface.php b/vendor/symfony/mime/Encoder/ContentEncoderInterface.php new file mode 100644 index 0000000000..b44e1a4a71 --- /dev/null +++ b/vendor/symfony/mime/Encoder/ContentEncoderInterface.php @@ -0,0 +1,32 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface ContentEncoderInterface extends EncoderInterface +{ + /** + * Encodes the stream to a Generator. + * + * @param resource $stream + */ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable; + + /** + * Gets the MIME name of this content encoding scheme. + */ + public function getName(): string; +} diff --git a/vendor/symfony/mime/Encoder/EightBitContentEncoder.php b/vendor/symfony/mime/Encoder/EightBitContentEncoder.php new file mode 100644 index 0000000000..94b838ce60 --- /dev/null +++ b/vendor/symfony/mime/Encoder/EightBitContentEncoder.php @@ -0,0 +1,37 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class EightBitContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + while (!feof($stream)) { + yield fread($stream, 16372); + } + } + + public function getName(): string + { + return '8bit'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $string; + } +} diff --git a/vendor/symfony/mime/Encoder/EncoderInterface.php b/vendor/symfony/mime/Encoder/EncoderInterface.php new file mode 100644 index 0000000000..3c2ef198e5 --- /dev/null +++ b/vendor/symfony/mime/Encoder/EncoderInterface.php @@ -0,0 +1,28 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface EncoderInterface +{ + /** + * Encode a given string to produce an encoded string. + * + * @param int $firstLineOffset if first line needs to be shorter + * @param int $maxLineLength - 0 indicates the default length for this encoding + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string; +} diff --git a/vendor/symfony/mime/Encoder/IdnAddressEncoder.php b/vendor/symfony/mime/Encoder/IdnAddressEncoder.php new file mode 100644 index 0000000000..8936047ceb --- /dev/null +++ b/vendor/symfony/mime/Encoder/IdnAddressEncoder.php @@ -0,0 +1,56 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\Exception\AddressEncoderException; + +/** + * An IDN email address encoder. + * + * Encodes the domain part of an address using IDN. This is compatible will all + * SMTP servers. + * + * This encoder does not support email addresses with non-ASCII characters in + * local-part (the substring before @). To send to such addresses, use + * Utf8AddressEncoder together with SmtpUtf8Handler. Your outbound SMTP server must support + * the SMTPUTF8 extension. + * + * @author Christian Schmidt + * + * @experimental in 4.3 + */ +final class IdnAddressEncoder implements AddressEncoderInterface +{ + /** + * Encodes the domain part of an address using IDN. + * + * @throws AddressEncoderException If local-part contains non-ASCII characters + */ + public function encodeString(string $address): string + { + $i = strrpos($address, '@'); + if (false !== $i) { + $local = substr($address, 0, $i); + $domain = substr($address, $i + 1); + + if (preg_match('/[^\x00-\x7F]/', $local)) { + throw new AddressEncoderException(sprintf('Non-ASCII characters not supported in local-part os "%s".', $address)); + } + + if (preg_match('/[^\x00-\x7F]/', $domain)) { + $address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46)); + } + } + + return $address; + } +} diff --git a/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php b/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php new file mode 100644 index 0000000000..f5756650ca --- /dev/null +++ b/vendor/symfony/mime/Encoder/MimeHeaderEncoderInterface.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface MimeHeaderEncoderInterface +{ + /** + * Get the MIME name of this content encoding scheme. + */ + public function getName(): string; +} diff --git a/vendor/symfony/mime/Encoder/QpContentEncoder.php b/vendor/symfony/mime/Encoder/QpContentEncoder.php new file mode 100644 index 0000000000..ef2de46f0b --- /dev/null +++ b/vendor/symfony/mime/Encoder/QpContentEncoder.php @@ -0,0 +1,66 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Lars Strojny + * + * @experimental in 4.3 + */ +final class QpContentEncoder implements ContentEncoderInterface +{ + public function encodeByteStream($stream, int $maxLineLength = 0): iterable + { + if (!\is_resource($stream)) { + throw new \TypeError(sprintf('Method "%s" takes a stream as a first argument.', __METHOD__)); + } + + // we don't use PHP stream filters here as the content should be small enough + if (stream_get_meta_data($stream)['seekable'] ?? false) { + rewind($stream); + } + + yield $this->encodeString(stream_get_contents($stream), 'utf-8', 0, $maxLineLength); + } + + public function getName(): string + { + return 'quoted-printable'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return $this->standardize(quoted_printable_encode($string)); + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + */ + private function standardize(string $string): string + { + // transform CR or LF to CRLF + $string = preg_replace('~=0D(?!=0A)|(?<!=0D)=0A~', '=0D=0A', $string); + // transform =0D=0A to CRLF + $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); + + switch (\ord(substr($string, -1))) { + case 0x09: + $string = substr_replace($string, '=09', -1); + break; + case 0x20: + $string = substr_replace($string, '=20', -1); + break; + } + + return $string; + } +} diff --git a/vendor/symfony/mime/Encoder/QpEncoder.php b/vendor/symfony/mime/Encoder/QpEncoder.php new file mode 100644 index 0000000000..4ffbaed78e --- /dev/null +++ b/vendor/symfony/mime/Encoder/QpEncoder.php @@ -0,0 +1,197 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class QpEncoder implements EncoderInterface +{ + /** + * Pre-computed QP for HUGE optimization. + */ + private static $qpMap = [ + 0 => '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04', + 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09', + 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E', + 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13', + 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18', + 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D', + 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22', + 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27', + 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C', + 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31', + 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36', + 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B', + 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40', + 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45', + 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A', + 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F', + 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54', + 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59', + 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E', + 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63', + 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68', + 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D', + 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72', + 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77', + 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C', + 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81', + 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86', + 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B', + 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90', + 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95', + 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A', + 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F', + 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4', + 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9', + 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE', + 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3', + 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8', + 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD', + 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2', + 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7', + 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC', + 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1', + 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6', + 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB', + 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0', + 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5', + 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA', + 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF', + 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4', + 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9', + 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE', + 255 => '=FF', + ]; + + private static $safeMapShare = []; + + /** + * A map of non-encoded ascii characters. + * + * @var string[] + * + * @internal + */ + protected $safeMap = []; + + public function __construct() + { + $id = \get_class($this); + if (!isset(self::$safeMapShare[$id])) { + $this->initSafeMap(); + self::$safeMapShare[$id] = $this->safeMap; + } else { + $this->safeMap = self::$safeMapShare[$id]; + } + } + + protected function initSafeMap(): void + { + foreach (array_merge([0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) { + $this->safeMap[$byte] = \chr($byte); + } + } + + /** + * {@inheritdoc} + * + * Takes an unencoded string and produces a QP encoded string from it. + * + * QP encoded strings have a maximum line length of 76 characters. + * If the first line needs to be shorter, indicate the difference with + * $firstLineOffset. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + if ($maxLineLength > 76 || $maxLineLength <= 0) { + $maxLineLength = 76; + } + + $thisLineLength = $maxLineLength - $firstLineOffset; + + $lines = []; + $lNo = 0; + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $size = $lineLen = 0; + $charStream = new CharacterStream($string, $charset); + + // Fetching more than 4 chars at one is slower, as is fetching fewer bytes + // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6 + // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes + while (null !== $bytes = $charStream->readBytes(4)) { + $enc = $this->encodeByteSequence($bytes, $size); + + $i = strpos($enc, '=0D=0A'); + $newLineLength = $lineLen + (false === $i ? $size : $i); + + if ($currentLine && $newLineLength >= $thisLineLength) { + $lines[$lNo] = ''; + $currentLine = &$lines[$lNo++]; + $thisLineLength = $maxLineLength; + $lineLen = 0; + } + + $currentLine .= $enc; + + if (false === $i) { + $lineLen += $size; + } else { + // 6 is the length of '=0D=0A'. + $lineLen = $size - strrpos($enc, '=0D=0A') - 6; + } + } + + return $this->standardize(implode("=\r\n", $lines)); + } + + /** + * Encode the given byte array into a verbatim QP form. + */ + private function encodeByteSequence(array $bytes, int &$size): string + { + $ret = ''; + $size = 0; + foreach ($bytes as $b) { + if (isset($this->safeMap[$b])) { + $ret .= $this->safeMap[$b]; + ++$size; + } else { + $ret .= self::$qpMap[$b]; + $size += 3; + } + } + + return $ret; + } + + /** + * Make sure CRLF is correct and HT/SPACE are in valid places. + */ + private function standardize(string $string): string + { + $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'], ["=09\r\n", "=20\r\n", "\r\n"], $string); + switch ($end = \ord(substr($string, -1))) { + case 0x09: + case 0x20: + $string = substr_replace($string, self::$qpMap[$end], -1); + } + + return $string; + } +} diff --git a/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php b/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php new file mode 100644 index 0000000000..0413959587 --- /dev/null +++ b/vendor/symfony/mime/Encoder/QpMimeHeaderEncoder.php @@ -0,0 +1,42 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class QpMimeHeaderEncoder extends QpEncoder implements MimeHeaderEncoderInterface +{ + protected function initSafeMap(): void + { + foreach (array_merge( + range(0x61, 0x7A), range(0x41, 0x5A), + range(0x30, 0x39), [0x20, 0x21, 0x2A, 0x2B, 0x2D, 0x2F] + ) as $byte) { + $this->safeMap[$byte] = \chr($byte); + } + } + + public function getName(): string + { + return 'Q'; + } + + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"], + parent::encodeString($string, $charset, $firstLineOffset, $maxLineLength) + ); + } +} diff --git a/vendor/symfony/mime/Encoder/Rfc2231Encoder.php b/vendor/symfony/mime/Encoder/Rfc2231Encoder.php new file mode 100644 index 0000000000..4743a7217c --- /dev/null +++ b/vendor/symfony/mime/Encoder/Rfc2231Encoder.php @@ -0,0 +1,52 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Encoder; + +use Symfony\Component\Mime\CharacterStream; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class Rfc2231Encoder implements EncoderInterface +{ + /** + * Takes an unencoded string and produces a string encoded according to RFC 2231 from it. + */ + public function encodeString(string $string, ?string $charset = 'utf-8', int $firstLineOffset = 0, int $maxLineLength = 0): string + { + $lines = []; + $lineCount = 0; + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + + if (0 >= $maxLineLength) { + $maxLineLength = 75; + } + + $charStream = new CharacterStream($string, $charset); + $thisLineLength = $maxLineLength - $firstLineOffset; + + while (null !== $char = $charStream->read(4)) { + $encodedChar = rawurlencode($char); + if (0 !== \strlen($currentLine) && \strlen($currentLine.$encodedChar) > $thisLineLength) { + $lines[] = ''; + $currentLine = &$lines[$lineCount++]; + $thisLineLength = $maxLineLength; + } + $currentLine .= $encodedChar; + } + + return implode("\r\n", $lines); + } +} diff --git a/vendor/symfony/contracts/HttpClient/Exception/ClientExceptionInterface.php b/vendor/symfony/mime/Exception/AddressEncoderException.php index 5b5fa5084e..73ef7f3222 100644 --- a/vendor/symfony/contracts/HttpClient/Exception/ClientExceptionInterface.php +++ b/vendor/symfony/mime/Exception/AddressEncoderException.php @@ -9,15 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\HttpClient\Exception; +namespace Symfony\Component\Mime\Exception; /** - * When a 4xx response is returned. + * @author Fabien Potencier <fabien@symfony.com> * - * @author Nicolas Grekas <p@tchwork.com> - * - * @experimental in 1.1 + * @experimental in 4.3 */ -interface ClientExceptionInterface extends HttpExceptionInterface +class AddressEncoderException extends RfcComplianceException { } diff --git a/vendor/symfony/contracts/HttpClient/Exception/ExceptionInterface.php b/vendor/symfony/mime/Exception/ExceptionInterface.php index 6d59715f70..7dbcdc72b0 100644 --- a/vendor/symfony/contracts/HttpClient/Exception/ExceptionInterface.php +++ b/vendor/symfony/mime/Exception/ExceptionInterface.php @@ -9,14 +9,12 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\HttpClient\Exception; +namespace Symfony\Component\Mime\Exception; /** - * The base interface for all exceptions in the contract. + * @author Fabien Potencier <fabien@symfony.com> * - * @author Nicolas Grekas <p@tchwork.com> - * - * @experimental in 1.1 + * @experimental in 4.3 */ interface ExceptionInterface extends \Throwable { diff --git a/vendor/symfony/contracts/HttpClient/Exception/TransportExceptionInterface.php b/vendor/symfony/mime/Exception/InvalidArgumentException.php index 1cdc30a2fc..59d04e234e 100644 --- a/vendor/symfony/contracts/HttpClient/Exception/TransportExceptionInterface.php +++ b/vendor/symfony/mime/Exception/InvalidArgumentException.php @@ -9,15 +9,13 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\HttpClient\Exception; +namespace Symfony\Component\Mime\Exception; /** - * When any error happens at the transport level. + * @author Fabien Potencier <fabien@symfony.com> * - * @author Nicolas Grekas <p@tchwork.com> - * - * @experimental in 1.1 + * @experimental in 4.3 */ -interface TransportExceptionInterface extends ExceptionInterface +class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface { } diff --git a/vendor/symfony/mime/Exception/LogicException.php b/vendor/symfony/mime/Exception/LogicException.php new file mode 100644 index 0000000000..07cb044083 --- /dev/null +++ b/vendor/symfony/mime/Exception/LogicException.php @@ -0,0 +1,21 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class LogicException extends \LogicException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/mime/Exception/RfcComplianceException.php b/vendor/symfony/mime/Exception/RfcComplianceException.php new file mode 100644 index 0000000000..5dc4cf5f57 --- /dev/null +++ b/vendor/symfony/mime/Exception/RfcComplianceException.php @@ -0,0 +1,21 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class RfcComplianceException extends \InvalidArgumentException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/mime/Exception/RuntimeException.php b/vendor/symfony/mime/Exception/RuntimeException.php new file mode 100644 index 0000000000..84b11fba6f --- /dev/null +++ b/vendor/symfony/mime/Exception/RuntimeException.php @@ -0,0 +1,21 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Exception; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class RuntimeException extends \RuntimeException implements ExceptionInterface +{ +} diff --git a/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php b/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php new file mode 100644 index 0000000000..a25ebe4d5c --- /dev/null +++ b/vendor/symfony/mime/FileBinaryMimeTypeGuesser.php @@ -0,0 +1,95 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Guesses the MIME type with the binary "file" (only available on *nix). + * + * @author Bernhard Schussek <bschussek@gmail.com> + * + * @experimental in 4.3 + */ +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(string $cmd = 'file -b --mime %s 2>/dev/null') + { + $this->cmd = $cmd; + } + + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + 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 guessMimeType(string $path): ?string + { + if (!is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + } + + if (!$this->isGuesserSupported()) { + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + } + + ob_start(); + + // need to use --mime instead of -i. see #6641 + passthru(sprintf($this->cmd, escapeshellarg($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/mime/FileinfoMimeTypeGuesser.php b/vendor/symfony/mime/FileinfoMimeTypeGuesser.php new file mode 100644 index 0000000000..81c62ee201 --- /dev/null +++ b/vendor/symfony/mime/FileinfoMimeTypeGuesser.php @@ -0,0 +1,65 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Guesses the MIME type using the PECL extension FileInfo. + * + * @author Bernhard Schussek <bschussek@gmail.com> + * + * @experimental in 4.3 + */ +class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface +{ + private $magicFile; + + /** + * @param string $magicFile A magic file to use with the finfo instance + * + * @see http://www.php.net/manual/en/function.finfo-open.php + */ + public function __construct(string $magicFile = null) + { + $this->magicFile = $magicFile; + } + + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + return \function_exists('finfo_open'); + } + + /** + * {@inheritdoc} + */ + public function guessMimeType(string $path): ?string + { + if (!is_file($path) || !is_readable($path)) { + throw new InvalidArgumentException(sprintf('The "%s" file does not exist or is not readable.', $path)); + } + + if (!$this->isGuesserSupported()) { + throw new LogicException(sprintf('The "%s" guesser is not supported.', __CLASS__)); + } + + if (false === $finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { + return null; + } + + return $finfo->file($path); + } +} diff --git a/vendor/symfony/mime/Header/AbstractHeader.php b/vendor/symfony/mime/Header/AbstractHeader.php new file mode 100644 index 0000000000..517ee8dfb2 --- /dev/null +++ b/vendor/symfony/mime/Header/AbstractHeader.php @@ -0,0 +1,281 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; + +/** + * An abstract base MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +abstract class AbstractHeader implements HeaderInterface +{ + const PHRASE_PATTERN = '(?:(?:(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?[a-zA-Z0-9!#\$%&\'\*\+\-\/=\?\^_`\{\}\|~]+(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?)|(?:(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?"((?:(?:[ \t]*(?:\r\n))?[ \t])?(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21\x23-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])))*(?:(?:[ \t]*(?:\r\n))?[ \t])?"(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))*(?:(?:(?:(?:[ \t]*(?:\r\n))?[ \t])?(\((?:(?:(?:[ \t]*(?:\r\n))?[ \t])|(?:(?:[\x01-\x08\x0B\x0C\x0E-\x19\x7F]|[\x21-\x27\x2A-\x5B\x5D-\x7E])|(?:\\[\x00-\x08\x0B\x0C\x0E-\x7F])|(?1)))*(?:(?:[ \t]*(?:\r\n))?[ \t])?\)))|(?:(?:[ \t]*(?:\r\n))?[ \t])))?))+?)'; + + private static $encoder; + + private $name; + private $lineLength = 76; + private $lang; + private $charset = 'utf-8'; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function setCharset(string $charset) + { + $this->charset = $charset; + } + + public function getCharset(): ?string + { + return $this->charset; + } + + /** + * Set the language used in this Header. + * + * For example, for US English, 'en-us'. + */ + public function setLanguage(string $lang) + { + $this->lang = $lang; + } + + public function getLanguage(): ?string + { + return $this->lang; + } + + public function getName(): string + { + return $this->name; + } + + public function setMaxLineLength(int $lineLength) + { + $this->lineLength = $lineLength; + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + public function toString(): string + { + return $this->tokensToString($this->toTokens()); + } + + /** + * Produces a compliant, formatted RFC 2822 'phrase' based on the string given. + * + * @param string $string as displayed + * @param bool $shorten the first line to make remove for header name + */ + protected function createPhrase(HeaderInterface $header, string $string, string $charset, bool $shorten = false): string + { + // Treat token as exactly what was given + $phraseStr = $string; + + // If it's not valid + if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) { + // .. but it is just ascii text, try escaping some characters + // and make it a quoted-string + if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) { + foreach (['\\', '"'] as $char) { + $phraseStr = str_replace($char, '\\'.$char, $phraseStr); + } + $phraseStr = '"'.$phraseStr.'"'; + } else { + // ... otherwise it needs encoding + // Determine space remaining on line if first line + if ($shorten) { + $usedLength = \strlen($header->getName().': '); + } else { + $usedLength = 0; + } + $phraseStr = $this->encodeWords($header, $string, $usedLength); + } + } + + return $phraseStr; + } + + /** + * Encode needed word tokens within a string of input. + */ + protected function encodeWords(HeaderInterface $header, string $input, int $usedLength = -1): string + { + $value = ''; + $tokens = $this->getEncodableWordTokens($input); + foreach ($tokens as $token) { + // See RFC 2822, Sect 2.2 (really 2.2 ??) + if ($this->tokenNeedsEncoding($token)) { + // Don't encode starting WSP + $firstChar = substr($token, 0, 1); + switch ($firstChar) { + case ' ': + case "\t": + $value .= $firstChar; + $token = substr($token, 1); + } + + if (-1 == $usedLength) { + $usedLength = \strlen($header->getName().': ') + \strlen($value); + } + $value .= $this->getTokenAsEncodedWord($token, $usedLength); + } else { + $value .= $token; + } + } + + return $value; + } + + protected function tokenNeedsEncoding(string $token): bool + { + return (bool) preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token); + } + + /** + * Splits a string into tokens in blocks of words which can be encoded quickly. + * + * @return string[] + */ + protected function getEncodableWordTokens(string $string): array + { + $tokens = []; + $encodedToken = ''; + // Split at all whitespace boundaries + foreach (preg_split('~(?=[\t ])~', $string) as $token) { + if ($this->tokenNeedsEncoding($token)) { + $encodedToken .= $token; + } else { + if (\strlen($encodedToken) > 0) { + $tokens[] = $encodedToken; + $encodedToken = ''; + } + $tokens[] = $token; + } + } + if (\strlen($encodedToken)) { + $tokens[] = $encodedToken; + } + + return $tokens; + } + + /** + * Get a token as an encoded word for safe insertion into headers. + */ + protected function getTokenAsEncodedWord(string $token, int $firstLineOffset = 0): string + { + if (null === self::$encoder) { + self::$encoder = new QpMimeHeaderEncoder(); + } + + // Adjust $firstLineOffset to account for space needed for syntax + $charsetDecl = $this->charset; + if (null !== $this->lang) { + $charsetDecl .= '*'.$this->lang; + } + $encodingWrapperLength = \strlen('=?'.$charsetDecl.'?'.self::$encoder->getName().'??='); + + if ($firstLineOffset >= 75) { + //Does this logic need to be here? + $firstLineOffset = 0; + } + + $encodedTextLines = explode("\r\n", + self::$encoder->encodeString($token, $this->charset, $firstLineOffset, 75 - $encodingWrapperLength) + ); + + if ('iso-2022-jp' !== strtolower($this->charset)) { + // special encoding for iso-2022-jp using mb_encode_mimeheader + foreach ($encodedTextLines as $lineNum => $line) { + $encodedTextLines[$lineNum] = '=?'.$charsetDecl.'?'.self::$encoder->getName().'?'.$line.'?='; + } + } + + return implode("\r\n ", $encodedTextLines); + } + + /** + * Generates tokens from the given string which include CRLF as individual tokens. + * + * @return string[] + */ + protected function generateTokenLines(string $token): array + { + return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE); + } + + /** + * Generate a list of all tokens in the final header. + */ + protected function toTokens(string $string = null): array + { + if (null === $string) { + $string = $this->getBodyAsString(); + } + + $tokens = []; + // Generate atoms; split at all invisible boundaries followed by WSP + foreach (preg_split('~(?=[ \t])~', $string) as $token) { + $newTokens = $this->generateTokenLines($token); + foreach ($newTokens as $newToken) { + $tokens[] = $newToken; + } + } + + return $tokens; + } + + /** + * Takes an array of tokens which appear in the header and turns them into + * an RFC 2822 compliant string, adding FWSP where needed. + * + * @param string[] $tokens + */ + private function tokensToString(array $tokens): string + { + $lineCount = 0; + $headerLines = []; + $headerLines[] = $this->name.': '; + $currentLine = &$headerLines[$lineCount++]; + + // Build all tokens back into compliant header + foreach ($tokens as $i => $token) { + // Line longer than specified maximum or token was just a new line + if (("\r\n" === $token) || + ($i > 0 && \strlen($currentLine.$token) > $this->lineLength) + && 0 < \strlen($currentLine)) { + $headerLines[] = ''; + $currentLine = &$headerLines[$lineCount++]; + } + + // Append token to the line + if ("\r\n" !== $token) { + $currentLine .= $token; + } + } + + // Implode with FWS (RFC 2822, 2.2.3) + return implode("\r\n", $headerLines); + } +} diff --git a/vendor/symfony/mime/Header/DateHeader.php b/vendor/symfony/mime/Header/DateHeader.php new file mode 100644 index 0000000000..1e1a979569 --- /dev/null +++ b/vendor/symfony/mime/Header/DateHeader.php @@ -0,0 +1,71 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Date MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class DateHeader extends AbstractHeader +{ + private $dateTime; + + public function __construct(string $name, \DateTimeInterface $date) + { + parent::__construct($name); + + $this->setDateTime($date); + } + + /** + * @param \DateTimeInterface $body + */ + public function setBody($body) + { + $this->setDateTime($body); + } + + /** + * @return \DateTimeImmutable + */ + public function getBody() + { + return $this->getDateTime(); + } + + public function getDateTime(): \DateTimeImmutable + { + return $this->dateTime; + } + + /** + * Set the date-time of the Date in this Header. + * + * If a DateTime instance is provided, it is converted to DateTimeImmutable. + */ + public function setDateTime(\DateTimeInterface $dateTime) + { + if ($dateTime instanceof \DateTime) { + $immutable = new \DateTimeImmutable('@'.$dateTime->getTimestamp()); + $dateTime = $immutable->setTimezone($dateTime->getTimezone()); + } + $this->dateTime = $dateTime; + } + + public function getBodyAsString(): string + { + return $this->dateTime->format(\DateTime::RFC2822); + } +} diff --git a/vendor/symfony/mime/Header/HeaderInterface.php b/vendor/symfony/mime/Header/HeaderInterface.php new file mode 100644 index 0000000000..b0638bca40 --- /dev/null +++ b/vendor/symfony/mime/Header/HeaderInterface.php @@ -0,0 +1,67 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +interface HeaderInterface +{ + /** + * Sets the body. + * + * The type depends on the Header concrete class. + * + * @param mixed $body + */ + public function setBody($body); + + /** + * Gets the body. + * + * The return type depends on the Header concrete class. + * + * @return mixed + */ + public function getBody(); + + public function setCharset(string $charset); + + public function getCharset(): ?string; + + public function setLanguage(string $lang); + + public function getLanguage(): ?string; + + public function getName(): string; + + public function setMaxLineLength(int $lineLength); + + public function getMaxLineLength(): int; + + /** + * Gets this Header rendered as a compliant string. + */ + public function toString(): string; + + /** + * Gets the header's body, prepared for folding into a final header value. + * + * This is not necessarily RFC 2822 compliant since folding white space is + * not added at this stage (see {@link toString()} for that). + */ + public function getBodyAsString(): string; +} diff --git a/vendor/symfony/mime/Header/Headers.php b/vendor/symfony/mime/Header/Headers.php new file mode 100644 index 0000000000..c0e45e0d0a --- /dev/null +++ b/vendor/symfony/mime/Header/Headers.php @@ -0,0 +1,285 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\NamedAddress; + +/** + * A collection of headers. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class Headers +{ + private static $uniqueHeaders = [ + 'date', 'from', 'sender', 'reply-to', 'to', 'cc', 'bcc', + 'message-id', 'in-reply-to', 'references', 'subject', + ]; + + private $headers = []; + private $lineLength = 76; + + public function __construct(HeaderInterface ...$headers) + { + foreach ($headers as $header) { + $this->add($header); + } + } + + public function __clone() + { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $i => $header) { + $this->headers[$name][$i] = clone $header; + } + } + } + + public function setMaxLineLength(int $lineLength) + { + $this->lineLength = $lineLength; + foreach ($this->getAll() as $header) { + $header->setMaxLineLength($lineLength); + } + } + + public function getMaxLineLength(): int + { + return $this->lineLength; + } + + /** + * @param (NamedAddress|Address|string)[] $addresses + * + * @return $this + */ + public function addMailboxListHeader(string $name, array $addresses) + { + return $this->add(new MailboxListHeader($name, Address::createArray($addresses))); + } + + /** + * @param NamedAddress|Address|string $address + * + * @return $this + */ + public function addMailboxHeader(string $name, $address) + { + return $this->add(new MailboxHeader($name, Address::create($address))); + } + + /** + * @param string|array $ids + * + * @return $this + */ + public function addIdHeader(string $name, $ids) + { + return $this->add(new IdentificationHeader($name, $ids)); + } + + /** + * @param Address|string $path + * + * @return $this + */ + public function addPathHeader(string $name, $path) + { + return $this->add(new PathHeader($name, $path instanceof Address ? $path : new Address($path))); + } + + /** + * @return $this + */ + public function addDateHeader(string $name, \DateTimeInterface $dateTime) + { + return $this->add(new DateHeader($name, $dateTime)); + } + + /** + * @return $this + */ + public function addTextHeader(string $name, string $value) + { + return $this->add(new UnstructuredHeader($name, $value)); + } + + /** + * @return $this + */ + public function addParameterizedHeader(string $name, string $value, array $params = []) + { + return $this->add(new ParameterizedHeader($name, $value, $params)); + } + + public function has(string $name): bool + { + return isset($this->headers[strtolower($name)]); + } + + /** + * @return $this + */ + public function add(HeaderInterface $header) + { + static $map = [ + 'date' => DateHeader::class, + 'from' => MailboxListHeader::class, + 'sender' => MailboxHeader::class, + 'reply-to' => MailboxListHeader::class, + 'to' => MailboxListHeader::class, + 'cc' => MailboxListHeader::class, + 'bcc' => MailboxListHeader::class, + 'message-id' => IdentificationHeader::class, + 'in-reply-to' => IdentificationHeader::class, + 'references' => IdentificationHeader::class, + 'return-path' => PathHeader::class, + ]; + + $header->setMaxLineLength($this->lineLength); + $name = strtolower($header->getName()); + + if (isset($map[$name]) && !$header instanceof $map[$name]) { + throw new LogicException(sprintf('The "%s" header must be an instance of "%s" (got "%s").', $header->getName(), $map[$name], \get_class($header))); + } + + if (\in_array($name, self::$uniqueHeaders, true) && isset($this->headers[$name]) && \count($this->headers[$name]) > 0) { + throw new LogicException(sprintf('Impossible to set header "%s" as it\'s already defined and must be unique.', $header->getName())); + } + + $this->headers[$name][] = $header; + + return $this; + } + + public function get(string $name): ?HeaderInterface + { + $name = strtolower($name); + if (!isset($this->headers[$name])) { + return null; + } + + $values = array_values($this->headers[$name]); + + return array_shift($values); + } + + public function getAll(string $name = null): iterable + { + if (null === $name) { + foreach ($this->headers as $name => $collection) { + foreach ($collection as $header) { + yield $name => $header; + } + } + } elseif (isset($this->headers[strtolower($name)])) { + foreach ($this->headers[strtolower($name)] as $header) { + yield $header; + } + } + } + + public function getNames(): array + { + return array_keys($this->headers); + } + + public function remove(string $name): void + { + unset($this->headers[strtolower($name)]); + } + + public static function isUniqueHeader(string $name): bool + { + return \in_array($name, self::$uniqueHeaders, true); + } + + public function toString(): string + { + $string = ''; + foreach ($this->toArray() as $str) { + $string .= $str."\r\n"; + } + + return $string; + } + + public function toArray(): array + { + $arr = []; + foreach ($this->getAll() as $header) { + if ('' !== $header->getBodyAsString()) { + $arr[] = $header->toString(); + } + } + + return $arr; + } + + /** + * @internal + */ + public function getHeaderBody($name) + { + return $this->has($name) ? $this->get($name)->getBody() : null; + } + + /** + * @internal + */ + public function setHeaderBody(string $type, string $name, $body): void + { + if ($this->has($name)) { + $this->get($name)->setBody($body); + } else { + $this->{'add'.$type.'Header'}($name, $body); + } + } + + /** + * @internal + */ + public function getHeaderParameter(string $name, string $parameter): ?string + { + if (!$this->has($name)) { + return null; + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to get parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + return $header->getParameter($parameter); + } + + /** + * @internal + */ + public function setHeaderParameter(string $name, string $parameter, $value): void + { + if (!$this->has($name)) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not defined.', $parameter, $name)); + } + + $header = $this->get($name); + if (!$header instanceof ParameterizedHeader) { + throw new LogicException(sprintf('Unable to set parameter "%s" on header "%s" as the header is not of class "%s".', $parameter, $name, ParameterizedHeader::class)); + } + + $header->setParameter($parameter, $value); + } +} diff --git a/vendor/symfony/mime/Header/IdentificationHeader.php b/vendor/symfony/mime/Header/IdentificationHeader.php new file mode 100644 index 0000000000..0695b688da --- /dev/null +++ b/vendor/symfony/mime/Header/IdentificationHeader.php @@ -0,0 +1,115 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * An ID MIME Header for something like Message-ID or Content-ID (one or more addresses). + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class IdentificationHeader extends AbstractHeader +{ + private $ids = []; + private $idsAsAddresses = []; + + /** + * @param string|array $ids + */ + public function __construct(string $name, $ids) + { + parent::__construct($name); + + $this->setId($ids); + } + + /** + * @param string|array $body a string ID or an array of IDs + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setId($body); + } + + /** + * @return array + */ + public function getBody() + { + return $this->getIds(); + } + + /** + * Set the ID used in the value of this header. + * + * @param string|array $id + * + * @throws RfcComplianceException + */ + public function setId($id) + { + $this->setIds(\is_array($id) ? $id : [$id]); + } + + /** + * Get the ID used in the value of this Header. + * + * If multiple IDs are set only the first is returned. + */ + public function getId(): ?string + { + return $this->ids[0] ?? null; + } + + /** + * Set a collection of IDs to use in the value of this Header. + * + * @param string[] $ids + * + * @throws RfcComplianceException + */ + public function setIds(array $ids) + { + $this->ids = []; + $this->idsAsAddresses = []; + foreach ($ids as $id) { + $this->idsAsAddresses[] = new Address($id); + $this->ids[] = $id; + } + } + + /** + * Get the list of IDs used in this Header. + * + * @return string[] + */ + public function getIds(): array + { + return $this->ids; + } + + public function getBodyAsString(): string + { + $addrs = []; + foreach ($this->idsAsAddresses as $address) { + $addrs[] = '<'.$address->toString().'>'; + } + + return implode(' ', $addrs); + } +} diff --git a/vendor/symfony/mime/Header/MailboxHeader.php b/vendor/symfony/mime/Header/MailboxHeader.php new file mode 100644 index 0000000000..c4f48f3e48 --- /dev/null +++ b/vendor/symfony/mime/Header/MailboxHeader.php @@ -0,0 +1,93 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; +use Symfony\Component\Mime\NamedAddress; + +/** + * A Mailbox MIME Header for something like Sender (one named address). + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class MailboxHeader extends AbstractHeader +{ + private $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddress($body); + } + + /** + * @throws RfcComplianceException + * + * @return Address + */ + public function getBody() + { + return $this->getAddress(); + } + + /** + * @throws RfcComplianceException + */ + public function setAddress(Address $address) + { + $this->address = $address; + } + + /** + * @return Address + */ + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + $str = $this->address->getEncodedAddress(); + if ($this->address instanceof NamedAddress && $name = $this->address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), true).' <'.$str.'>'; + } + + return $str; + } + + /** + * Redefine the encoding requirements for an address. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/vendor/symfony/mime/Header/MailboxListHeader.php b/vendor/symfony/mime/Header/MailboxListHeader.php new file mode 100644 index 0000000000..51af2da87c --- /dev/null +++ b/vendor/symfony/mime/Header/MailboxListHeader.php @@ -0,0 +1,139 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; +use Symfony\Component\Mime\NamedAddress; + +/** + * A Mailbox list MIME Header for something like From, To, Cc, and Bcc (one or more named addresses). + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class MailboxListHeader extends AbstractHeader +{ + private $addresses = []; + + /** + * @param (NamedAddress|Address)[] $addresses + */ + public function __construct(string $name, array $addresses) + { + parent::__construct($name); + + $this->setAddresses($addresses); + } + + /** + * @param (NamedAddress|Address)[] $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddresses($body); + } + + /** + * @throws RfcComplianceException + * + * @return (NamedAddress|Address)[] + */ + public function getBody() + { + return $this->getAddresses(); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param (NamedAddress|Address)[] $addresses + * + * @throws RfcComplianceException + */ + public function setAddresses(array $addresses) + { + $this->addresses = []; + $this->addAddresses($addresses); + } + + /** + * Sets a list of addresses to be shown in this Header. + * + * @param (NamedAddress|Address)[] $addresses + * + * @throws RfcComplianceException + */ + public function addAddresses(array $addresses) + { + foreach ($addresses as $address) { + $this->addAddress($address); + } + } + + /** + * @throws RfcComplianceException + */ + public function addAddress(Address $address) + { + $this->addresses[] = $address; + } + + /** + * @return (NamedAddress|Address)[] + */ + public function getAddresses(): array + { + return $this->addresses; + } + + /** + * Gets the full mailbox list of this Header as an array of valid RFC 2822 strings. + * + * @throws RfcComplianceException + * + * @return string[] + */ + public function getAddressStrings(): array + { + $strings = []; + foreach ($this->addresses as $address) { + $str = $address->getEncodedAddress(); + if ($address instanceof NamedAddress && $name = $address->getName()) { + $str = $this->createPhrase($this, $name, $this->getCharset(), empty($strings)).' <'.$str.'>'; + } + $strings[] = $str; + } + + return $strings; + } + + public function getBodyAsString(): string + { + return implode(', ', $this->getAddressStrings()); + } + + /** + * Redefine the encoding requirements for addresses. + * + * All "specials" must be encoded as the full header value will not be quoted + * + * @see RFC 2822 3.2.1 + */ + protected function tokenNeedsEncoding(string $token): bool + { + return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token); + } +} diff --git a/vendor/symfony/mime/Header/ParameterizedHeader.php b/vendor/symfony/mime/Header/ParameterizedHeader.php new file mode 100644 index 0000000000..5813dcf79f --- /dev/null +++ b/vendor/symfony/mime/Header/ParameterizedHeader.php @@ -0,0 +1,176 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Encoder\Rfc2231Encoder; + +/** + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class ParameterizedHeader extends UnstructuredHeader +{ + /** + * RFC 2231's definition of a token. + * + * @var string + */ + const TOKEN_REGEX = '(?:[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+)'; + + private $encoder; + private $parameters = []; + + public function __construct(string $name, string $value, array $parameters = []) + { + parent::__construct($name, $value); + + foreach ($parameters as $k => $v) { + $this->setParameter($k, $v); + } + + if ('content-disposition' === strtolower($name)) { + $this->encoder = new Rfc2231Encoder(); + } + } + + public function setParameter(string $parameter, ?string $value) + { + $this->setParameters(array_merge($this->getParameters(), [$parameter => $value])); + } + + public function getParameter(string $parameter): string + { + return $this->getParameters()[$parameter] ?? ''; + } + + /** + * @param string[] $parameters + */ + public function setParameters(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * @return string[] + */ + public function getParameters(): array + { + return $this->parameters; + } + + public function getBodyAsString(): string + { + $body = parent::getBodyAsString(); + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + $body .= '; '.$this->createParameter($name, $value); + } + } + + return $body; + } + + /** + * Generate a list of all tokens in the final header. + * + * This doesn't need to be overridden in theory, but it is for implementation + * reasons to prevent potential breakage of attributes. + */ + protected function toTokens(string $string = null): array + { + $tokens = parent::toTokens(parent::getBodyAsString()); + + // Try creating any parameters + foreach ($this->parameters as $name => $value) { + if (null !== $value) { + // Add the semi-colon separator + $tokens[\count($tokens) - 1] .= ';'; + $tokens = array_merge($tokens, $this->generateTokenLines(' '.$this->createParameter($name, $value))); + } + } + + return $tokens; + } + + /** + * Render a RFC 2047 compliant header parameter from the $name and $value. + */ + private function createParameter(string $name, string $value): string + { + $origValue = $value; + + $encoded = false; + // Allow room for parameter name, indices, "=" and DQUOTEs + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1; + $firstLineOffset = 0; + + // If it's not already a valid parameter value... + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + // TODO: text, or something else?? + // ... and it's not ascii + if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) { + $encoded = true; + // Allow space for the indices, charset and language + $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1; + $firstLineOffset = \strlen($this->getCharset()."'".$this->getLanguage()."'"); + } + } + + // Encode if we need to + if ($encoded || \strlen($value) > $maxValueLength) { + if (null !== $this->encoder) { + $value = $this->encoder->encodeString($origValue, $this->getCharset(), $firstLineOffset, $maxValueLength); + } else { + // We have to go against RFC 2183/2231 in some areas for interoperability + $value = $this->getTokenAsEncodedWord($origValue); + $encoded = false; + } + } + + $valueLines = $this->encoder ? explode("\r\n", $value) : [$value]; + + // Need to add indices + if (\count($valueLines) > 1) { + $paramLines = []; + foreach ($valueLines as $i => $line) { + $paramLines[] = $name.'*'.$i.$this->getEndOfParameterValue($line, true, 0 === $i); + } + + return implode(";\r\n ", $paramLines); + } else { + return $name.$this->getEndOfParameterValue($valueLines[0], $encoded, true); + } + } + + /** + * Returns the parameter value from the "=" and beyond. + * + * @param string $value to append + */ + private function getEndOfParameterValue(string $value, bool $encoded = false, bool $firstLine = false): string + { + if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) { + $value = '"'.$value.'"'; + } + $prepend = '='; + if ($encoded) { + $prepend = '*='; + if ($firstLine) { + $prepend = '*='.$this->getCharset()."'".$this->getLanguage()."'"; + } + } + + return $prepend.$value; + } +} diff --git a/vendor/symfony/mime/Header/PathHeader.php b/vendor/symfony/mime/Header/PathHeader.php new file mode 100644 index 0000000000..6d16500a18 --- /dev/null +++ b/vendor/symfony/mime/Header/PathHeader.php @@ -0,0 +1,67 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Exception\RfcComplianceException; + +/** + * A Path Header, such a Return-Path (one address). + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +final class PathHeader extends AbstractHeader +{ + private $address; + + public function __construct(string $name, Address $address) + { + parent::__construct($name); + + $this->setAddress($address); + } + + /** + * @param Address $body + * + * @throws RfcComplianceException + */ + public function setBody($body) + { + $this->setAddress($body); + } + + /** + * @return Address + */ + public function getBody() + { + return $this->getAddress(); + } + + public function setAddress(Address $address) + { + $this->address = $address; + } + + public function getAddress(): Address + { + return $this->address; + } + + public function getBodyAsString(): string + { + return '<'.$this->address->toString().'>'; + } +} diff --git a/vendor/symfony/mime/Header/UnstructuredHeader.php b/vendor/symfony/mime/Header/UnstructuredHeader.php new file mode 100644 index 0000000000..afb9615257 --- /dev/null +++ b/vendor/symfony/mime/Header/UnstructuredHeader.php @@ -0,0 +1,71 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Header; + +/** + * A Simple MIME Header. + * + * @author Chris Corbyn + * + * @experimental in 4.3 + */ +class UnstructuredHeader extends AbstractHeader +{ + private $value; + + public function __construct(string $name, string $value) + { + parent::__construct($name); + + $this->setValue($value); + } + + /** + * @param string $body + */ + public function setBody($body) + { + $this->setValue($body); + } + + /** + * @return string + */ + public function getBody() + { + return $this->getValue(); + } + + /** + * Get the (unencoded) value of this header. + */ + public function getValue(): string + { + return $this->value; + } + + /** + * Set the (unencoded) value of this header. + */ + public function setValue(string $value) + { + $this->value = $value; + } + + /** + * Get the value of this header prepared for rendering. + */ + public function getBodyAsString(): string + { + return $this->encodeWords($this, $this->value); + } +} diff --git a/vendor/symfony/mime/LICENSE b/vendor/symfony/mime/LICENSE new file mode 100644 index 0000000000..9a9a61b1c6 --- /dev/null +++ b/vendor/symfony/mime/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010-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/mime/Message.php b/vendor/symfony/mime/Message.php new file mode 100644 index 0000000000..db6e13fae6 --- /dev/null +++ b/vendor/symfony/mime/Message.php @@ -0,0 +1,148 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Part\AbstractPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class Message extends RawMessage +{ + private $headers; + private $body; + + public function __construct(Headers $headers = null, AbstractPart $body = null) + { + $this->headers = $headers ? clone $headers : new Headers(); + $this->body = $body; + } + + public function __clone() + { + if (null !== $this->headers) { + $this->headers = clone $this->headers; + } + + if (null !== $this->body) { + $this->body = clone $this->body; + } + } + + /** + * @return $this + */ + public function setBody(AbstractPart $body = null) + { + $this->body = $body; + + return $this; + } + + public function getBody(): ?AbstractPart + { + return $this->body; + } + + /** + * @return $this + */ + public function setHeaders(Headers $headers) + { + $this->headers = $headers; + + return $this; + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + + if (!$headers->has('From')) { + throw new LogicException('An email must have a "From" header.'); + } + + $headers->addTextHeader('MIME-Version', '1.0'); + + if (!$headers->has('Date')) { + $headers->addDateHeader('Date', new \DateTimeImmutable()); + } + + // determine the "real" sender + $senders = $headers->get('From')->getAddresses(); + $sender = $senders[0]; + if ($headers->has('Sender')) { + $sender = $headers->get('Sender')->getAddress(); + } elseif (\count($senders) > 1) { + $headers->addMailboxHeader('Sender', $sender); + } + + if (!$headers->has('Message-ID')) { + $headers->addIdHeader('Message-ID', $this->generateMessageId($sender->getAddress())); + } + + // remove the Bcc field which should NOT be part of the sent message + $headers->remove('Bcc'); + + return $headers; + } + + public function toString(): string + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + return $this->getPreparedHeaders()->toString().$body->toString(); + } + + public function toIterable(): iterable + { + if (null === $body = $this->getBody()) { + $body = new TextPart(''); + } + + yield $this->getPreparedHeaders()->toString(); + yield from $body->toIterable(); + } + + private function generateMessageId(string $email): string + { + return bin2hex(random_bytes(16)).strstr($email, '@'); + } + + /** + * @internal + */ + public function __serialize(): array + { + return [$this->headers, $this->body]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->headers, $this->body] = $data; + } +} diff --git a/vendor/symfony/mime/MessageConverter.php b/vendor/symfony/mime/MessageConverter.php new file mode 100644 index 0000000000..287cbd2f1c --- /dev/null +++ b/vendor/symfony/mime/MessageConverter.php @@ -0,0 +1,132 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class MessageConverter +{ + /** + * @throws RuntimeException when unable to convert the message to an email + */ + public static function toEmail(RawMessage $message): Email + { + if ($message instanceof Email) { + return $message; + } + + if (RawMessage::class === \get_class($message)) { + // FIXME: parse the raw message to create the envelope? + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as it is not supported yet.', RawMessage::class)); + } + + // try to convert to a "simple" Email instance + $body = $message->getBody(); + if ($body instanceof TextPart) { + return self::createEmailFromTextPart($message, $body); + } + + if ($body instanceof AlternativePart) { + return self::createEmailFromAlternativePart($message, $body); + } + + if ($body instanceof RelatedPart) { + return self::createEmailFromRelatedPart($message, $body); + } + + if ($body instanceof MixedPart) { + $parts = $body->getParts(); + if ($parts[0] instanceof RelatedPart) { + $email = self::createEmailFromRelatedPart($message, $parts[0]); + } elseif ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + return self::attachParts($email, \array_slice($parts, 1)); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + private static function createEmailFromTextPart(Message $message, TextPart $part): Email + { + if ('text' === $part->getMediaType() && 'plain' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->text($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + if ('text' === $part->getMediaType() && 'html' === $part->getMediaSubtype()) { + return (new Email(clone $message->getHeaders()))->html($part->getBody(), $part->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8'); + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + private static function createEmailFromAlternativePart(Message $message, AlternativePart $part): Email + { + $parts = $part->getParts(); + if ( + 2 === \count($parts) && + $parts[0] instanceof TextPart && 'text' === $parts[0]->getMediaType() && 'plain' === $parts[0]->getMediaSubtype() && + $parts[1] instanceof TextPart && 'text' === $parts[1]->getMediaType() && 'html' === $parts[1]->getMediaSubtype() + ) { + return (new Email(clone $message->getHeaders())) + ->text($parts[0]->getBody(), $parts[0]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ->html($parts[1]->getBody(), $parts[1]->getPreparedHeaders()->getHeaderParameter('Content-Type', 'charset') ?: 'utf-8') + ; + } + + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + private static function createEmailFromRelatedPart(Message $message, RelatedPart $part): Email + { + $parts = $part->getParts(); + if ($parts[0] instanceof AlternativePart) { + $email = self::createEmailFromAlternativePart($message, $parts[0]); + } elseif ($parts[0] instanceof TextPart) { + $email = self::createEmailFromTextPart($message, $parts[0]); + } else { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($message))); + } + + return self::attachParts($email, \array_slice($parts, 1)); + } + + private static function attachParts(Email $email, array $parts): Email + { + foreach ($parts as $part) { + if (!$part instanceof DataPart) { + throw new RuntimeException(sprintf('Unable to create an Email from an instance of "%s" as the body is too complex.', \get_class($email))); + } + + $headers = $part->getPreparedHeaders(); + $method = 'inline' === $headers->getHeaderBody('Content-Disposition') ? 'embed' : 'attach'; + $name = $headers->getHeaderParameter('Content-Disposition', 'filename'); + $email->$method($part->getBody(), $name, $part->getMediaType().'/'.$part->getMediaSubtype()); + } + + return $email; + } +} diff --git a/vendor/symfony/mime/MimeTypeGuesserInterface.php b/vendor/symfony/mime/MimeTypeGuesserInterface.php new file mode 100644 index 0000000000..b7d27f53e2 --- /dev/null +++ b/vendor/symfony/mime/MimeTypeGuesserInterface.php @@ -0,0 +1,39 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * Guesses the MIME type of a file. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +interface MimeTypeGuesserInterface +{ + /** + * Returns true if this guesser is supported. + */ + public function isGuesserSupported(): bool; + + /** + * 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 \LogicException If the guesser is not supported + * @throws \InvalidArgumentException If the file does not exist or is not readable + */ + public function guessMimeType(string $path): ?string; +} diff --git a/vendor/symfony/mime/MimeTypes.php b/vendor/symfony/mime/MimeTypes.php new file mode 100644 index 0000000000..eea75fa2df --- /dev/null +++ b/vendor/symfony/mime/MimeTypes.php @@ -0,0 +1,3154 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +use Symfony\Component\Mime\Exception\LogicException; + +/** + * Manages MIME types and file extensions. + * + * For MIME type guessing, you can register custom guessers + * by calling the registerGuesser() method. + * Custom guessers are always called before any default ones: + * + * $guesser = new MimeTypes(); + * $guesser->registerGuesser(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 = new MimeTypes(); + * $guesser->registerGuesser(new FileinfoMimeTypeGuesser('/path/to/magic/file')); + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class MimeTypes implements MimeTypesInterface +{ + private $extensions = []; + private $mimeTypes = []; + + /** + * @var MimeTypeGuesserInterface[] + */ + private $guessers = []; + private static $default; + + public function __construct(array $map = []) + { + foreach ($map as $mimeType => $extensions) { + $this->extensions[$mimeType] = $extensions; + + foreach ($extensions as $extension) { + $this->mimeTypes[$extension] = $mimeType; + } + } + $this->registerGuesser(new FileBinaryMimeTypeGuesser()); + $this->registerGuesser(new FileinfoMimeTypeGuesser()); + } + + public static function setDefault(self $default) + { + self::$default = $default; + } + + public static function getDefault(): self + { + return self::$default ?? self::$default = new self(); + } + + /** + * Registers a MIME type guesser. + * + * The last registered guesser has precedence over the other ones. + */ + public function registerGuesser(MimeTypeGuesserInterface $guesser) + { + array_unshift($this->guessers, $guesser); + } + + /** + * {@inheritdoc} + */ + public function getExtensions(string $mimeType): array + { + if ($this->extensions) { + $extensions = $this->extensions[$mimeType] ?? $this->extensions[$lcMimeType = strtolower($mimeType)] ?? null; + } + + return $extensions ?? self::$map[$mimeType] ?? self::$map[$lcMimeType ?? strtolower($mimeType)] ?? []; + } + + /** + * {@inheritdoc} + */ + public function getMimeTypes(string $ext): array + { + if ($this->mimeTypes) { + $mimeTypes = $this->mimeTypes[$ext] ?? $this->mimeTypes[$lcExt = strtolower($ext)] ?? null; + } + + return $mimeTypes ?? self::$reverseMap[$ext] ?? self::$reverseMap[$lcExt ?? strtolower($ext)] ?? []; + } + + /** + * {@inheritdoc} + */ + public function isGuesserSupported(): bool + { + foreach ($this->guessers as $guesser) { + if ($guesser->isGuesserSupported()) { + return true; + } + } + + return false; + } + + /** + * {@inheritdoc} + * + * 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. + */ + public function guessMimeType(string $path): ?string + { + foreach ($this->guessers as $guesser) { + if (!$guesser->isGuesserSupported()) { + continue; + } + + if (null !== $mimeType = $guesser->guessMimeType($path)) { + return $mimeType; + } + } + + if (!$this->isGuesserSupported()) { + throw new LogicException('Unable to guess the MIME type as no guessers are available (have you enable the php_fileinfo extension?).'); + } + + return null; + } + + /** + * A map of MIME types and their default extensions. + * + * Updated from upstream on 2019-01-16 + * + * @see Resources/bin/update_mime_types.php + */ + private static $map = [ + 'application/acrobat' => ['pdf'], + 'application/andrew-inset' => ['ez'], + 'application/annodex' => ['anx'], + '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/cdr' => ['cdr'], + 'application/coreldraw' => ['cdr'], + 'application/cu-seeme' => ['cu'], + 'application/davmount+xml' => ['davmount'], + 'application/dbase' => ['dbf'], + 'application/dbf' => ['dbf'], + 'application/dicom' => ['dcm'], + 'application/docbook+xml' => ['dbk', 'docbook'], + 'application/dssc+der' => ['dssc'], + 'application/dssc+xml' => ['xdssc'], + 'application/ecmascript' => ['ecma', 'es'], + 'application/emf' => ['emf'], + 'application/emma+xml' => ['emma'], + 'application/epub+zip' => ['epub'], + 'application/exi' => ['exi'], + 'application/font-tdpfr' => ['pfr'], + 'application/font-woff' => ['woff'], + 'application/futuresplash' => ['swf', 'spl'], + 'application/geo+json' => ['geojson', 'geo.json'], + 'application/gml+xml' => ['gml'], + 'application/gnunet-directory' => ['gnd'], + 'application/gpx' => ['gpx'], + 'application/gpx+xml' => ['gpx'], + 'application/gxf' => ['gxf'], + 'application/gzip' => ['gz'], + 'application/hyperstudio' => ['stk'], + 'application/ico' => ['ico'], + 'application/ics' => ['vcs', 'ics'], + 'application/illustrator' => ['ai'], + 'application/inkml+xml' => ['ink', 'inkml'], + 'application/ipfix' => ['ipfix'], + 'application/java' => ['class'], + 'application/java-archive' => ['jar'], + 'application/java-byte-code' => ['class'], + 'application/java-serialized-object' => ['ser'], + 'application/java-vm' => ['class'], + 'application/javascript' => ['js', 'jsm', 'mjs'], + 'application/jrd+json' => ['jrd'], + 'application/json' => ['json'], + 'application/json-patch+json' => ['json-patch'], + 'application/jsonml+json' => ['jsonml'], + 'application/ld+json' => ['jsonld'], + 'application/lost+xml' => ['lostxml'], + 'application/lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/m3u' => ['m3u', 'm3u8', 'vlc'], + 'application/mac-binhex40' => ['hqx'], + 'application/mac-compactpro' => ['cpt'], + 'application/mads+xml' => ['mads'], + 'application/marc' => ['mrc'], + 'application/marcxml+xml' => ['mrcx'], + 'application/mathematica' => ['ma', 'nb', 'mb'], + 'application/mathml+xml' => ['mathml', 'mml'], + 'application/mbox' => ['mbox'], + 'application/mdb' => ['mdb'], + 'application/mediaservercontrol+xml' => ['mscml'], + 'application/metalink+xml' => ['metalink'], + 'application/metalink4+xml' => ['meta4'], + 'application/mets+xml' => ['mets'], + 'application/mods+xml' => ['mods'], + 'application/mp21' => ['m21', 'mp21'], + 'application/mp4' => ['mp4s'], + 'application/ms-tnef' => ['tnef', 'tnf'], + 'application/msaccess' => ['mdb'], + 'application/msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/msword' => ['doc', 'dot'], + 'application/msword-template' => ['dot'], + 'application/mxf' => ['mxf'], + 'application/nappdf' => ['pdf'], + 'application/octet-stream' => ['bin', 'dms', 'lrf', 'mar', 'so', 'dist', 'distz', 'pkg', 'bpk', 'dump', 'elc', 'deploy'], + 'application/oda' => ['oda'], + 'application/oebps-package+xml' => ['opf'], + 'application/ogg' => ['ogx'], + 'application/omdoc+xml' => ['omdoc'], + 'application/onenote' => ['onetoc', 'onetoc2', 'onetmp', 'onepkg'], + 'application/owl+xml' => ['owx'], + 'application/oxps' => ['oxps', 'xps'], + 'application/patch-ops-error+xml' => ['xer'], + 'application/pcap' => ['pcap', 'cap', 'dmp'], + 'application/pdf' => ['pdf'], + 'application/pgp' => ['pgp', 'gpg', 'asc'], + 'application/pgp-encrypted' => ['pgp', 'gpg', 'asc'], + 'application/pgp-keys' => ['skr', 'pkr', 'asc', 'pgp', 'gpg'], + 'application/pgp-signature' => ['asc', 'sig', 'pgp', 'gpg'], + 'application/photoshop' => ['psd'], + 'application/pics-rules' => ['prf'], + 'application/pkcs10' => ['p10'], + 'application/pkcs12' => ['p12', 'pfx'], + 'application/pkcs7-mime' => ['p7m', 'p7c'], + 'application/pkcs7-signature' => ['p7s'], + 'application/pkcs8' => ['p8'], + 'application/pkcs8-encrypted' => ['p8e'], + 'application/pkix-attr-cert' => ['ac'], + 'application/pkix-cert' => ['cer'], + 'application/pkix-crl' => ['crl'], + 'application/pkix-pkipath' => ['pkipath'], + 'application/pkixcmp' => ['pki'], + 'application/pls' => ['pls'], + 'application/pls+xml' => ['pls'], + 'application/postscript' => ['ai', 'eps', 'ps'], + 'application/powerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/prs.cww' => ['cww'], + 'application/pskc+xml' => ['pskcxml'], + 'application/ram' => ['ram'], + 'application/raml+yaml' => ['raml'], + 'application/rdf+xml' => ['rdf', 'rdfs', 'owl'], + '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/sieve' => ['siv'], + 'application/smil' => ['smil', 'smi', 'sml', 'kino'], + 'application/smil+xml' => ['smi', 'smil', 'sml', 'kino'], + 'application/sparql-query' => ['rq'], + 'application/sparql-results+xml' => ['srx'], + 'application/sql' => ['sql'], + 'application/srgs' => ['gram'], + 'application/srgs+xml' => ['grxml'], + 'application/sru+xml' => ['sru'], + 'application/ssdl+xml' => ['ssdl'], + 'application/ssml+xml' => ['ssml'], + 'application/stuffit' => ['sit'], + 'application/tei+xml' => ['tei', 'teicorpus'], + 'application/thraud+xml' => ['tfi'], + 'application/timestamped-data' => ['tsd'], + 'application/trig' => ['trig'], + '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', 'acutc'], + 'application/vnd.adobe.air-application-installer-package+zip' => ['air'], + 'application/vnd.adobe.flash.movie' => ['swf', 'spl'], + 'application/vnd.adobe.formscentral.fcdt' => ['fcdt'], + 'application/vnd.adobe.fxp' => ['fxp', 'fxpl'], + 'application/vnd.adobe.illustrator' => ['ai'], + '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.appimage' => ['appimage'], + 'application/vnd.apple.installer+xml' => ['mpkg'], + 'application/vnd.apple.keynote' => ['key'], + 'application/vnd.apple.mpegurl' => ['m3u8', 'm3u'], + '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.chess-pgn' => ['pgn'], + 'application/vnd.chipnuts.karaoke-mmd' => ['mmd'], + 'application/vnd.cinderella' => ['cdy'], + 'application/vnd.claymore' => ['cla'], + 'application/vnd.cloanto.rp9' => ['rp9'], + 'application/vnd.clonk.c4group' => ['c4g', 'c4d', 'c4f', 'c4p', 'c4u'], + 'application/vnd.cluetrust.cartomobile-config' => ['c11amc'], + 'application/vnd.cluetrust.cartomobile-config-pkg' => ['c11amz'], + 'application/vnd.coffeescript' => ['coffee'], + 'application/vnd.comicbook+zip' => ['cbz'], + 'application/vnd.comicbook-rar' => ['cbr'], + 'application/vnd.commonspace' => ['csp'], + 'application/vnd.contact.cmsg' => ['cdbcmsg'], + 'application/vnd.corel-draw' => ['cdr'], + '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.debian.binary-package' => ['deb', 'udeb'], + 'application/vnd.dece.data' => ['uvf', 'uvvf', 'uvd', 'uvvd'], + 'application/vnd.dece.ttml+xml' => ['uvt', 'uvvt'], + 'application/vnd.dece.unspecified' => ['uvx', 'uvvx'], + 'application/vnd.dece.zip' => ['uvz', 'uvvz'], + '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.emusic-emusic_package' => ['emp'], + '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', 'et3'], + 'application/vnd.ezpix-album' => ['ez2'], + 'application/vnd.ezpix-package' => ['ez3'], + 'application/vnd.fdf' => ['fdf'], + 'application/vnd.fdsn.mseed' => ['mseed'], + 'application/vnd.fdsn.seed' => ['seed', 'dataless'], + 'application/vnd.flatpak' => ['flatpak', 'xdgapp'], + 'application/vnd.flatpak.ref' => ['flatpakref'], + 'application/vnd.flatpak.repo' => ['flatpakrepo'], + 'application/vnd.flographit' => ['gph'], + 'application/vnd.fluxtime.clip' => ['ftc'], + 'application/vnd.framemaker' => ['fm', 'frame', 'maker', 'book'], + '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.geo+json' => ['geojson', 'geo.json'], + 'application/vnd.geogebra.file' => ['ggb'], + 'application/vnd.geogebra.tool' => ['ggt'], + 'application/vnd.geometry-explorer' => ['gex', 'gre'], + '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', 'gqs'], + '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.haansoft-hwp' => ['hwp'], + 'application/vnd.haansoft-hwt' => ['hwt'], + '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', 'listafp', 'list3820'], + 'application/vnd.ibm.rights-management' => ['irm'], + 'application/vnd.ibm.secure-container' => ['sc'], + 'application/vnd.iccprofile' => ['icc', 'icm'], + 'application/vnd.igloader' => ['igl'], + 'application/vnd.immervision-ivp' => ['ivp'], + 'application/vnd.immervision-ivu' => ['ivu'], + 'application/vnd.insors.igm' => ['igm'], + 'application/vnd.intercon.formnet' => ['xpw', 'xpx'], + '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', 'ktr'], + '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', 'kpt'], + 'application/vnd.kde.kspread' => ['ksp'], + 'application/vnd.kde.kword' => ['kwd', 'kwt'], + 'application/vnd.kenameaapp' => ['htke'], + 'application/vnd.kidspiration' => ['kia'], + 'application/vnd.kinar' => ['kne', 'knp'], + 'application/vnd.koan' => ['skp', 'skd', 'skt', 'skm'], + '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', 'wk1', 'wk3', 'wk4', 'wks'], + '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-access' => ['mdb'], + 'application/vnd.ms-artgalry' => ['cil'], + 'application/vnd.ms-asf' => ['asf'], + 'application/vnd.ms-cab-compressed' => ['cab'], + 'application/vnd.ms-excel' => ['xls', 'xlm', 'xla', 'xlc', 'xlt', 'xlw', 'xll', 'xld'], + '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', 'pps', 'pot', 'ppz'], + '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', 'mpt'], + 'application/vnd.ms-publisher' => ['pub'], + 'application/vnd.ms-tnef' => ['tnef', 'tnf'], + 'application/vnd.ms-visio.drawing.macroenabled.main+xml' => ['vsdm'], + 'application/vnd.ms-visio.drawing.main+xml' => ['vsdx'], + 'application/vnd.ms-visio.stencil.macroenabled.main+xml' => ['vssm'], + 'application/vnd.ms-visio.stencil.main+xml' => ['vssx'], + 'application/vnd.ms-visio.template.macroenabled.main+xml' => ['vstm'], + 'application/vnd.ms-visio.template.main+xml' => ['vstx'], + 'application/vnd.ms-word' => ['doc'], + 'application/vnd.ms-word.document.macroenabled.12' => ['docm'], + 'application/vnd.ms-word.template.macroenabled.12' => ['dotm'], + 'application/vnd.ms-works' => ['wps', 'wks', 'wcm', 'wdb', 'xlr'], + 'application/vnd.ms-wpl' => ['wpl'], + 'application/vnd.ms-xpsdocument' => ['xps', 'oxps'], + 'application/vnd.msaccess' => ['mdb'], + 'application/vnd.mseq' => ['mseq'], + 'application/vnd.musician' => ['mus'], + 'application/vnd.muvee.style' => ['msty'], + 'application/vnd.mynfc' => ['taglet'], + 'application/vnd.neurolanguage.nlu' => ['nlu'], + 'application/vnd.nintendo.snes.rom' => ['sfc', 'smc'], + 'application/vnd.nitf' => ['ntf', 'nitf'], + '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.docbook+xml' => ['dbk', 'docbook'], + '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', 'otf'], + 'application/vnd.oasis.opendocument.graphics' => ['odg'], + 'application/vnd.oasis.opendocument.graphics-flat-xml' => ['fodg'], + '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-flat-xml' => ['fodp'], + 'application/vnd.oasis.opendocument.presentation-template' => ['otp'], + 'application/vnd.oasis.opendocument.spreadsheet' => ['ods'], + 'application/vnd.oasis.opendocument.spreadsheet-flat-xml' => ['fods'], + 'application/vnd.oasis.opendocument.spreadsheet-template' => ['ots'], + 'application/vnd.oasis.opendocument.text' => ['odt'], + 'application/vnd.oasis.opendocument.text-flat-xml' => ['fodt'], + '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', 'pqa', 'oprc', 'prc'], + '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', 'qxt', 'qwd', 'qwt', 'qxl', 'qxb'], + 'application/vnd.rar' => ['rar'], + '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', 'rmj', 'rmm', 'rms', 'rmx', 'rmvb'], + 'application/vnd.rn-realmedia-vbr' => ['rmvb', 'rm', 'rmj', 'rmm', 'rms', 'rmx'], + 'application/vnd.route66.link66+xml' => ['link66'], + 'application/vnd.sailingtracker.track' => ['st'], + 'application/vnd.sdp' => ['sdp'], + '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', 'twds'], + 'application/vnd.smaf' => ['mmf', 'smaf'], + 'application/vnd.smart.teacher' => ['teacher'], + 'application/vnd.snap' => ['snap'], + 'application/vnd.solent.sdkm+xml' => ['sdkm', 'sdkd'], + 'application/vnd.spotfire.dxp' => ['dxp'], + 'application/vnd.spotfire.sfs' => ['sfs'], + 'application/vnd.sqlite3' => ['sqlite3'], + 'application/vnd.squashfs' => ['sqsh'], + 'application/vnd.stardivision.calc' => ['sdc'], + 'application/vnd.stardivision.chart' => ['sds'], + 'application/vnd.stardivision.draw' => ['sda'], + 'application/vnd.stardivision.impress' => ['sdd', 'sdp'], + 'application/vnd.stardivision.mail' => ['smd'], + 'application/vnd.stardivision.math' => ['smf'], + 'application/vnd.stardivision.writer' => ['sdw', 'vor', 'sgl'], + 'application/vnd.stardivision.writer-global' => ['sgl', 'sdw', 'vor'], + 'application/vnd.stepmania.package' => ['smzip'], + 'application/vnd.stepmania.stepchart' => ['sm'], + 'application/vnd.sun.xml.base' => ['odb'], + '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', 'susp'], + 'application/vnd.svd' => ['svd'], + 'application/vnd.symbian.install' => ['sis', 'sisx'], + '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', 'cap', 'dmp'], + 'application/vnd.tmobile-livetv' => ['tmo'], + 'application/vnd.trid.tpt' => ['tpt'], + 'application/vnd.triscape.mxs' => ['mxs'], + 'application/vnd.trueapp' => ['tra'], + 'application/vnd.ufdl' => ['ufd', 'ufdl'], + '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', 'vst', 'vss', 'vsw'], + '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', 'wp', 'wp4', 'wp5', 'wp6', 'wpp'], + 'application/vnd.wqd' => ['wqd'], + 'application/vnd.wt.stf' => ['stf'], + 'application/vnd.xara' => ['xar'], + 'application/vnd.xdgapp' => ['flatpak', 'xdgapp'], + '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.youtube.yt' => ['yt'], + 'application/vnd.zul' => ['zir', 'zirz'], + 'application/vnd.zzazz.deck+xml' => ['zaz'], + 'application/voicexml+xml' => ['vxml'], + 'application/widget' => ['wgt'], + 'application/winhlp' => ['hlp'], + 'application/wk1' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/wmf' => ['wmf'], + 'application/wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], + 'application/wsdl+xml' => ['wsdl'], + 'application/wspolicy+xml' => ['wspolicy'], + 'application/wwf' => ['wwf'], + 'application/x-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/x-7z-compressed' => ['7z'], + 'application/x-abiword' => ['abw', 'abw.CRASHED', 'abw.gz', 'zabw'], + 'application/x-ace' => ['ace'], + 'application/x-ace-compressed' => ['ace'], + 'application/x-alz' => ['alz'], + 'application/x-amiga-disk-format' => ['adf'], + 'application/x-amipro' => ['sam'], + 'application/x-annodex' => ['anx'], + 'application/x-aportisdoc' => ['pdb', 'pdc'], + 'application/x-apple-diskimage' => ['dmg'], + 'application/x-applix-spreadsheet' => ['as'], + 'application/x-applix-word' => ['aw'], + 'application/x-archive' => ['a', 'ar'], + 'application/x-arj' => ['arj'], + 'application/x-asp' => ['asp'], + 'application/x-atari-2600-rom' => ['a26'], + 'application/x-atari-7800-rom' => ['a78'], + 'application/x-atari-lynx-rom' => ['lnx'], + 'application/x-authorware-bin' => ['aab', 'x32', 'u32', 'vox'], + 'application/x-authorware-map' => ['aam'], + 'application/x-authorware-seg' => ['aas'], + 'application/x-awk' => ['awk'], + 'application/x-bcpio' => ['bcpio'], + 'application/x-bittorrent' => ['torrent'], + 'application/x-blender' => ['blender', 'blend', 'BLEND'], + 'application/x-blorb' => ['blb', 'blorb'], + 'application/x-bsdiff' => ['bsdiff'], + 'application/x-bzdvi' => ['dvi.bz2'], + 'application/x-bzip' => ['bz', 'bz2'], + 'application/x-bzip-compressed-tar' => ['tar.bz2', 'tar.bz', 'tbz2', 'tbz', 'tb2'], + 'application/x-bzip2' => ['bz2', 'boz', 'bz'], + 'application/x-bzpdf' => ['pdf.bz2'], + 'application/x-bzpostscript' => ['ps.bz2'], + 'application/x-cb7' => ['cb7'], + 'application/x-cbr' => ['cbr', 'cba', 'cbt', 'cbz', 'cb7'], + 'application/x-cbt' => ['cbt'], + 'application/x-cbz' => ['cbz'], + 'application/x-ccmx' => ['ccmx'], + 'application/x-cd-image' => ['iso', 'iso9660'], + 'application/x-cdlink' => ['vcd'], + 'application/x-cdr' => ['cdr'], + 'application/x-cdrdao-toc' => ['toc'], + 'application/x-cfs-compressed' => ['cfs'], + 'application/x-chat' => ['chat'], + 'application/x-chess-pgn' => ['pgn'], + 'application/x-chm' => ['chm'], + 'application/x-cisco-vpn-settings' => ['pcf'], + 'application/x-compress' => ['Z'], + 'application/x-compressed-tar' => ['tar.gz', 'tgz'], + 'application/x-conference' => ['nsc'], + 'application/x-coreldraw' => ['cdr'], + 'application/x-cpio' => ['cpio'], + 'application/x-cpio-compressed' => ['cpio.gz'], + 'application/x-csh' => ['csh'], + 'application/x-cue' => ['cue'], + 'application/x-dar' => ['dar'], + 'application/x-dbase' => ['dbf'], + 'application/x-dbf' => ['dbf'], + 'application/x-dc-rom' => ['dc'], + 'application/x-deb' => ['deb', 'udeb'], + 'application/x-debian-package' => ['deb', 'udeb'], + 'application/x-designer' => ['ui'], + 'application/x-desktop' => ['desktop', 'kdelnk'], + 'application/x-dgc-compressed' => ['dgc'], + 'application/x-dia-diagram' => ['dia'], + 'application/x-dia-shape' => ['shape'], + 'application/x-director' => ['dir', 'dcr', 'dxr', 'cst', 'cct', 'cxt', 'w3d', 'fgd', 'swa'], + 'application/x-docbook+xml' => ['dbk', 'docbook'], + 'application/x-doom' => ['wad'], + 'application/x-doom-wad' => ['wad'], + 'application/x-dtbncx+xml' => ['ncx'], + 'application/x-dtbook+xml' => ['dtb'], + 'application/x-dtbresource+xml' => ['res'], + 'application/x-dvi' => ['dvi'], + 'application/x-e-theme' => ['etheme'], + 'application/x-egon' => ['egon'], + 'application/x-emf' => ['emf'], + 'application/x-envoy' => ['evy'], + 'application/x-eva' => ['eva'], + 'application/x-fd-file' => ['fd', 'qd'], + 'application/x-fds-disk' => ['fds'], + 'application/x-fictionbook' => ['fb2'], + 'application/x-fictionbook+xml' => ['fb2'], + 'application/x-flash-video' => ['flv'], + 'application/x-fluid' => ['fl'], + 'application/x-font-afm' => ['afm'], + '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', 'pcf.Z', 'pcf.gz'], + 'application/x-font-snf' => ['snf'], + 'application/x-font-speedo' => ['spd'], + 'application/x-font-ttf' => ['ttf'], + 'application/x-font-ttx' => ['ttx'], + 'application/x-font-type1' => ['pfa', 'pfb', 'pfm', 'afm', 'gsf'], + 'application/x-font-woff' => ['woff'], + 'application/x-frame' => ['fm'], + 'application/x-freearc' => ['arc'], + 'application/x-futuresplash' => ['spl'], + 'application/x-gameboy-color-rom' => ['gbc', 'cgb'], + 'application/x-gameboy-rom' => ['gb', 'sgb'], + 'application/x-gamecube-iso-image' => ['iso'], + 'application/x-gamecube-rom' => ['iso'], + 'application/x-gamegear-rom' => ['gg'], + 'application/x-gba-rom' => ['gba', 'agb'], + 'application/x-gca-compressed' => ['gca'], + 'application/x-gedcom' => ['ged', 'gedcom'], + 'application/x-genesis-32x-rom' => ['32x', 'mdx'], + 'application/x-genesis-rom' => ['gen', 'smd'], + 'application/x-gettext' => ['po'], + 'application/x-gettext-translation' => ['gmo', 'mo'], + 'application/x-glade' => ['glade'], + 'application/x-glulx' => ['ulx'], + 'application/x-gnome-app-info' => ['desktop', 'kdelnk'], + 'application/x-gnucash' => ['gnucash', 'gnc', 'xac'], + 'application/x-gnumeric' => ['gnumeric'], + 'application/x-gnuplot' => ['gp', 'gplt', 'gnuplot'], + 'application/x-go-sgf' => ['sgf'], + 'application/x-gpx' => ['gpx'], + 'application/x-gpx+xml' => ['gpx'], + 'application/x-gramps-xml' => ['gramps'], + 'application/x-graphite' => ['gra'], + 'application/x-gtar' => ['gtar', 'tar', 'gem'], + 'application/x-gtk-builder' => ['ui'], + 'application/x-gz-font-linux-psf' => ['psf.gz'], + 'application/x-gzdvi' => ['dvi.gz'], + 'application/x-gzip' => ['gz'], + 'application/x-gzpdf' => ['pdf.gz'], + 'application/x-gzpostscript' => ['ps.gz'], + 'application/x-hdf' => ['hdf', 'hdf4', 'h4', 'hdf5', 'h5'], + 'application/x-hfe-file' => ['hfe'], + 'application/x-hfe-floppy-image' => ['hfe'], + 'application/x-hwp' => ['hwp'], + 'application/x-hwt' => ['hwt'], + 'application/x-ica' => ['ica'], + 'application/x-install-instructions' => ['install'], + 'application/x-ipynb+json' => ['ipynb'], + 'application/x-iso9660-appimage' => ['appimage'], + 'application/x-iso9660-image' => ['iso', 'iso9660'], + 'application/x-it87' => ['it87'], + 'application/x-iwork-keynote-sffkey' => ['key'], + 'application/x-jar' => ['jar'], + 'application/x-java' => ['class'], + 'application/x-java-archive' => ['jar'], + 'application/x-java-class' => ['class'], + 'application/x-java-jce-keystore' => ['jceks'], + 'application/x-java-jnlp-file' => ['jnlp'], + 'application/x-java-keystore' => ['jks', 'ks'], + 'application/x-java-pack200' => ['pack'], + 'application/x-java-vm' => ['class'], + 'application/x-javascript' => ['js', 'jsm', 'mjs'], + 'application/x-jbuilder-project' => ['jpr', 'jpx'], + 'application/x-karbon' => ['karbon'], + 'application/x-kchart' => ['chrt'], + 'application/x-kexi-connectiondata' => ['kexic'], + 'application/x-kexiproject-shortcut' => ['kexis'], + 'application/x-kexiproject-sqlite' => ['kexi'], + 'application/x-kexiproject-sqlite2' => ['kexi'], + 'application/x-kexiproject-sqlite3' => ['kexi'], + 'application/x-kformula' => ['kfo'], + 'application/x-killustrator' => ['kil'], + 'application/x-kivio' => ['flw'], + 'application/x-kontour' => ['kon'], + 'application/x-kpovmodeler' => ['kpm'], + 'application/x-kpresenter' => ['kpr', 'kpt'], + 'application/x-krita' => ['kra'], + 'application/x-kspread' => ['ksp'], + 'application/x-kugar' => ['kud'], + 'application/x-kword' => ['kwd', 'kwt'], + 'application/x-latex' => ['latex'], + 'application/x-lha' => ['lha', 'lzh'], + 'application/x-lhz' => ['lhz'], + 'application/x-linguist' => ['ts'], + 'application/x-lotus123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'application/x-lrzip' => ['lrz'], + 'application/x-lrzip-compressed-tar' => ['tar.lrz', 'tlrz'], + 'application/x-lyx' => ['lyx'], + 'application/x-lz4' => ['lz4'], + 'application/x-lz4-compressed-tar' => ['tar.lz4'], + 'application/x-lzh-compressed' => ['lzh', 'lha'], + 'application/x-lzip' => ['lz'], + 'application/x-lzip-compressed-tar' => ['tar.lz'], + 'application/x-lzma' => ['lzma'], + 'application/x-lzma-compressed-tar' => ['tar.lzma', 'tlz'], + 'application/x-lzop' => ['lzo'], + 'application/x-lzpdf' => ['pdf.lz'], + 'application/x-m4' => ['m4'], + 'application/x-magicpoint' => ['mgp'], + 'application/x-markaby' => ['mab'], + 'application/x-mathematica' => ['nb'], + 'application/x-mdb' => ['mdb'], + 'application/x-mie' => ['mie'], + 'application/x-mif' => ['mif'], + 'application/x-mimearchive' => ['mhtml', 'mht'], + 'application/x-mobipocket-ebook' => ['prc', 'mobi'], + 'application/x-ms-application' => ['application'], + 'application/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], + 'application/x-ms-dos-executable' => ['exe'], + 'application/x-ms-shortcut' => ['lnk'], + 'application/x-ms-wim' => ['wim', 'swm'], + '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', 'dll', 'com', 'bat', 'msi'], + 'application/x-msexcel' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + 'application/x-msi' => ['msi'], + 'application/x-msmediaview' => ['mvb', 'm13', 'm14'], + 'application/x-msmetafile' => ['wmf', 'wmz', 'emf', 'emz'], + 'application/x-msmoney' => ['mny'], + 'application/x-mspowerpoint' => ['ppz', 'ppt', 'pps', 'pot'], + 'application/x-mspublisher' => ['pub'], + 'application/x-msschedule' => ['scd'], + 'application/x-msterminal' => ['trm'], + 'application/x-mswinurl' => ['url'], + 'application/x-msword' => ['doc'], + 'application/x-mswrite' => ['wri'], + 'application/x-msx-rom' => ['msx'], + 'application/x-n64-rom' => ['n64', 'z64', 'v64'], + 'application/x-navi-animation' => ['ani'], + 'application/x-neo-geo-pocket-color-rom' => ['ngc'], + 'application/x-neo-geo-pocket-rom' => ['ngp'], + 'application/x-nes-rom' => ['nes', 'nez', 'unf', 'unif'], + 'application/x-netcdf' => ['nc', 'cdf'], + 'application/x-netshow-channel' => ['nsc'], + 'application/x-nintendo-ds-rom' => ['nds'], + 'application/x-nzb' => ['nzb'], + 'application/x-object' => ['o'], + 'application/x-ogg' => ['ogx'], + 'application/x-oleo' => ['oleo'], + 'application/x-pagemaker' => ['p65', 'pm', 'pm6', 'pmd'], + 'application/x-pak' => ['pak'], + 'application/x-palm-database' => ['prc', 'pdb', 'pqa', 'oprc'], + 'application/x-par2' => ['PAR2', 'par2'], + 'application/x-partial-download' => ['wkdownload', 'crdownload', 'part'], + 'application/x-pc-engine-rom' => ['pce'], + 'application/x-pcap' => ['pcap', 'cap', 'dmp'], + 'application/x-pdf' => ['pdf'], + 'application/x-perl' => ['pl', 'PL', 'pm', 'al', 'perl', 'pod', 't'], + 'application/x-photoshop' => ['psd'], + 'application/x-php' => ['php', 'php3', 'php4', 'php5', 'phps'], + 'application/x-pkcs12' => ['p12', 'pfx'], + 'application/x-pkcs7-certificates' => ['p7b', 'spc'], + 'application/x-pkcs7-certreqresp' => ['p7r'], + 'application/x-planperfect' => ['pln'], + 'application/x-pocket-word' => ['psw'], + 'application/x-pw' => ['pw'], + 'application/x-python-bytecode' => ['pyc', 'pyo'], + 'application/x-qpress' => ['qp'], + 'application/x-qtiplot' => ['qti', 'qti.gz'], + 'application/x-quattropro' => ['wb1', 'wb2', 'wb3'], + 'application/x-quicktime-media-link' => ['qtl'], + 'application/x-quicktimeplayer' => ['qtl'], + 'application/x-qw' => ['qif'], + 'application/x-rar' => ['rar'], + 'application/x-rar-compressed' => ['rar'], + 'application/x-raw-disk-image' => ['raw-disk-image', 'img'], + 'application/x-raw-disk-image-xz-compressed' => ['raw-disk-image.xz', 'img.xz'], + 'application/x-raw-floppy-disk-image' => ['fd', 'qd'], + 'application/x-redhat-package-manager' => ['rpm'], + 'application/x-reject' => ['rej'], + 'application/x-research-info-systems' => ['ris'], + 'application/x-rnc' => ['rnc'], + 'application/x-rpm' => ['rpm'], + 'application/x-ruby' => ['rb'], + 'application/x-sami' => ['smi', 'sami'], + 'application/x-sap-file' => ['sap'], + 'application/x-saturn-rom' => ['bin', 'iso'], + 'application/x-sdp' => ['sdp'], + 'application/x-sega-cd-rom' => ['bin', 'iso'], + 'application/x-sg1000-rom' => ['sg'], + 'application/x-sh' => ['sh'], + 'application/x-shar' => ['shar'], + 'application/x-shared-library-la' => ['la'], + 'application/x-sharedlib' => ['so'], + 'application/x-shellscript' => ['sh'], + 'application/x-shockwave-flash' => ['swf', 'spl'], + 'application/x-shorten' => ['shn'], + 'application/x-siag' => ['siag'], + 'application/x-silverlight-app' => ['xap'], + 'application/x-sit' => ['sit'], + 'application/x-smaf' => ['mmf', 'smaf'], + 'application/x-sms-rom' => ['sms'], + 'application/x-snes-rom' => ['sfc', 'smc'], + 'application/x-source-rpm' => ['src.rpm', 'spm'], + 'application/x-spss-por' => ['por'], + 'application/x-spss-sav' => ['sav', 'zsav'], + 'application/x-spss-savefile' => ['sav', 'zsav'], + 'application/x-sql' => ['sql'], + 'application/x-sqlite2' => ['sqlite2'], + 'application/x-sqlite3' => ['sqlite3'], + 'application/x-srt' => ['srt'], + '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-t602' => ['602'], + 'application/x-tads' => ['gam'], + 'application/x-tar' => ['tar', 'gtar', 'gem'], + 'application/x-tarz' => ['tar.Z', 'taz'], + 'application/x-tcl' => ['tcl'], + 'application/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], + 'application/x-tex-gf' => ['gf'], + 'application/x-tex-pk' => ['pk'], + 'application/x-tex-tfm' => ['tfm'], + 'application/x-texinfo' => ['texinfo', 'texi'], + 'application/x-tgif' => ['obj'], + 'application/x-theme' => ['theme'], + 'application/x-thomson-cartridge-memo7' => ['m7'], + 'application/x-thomson-cassette' => ['k7'], + 'application/x-thomson-sap-image' => ['sap'], + 'application/x-trash' => ['bak', 'old', 'sik'], + 'application/x-trig' => ['trig'], + 'application/x-troff' => ['tr', 'roff', 't'], + 'application/x-troff-man' => ['man'], + 'application/x-tzo' => ['tar.lzo', 'tzo'], + 'application/x-ufraw' => ['ufraw'], + 'application/x-ustar' => ['ustar'], + 'application/x-virtual-boy-rom' => ['vb'], + 'application/x-vnd.kde.kexi' => ['kexi'], + 'application/x-wais-source' => ['src'], + 'application/x-wbfs' => ['iso'], + 'application/x-wia' => ['iso'], + 'application/x-wii-iso-image' => ['iso'], + 'application/x-wii-rom' => ['iso'], + 'application/x-wii-wad' => ['wad'], + 'application/x-windows-themepack' => ['themepack'], + 'application/x-wmf' => ['wmf'], + 'application/x-wonderswan-color-rom' => ['wsc'], + 'application/x-wonderswan-rom' => ['ws'], + 'application/x-wordperfect' => ['wp', 'wp4', 'wp5', 'wp6', 'wpd', 'wpp'], + 'application/x-wpg' => ['wpg'], + 'application/x-wwf' => ['wwf'], + 'application/x-x509-ca-cert' => ['der', 'crt', 'cert', 'pem'], + 'application/x-xar' => ['xar', 'pkg'], + 'application/x-xbel' => ['xbel'], + 'application/x-xfig' => ['fig'], + 'application/x-xliff' => ['xlf', 'xliff'], + 'application/x-xliff+xml' => ['xlf'], + 'application/x-xpinstall' => ['xpi'], + 'application/x-xspf+xml' => ['xspf'], + 'application/x-xz' => ['xz'], + 'application/x-xz-compressed-tar' => ['tar.xz', 'txz'], + 'application/x-xzpdf' => ['pdf.xz'], + 'application/x-yaml' => ['yaml', 'yml'], + 'application/x-zip' => ['zip'], + 'application/x-zip-compressed' => ['zip'], + 'application/x-zip-compressed-fb2' => ['fb2.zip'], + 'application/x-zmachine' => ['z1', 'z2', 'z3', 'z4', 'z5', 'z6', 'z7', 'z8'], + 'application/x-zoo' => ['zoo'], + 'application/xaml+xml' => ['xaml'], + 'application/xcap-diff+xml' => ['xdf'], + 'application/xenc+xml' => ['xenc'], + 'application/xhtml+xml' => ['xhtml', 'xht'], + 'application/xliff+xml' => ['xlf', 'xliff'], + 'application/xml' => ['xml', 'xsl', 'xbl', 'xsd', 'rng'], + 'application/xml-dtd' => ['dtd'], + 'application/xml-external-parsed-entity' => ['ent'], + 'application/xop+xml' => ['xop'], + 'application/xproc+xml' => ['xpl'], + 'application/xps' => ['oxps', 'xps'], + 'application/xslt+xml' => ['xslt', 'xsl'], + 'application/xspf+xml' => ['xspf'], + 'application/xv+xml' => ['mxml', 'xhvml', 'xvml', 'xvm'], + 'application/yang' => ['yang'], + 'application/yin+xml' => ['yin'], + 'application/zip' => ['zip'], + 'application/zlib' => ['zz'], + 'audio/3gpp' => ['3gp', '3gpp', '3ga'], + 'audio/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/3gpp2' => ['3g2', '3gp2', '3gpp2'], + 'audio/aac' => ['aac', 'adts', 'ass'], + 'audio/ac3' => ['ac3'], + 'audio/adpcm' => ['adp'], + 'audio/amr' => ['amr'], + 'audio/amr-encrypted' => ['amr'], + 'audio/amr-wb' => ['awb'], + 'audio/amr-wb-encrypted' => ['awb'], + 'audio/annodex' => ['axa'], + 'audio/basic' => ['au', 'snd'], + 'audio/flac' => ['flac'], + 'audio/imelody' => ['imy', 'ime'], + 'audio/m3u' => ['m3u', 'm3u8', 'vlc'], + 'audio/m4a' => ['m4a', 'f4a'], + 'audio/midi' => ['mid', 'midi', 'kar', 'rmi'], + 'audio/mobile-xmf' => ['xmf'], + 'audio/mp2' => ['mp2'], + 'audio/mp3' => ['mp3', 'mpga'], + 'audio/mp4' => ['m4a', 'mp4a', 'f4a'], + 'audio/mpeg' => ['mpga', 'mp2', 'mp2a', 'mp3', 'm2a', 'm3a'], + 'audio/mpegurl' => ['m3u', 'm3u8', 'vlc'], + 'audio/ogg' => ['oga', 'ogg', 'spx', 'opus'], + 'audio/prs.sid' => ['sid', 'psid'], + 'audio/s3m' => ['s3m'], + 'audio/scpls' => ['pls'], + 'audio/silk' => ['sil'], + 'audio/tta' => ['tta'], + 'audio/usac' => ['loas', 'xhe'], + 'audio/vnd.audible' => ['aa', 'aax'], + 'audio/vnd.audible.aax' => ['aa', 'aax'], + 'audio/vnd.dece.audio' => ['uva', 'uvva'], + '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.m-realaudio' => ['ra', 'rax'], + '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/vnd.rn-realaudio' => ['ra', 'rax'], + 'audio/vnd.wave' => ['wav'], + 'audio/vorbis' => ['oga', 'ogg'], + 'audio/wav' => ['wav'], + 'audio/webm' => ['weba'], + 'audio/wma' => ['wma'], + 'audio/x-aac' => ['aac', 'adts', 'ass'], + 'audio/x-aifc' => ['aifc', 'aiffc'], + 'audio/x-aiff' => ['aif', 'aiff', 'aifc'], + 'audio/x-aiffc' => ['aifc', 'aiffc'], + 'audio/x-amzxml' => ['amz'], + 'audio/x-annodex' => ['axa'], + 'audio/x-ape' => ['ape'], + 'audio/x-caf' => ['caf'], + 'audio/x-dts' => ['dts'], + 'audio/x-dtshd' => ['dtshd'], + 'audio/x-flac' => ['flac'], + 'audio/x-flac+ogg' => ['oga', 'ogg'], + 'audio/x-gsm' => ['gsm'], + 'audio/x-hx-aac-adts' => ['aac', 'adts', 'ass'], + 'audio/x-imelody' => ['imy', 'ime'], + 'audio/x-iriver-pla' => ['pla'], + 'audio/x-it' => ['it'], + 'audio/x-m3u' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-m4a' => ['m4a', 'f4a'], + 'audio/x-m4b' => ['m4b', 'f4b'], + 'audio/x-m4r' => ['m4r'], + 'audio/x-matroska' => ['mka'], + 'audio/x-midi' => ['mid', 'midi', 'kar'], + 'audio/x-minipsf' => ['minipsf'], + 'audio/x-mo3' => ['mo3'], + 'audio/x-mod' => ['mod', 'ult', 'uni', 'm15', 'mtm', '669', 'med'], + 'audio/x-mp2' => ['mp2'], + 'audio/x-mp3' => ['mp3', 'mpga'], + 'audio/x-mp3-playlist' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-mpeg' => ['mp3', 'mpga'], + 'audio/x-mpegurl' => ['m3u', 'm3u8', 'vlc'], + 'audio/x-mpg' => ['mp3', 'mpga'], + 'audio/x-ms-asx' => ['asx', 'wax', 'wvx', 'wmx'], + 'audio/x-ms-wax' => ['wax'], + 'audio/x-ms-wma' => ['wma'], + 'audio/x-musepack' => ['mpc', 'mpp', 'mp+'], + 'audio/x-ogg' => ['oga', 'ogg', 'opus'], + 'audio/x-oggflac' => ['oga', 'ogg'], + 'audio/x-opus+ogg' => ['opus'], + 'audio/x-pn-audibleaudio' => ['aa', 'aax'], + 'audio/x-pn-realaudio' => ['ram', 'ra', 'rax'], + 'audio/x-pn-realaudio-plugin' => ['rmp'], + 'audio/x-psf' => ['psf'], + 'audio/x-psflib' => ['psflib'], + 'audio/x-rn-3gpp-amr' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-wb' => ['3gp', '3gpp', '3ga'], + 'audio/x-rn-3gpp-amr-wb-encrypted' => ['3gp', '3gpp', '3ga'], + 'audio/x-s3m' => ['s3m'], + 'audio/x-scpls' => ['pls'], + 'audio/x-shorten' => ['shn'], + 'audio/x-speex' => ['spx'], + 'audio/x-speex+ogg' => ['oga', 'ogg'], + 'audio/x-stm' => ['stm'], + 'audio/x-tta' => ['tta'], + 'audio/x-voc' => ['voc'], + 'audio/x-vorbis' => ['oga', 'ogg'], + 'audio/x-vorbis+ogg' => ['oga', 'ogg'], + 'audio/x-wav' => ['wav'], + 'audio/x-wavpack' => ['wv', 'wvp'], + 'audio/x-wavpack-correction' => ['wvc'], + 'audio/x-xi' => ['xi'], + 'audio/x-xm' => ['xm'], + 'audio/x-xmf' => ['xmf'], + 'audio/xm' => ['xm'], + 'audio/xmf' => ['xmf'], + 'chemical/x-cdx' => ['cdx'], + 'chemical/x-cif' => ['cif'], + 'chemical/x-cmdf' => ['cmdf'], + 'chemical/x-cml' => ['cml'], + 'chemical/x-csml' => ['csml'], + 'chemical/x-xyz' => ['xyz'], + 'flv-application/octet-stream' => ['flv'], + 'font/collection' => ['ttc'], + 'font/otf' => ['otf'], + 'font/ttf' => ['ttf'], + 'font/woff' => ['woff', 'woff2'], + 'font/woff2' => ['woff2'], + 'image/bmp' => ['bmp', 'dib'], + 'image/cdr' => ['cdr'], + 'image/cgm' => ['cgm'], + 'image/emf' => ['emf'], + 'image/fax-g3' => ['g3'], + 'image/fits' => ['fits'], + 'image/g3fax' => ['g3'], + 'image/gif' => ['gif'], + 'image/heic' => ['heic', 'heif'], + 'image/heic-sequence' => ['heic', 'heif'], + 'image/heif' => ['heic', 'heif'], + 'image/heif-sequence' => ['heic', 'heif'], + 'image/ico' => ['ico'], + 'image/icon' => ['ico'], + 'image/ief' => ['ief'], + 'image/jp2' => ['jp2', 'jpg2'], + 'image/jpeg' => ['jpeg', 'jpg', 'jpe'], + 'image/jpeg2000' => ['jp2', 'jpg2'], + 'image/jpeg2000-image' => ['jp2', 'jpg2'], + 'image/jpm' => ['jpm', 'jpgm'], + 'image/jpx' => ['jpf', 'jpx'], + 'image/ktx' => ['ktx'], + 'image/openraster' => ['ora'], + 'image/pdf' => ['pdf'], + 'image/photoshop' => ['psd'], + 'image/pjpeg' => ['jpeg', 'jpg', 'jpe'], + 'image/png' => ['png'], + 'image/prs.btif' => ['btif'], + 'image/psd' => ['psd'], + 'image/rle' => ['rle'], + 'image/sgi' => ['sgi'], + 'image/svg+xml' => ['svg', 'svgz'], + 'image/svg+xml-compressed' => ['svgz'], + 'image/tiff' => ['tiff', 'tif'], + 'image/vnd.adobe.photoshop' => ['psd'], + 'image/vnd.dece.graphic' => ['uvi', 'uvvi', 'uvg', 'uvvg'], + 'image/vnd.djvu' => ['djvu', 'djv'], + 'image/vnd.djvu+multipage' => ['djvu', 'djv'], + '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.microsoft.icon' => ['ico'], + 'image/vnd.ms-modi' => ['mdi'], + 'image/vnd.ms-photo' => ['wdp'], + 'image/vnd.net-fpx' => ['npx'], + 'image/vnd.rn-realpix' => ['rp'], + 'image/vnd.wap.wbmp' => ['wbmp'], + 'image/vnd.xiff' => ['xif'], + 'image/vnd.zbrush.pcx' => ['pcx'], + 'image/webp' => ['webp'], + 'image/wmf' => ['wmf'], + 'image/x-3ds' => ['3ds'], + 'image/x-adobe-dng' => ['dng'], + 'image/x-applix-graphics' => ['ag'], + 'image/x-bmp' => ['bmp', 'dib'], + 'image/x-bzeps' => ['eps.bz2', 'epsi.bz2', 'epsf.bz2'], + 'image/x-canon-cr2' => ['cr2'], + 'image/x-canon-crw' => ['crw'], + 'image/x-cdr' => ['cdr'], + 'image/x-cmu-raster' => ['ras'], + 'image/x-cmx' => ['cmx'], + 'image/x-compressed-xcf' => ['xcf.gz', 'xcf.bz2'], + 'image/x-dds' => ['dds'], + 'image/x-djvu' => ['djvu', 'djv'], + 'image/x-emf' => ['emf'], + 'image/x-eps' => ['eps', 'epsi', 'epsf'], + 'image/x-exr' => ['exr'], + 'image/x-fits' => ['fits'], + 'image/x-freehand' => ['fh', 'fhc', 'fh4', 'fh5', 'fh7'], + 'image/x-fuji-raf' => ['raf'], + 'image/x-gimp-gbr' => ['gbr'], + 'image/x-gimp-gih' => ['gih'], + 'image/x-gimp-pat' => ['pat'], + 'image/x-gzeps' => ['eps.gz', 'epsi.gz', 'epsf.gz'], + 'image/x-icb' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-icns' => ['icns'], + 'image/x-ico' => ['ico'], + 'image/x-icon' => ['ico'], + 'image/x-iff' => ['iff', 'ilbm', 'lbm'], + 'image/x-ilbm' => ['iff', 'ilbm', 'lbm'], + 'image/x-jng' => ['jng'], + 'image/x-jp2-codestream' => ['j2c', 'j2k', 'jpc'], + 'image/x-jpeg2000-image' => ['jp2', 'jpg2'], + 'image/x-kodak-dcr' => ['dcr'], + 'image/x-kodak-k25' => ['k25'], + 'image/x-kodak-kdc' => ['kdc'], + 'image/x-lwo' => ['lwo', 'lwob'], + 'image/x-lws' => ['lws'], + 'image/x-macpaint' => ['pntg'], + 'image/x-minolta-mrw' => ['mrw'], + 'image/x-mrsid-image' => ['sid'], + 'image/x-ms-bmp' => ['bmp', 'dib'], + 'image/x-msod' => ['msod'], + 'image/x-nikon-nef' => ['nef'], + 'image/x-olympus-orf' => ['orf'], + 'image/x-panasonic-raw' => ['raw'], + 'image/x-panasonic-raw2' => ['rw2'], + 'image/x-panasonic-rw' => ['raw'], + 'image/x-panasonic-rw2' => ['rw2'], + 'image/x-pcx' => ['pcx'], + 'image/x-pentax-pef' => ['pef'], + 'image/x-photo-cd' => ['pcd'], + 'image/x-photoshop' => ['psd'], + 'image/x-pict' => ['pic', 'pct', 'pict', 'pict1', 'pict2'], + 'image/x-portable-anymap' => ['pnm'], + 'image/x-portable-bitmap' => ['pbm'], + 'image/x-portable-graymap' => ['pgm'], + 'image/x-portable-pixmap' => ['ppm'], + 'image/x-psd' => ['psd'], + 'image/x-quicktime' => ['qtif', 'qif'], + 'image/x-rgb' => ['rgb'], + 'image/x-sgi' => ['sgi'], + 'image/x-sigma-x3f' => ['x3f'], + 'image/x-skencil' => ['sk', 'sk1'], + 'image/x-sony-arw' => ['arw'], + 'image/x-sony-sr2' => ['sr2'], + 'image/x-sony-srf' => ['srf'], + 'image/x-sun-raster' => ['sun'], + 'image/x-tga' => ['tga', 'icb', 'tpic', 'vda', 'vst'], + 'image/x-win-bitmap' => ['cur'], + 'image/x-win-metafile' => ['wmf'], + 'image/x-wmf' => ['wmf'], + 'image/x-xbitmap' => ['xbm'], + 'image/x-xcf' => ['xcf'], + 'image/x-xfig' => ['fig'], + 'image/x-xpixmap' => ['xpm'], + 'image/x-xpm' => ['xpm'], + 'image/x-xwindowdump' => ['xwd'], + 'image/x.djvu' => ['djvu', 'djv'], + 'message/rfc822' => ['eml', 'mime'], + 'model/iges' => ['igs', 'iges'], + 'model/mesh' => ['msh', 'mesh', 'silo'], + 'model/stl' => ['stl'], + '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', 'vrml', 'vrm'], + 'model/x.stl-ascii' => ['stl'], + 'model/x.stl-binary' => ['stl'], + 'model/x3d+binary' => ['x3db', 'x3dbz'], + 'model/x3d+vrml' => ['x3dv', 'x3dvz'], + 'model/x3d+xml' => ['x3d', 'x3dz'], + 'text/cache-manifest' => ['appcache', 'manifest'], + 'text/calendar' => ['ics', 'ifb', 'vcs'], + 'text/css' => ['css'], + 'text/csv' => ['csv'], + 'text/csv-schema' => ['csvs'], + 'text/directory' => ['vcard', 'vcf', 'vct', 'gcrd'], + 'text/ecmascript' => ['es'], + 'text/gedcom' => ['ged', 'gedcom'], + 'text/google-video-pointer' => ['gvp'], + 'text/html' => ['html', 'htm'], + 'text/ico' => ['ico'], + 'text/javascript' => ['js', 'jsm', 'mjs'], + 'text/markdown' => ['md', 'mkd', 'markdown'], + 'text/mathml' => ['mml'], + 'text/n3' => ['n3'], + 'text/plain' => ['txt', 'text', 'conf', 'def', 'list', 'log', 'in', 'asc'], + 'text/prs.lines.tag' => ['dsc'], + 'text/rdf' => ['rdf', 'rdfs', 'owl'], + 'text/richtext' => ['rtx'], + 'text/rss' => ['rss'], + 'text/rtf' => ['rtf'], + 'text/rust' => ['rs'], + 'text/sgml' => ['sgml', 'sgm'], + 'text/spreadsheet' => ['sylk', 'slk'], + 'text/tab-separated-values' => ['tsv'], + 'text/troff' => ['t', 'tr', 'roff', 'man', 'me', 'ms'], + 'text/turtle' => ['ttl'], + 'text/uri-list' => ['uri', 'uris', 'urls'], + 'text/vcard' => ['vcard', 'vcf', 'vct', 'gcrd'], + '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', 'dot'], + 'text/vnd.in3d.3dml' => ['3dml'], + 'text/vnd.in3d.spot' => ['spot'], + 'text/vnd.qt.linguist' => ['ts'], + 'text/vnd.rn-realtext' => ['rt'], + 'text/vnd.sun.j2me.app-descriptor' => ['jad'], + 'text/vnd.trolltech.linguist' => ['ts'], + 'text/vnd.wap.wml' => ['wml'], + 'text/vnd.wap.wmlscript' => ['wmls'], + 'text/vtt' => ['vtt'], + 'text/x-adasrc' => ['adb', 'ads'], + 'text/x-asm' => ['s', 'asm'], + 'text/x-bibtex' => ['bib'], + 'text/x-c' => ['c', 'cc', 'cxx', 'cpp', 'h', 'hh', 'dic'], + 'text/x-c++hdr' => ['hh', 'hp', 'hpp', 'h++', 'hxx'], + 'text/x-c++src' => ['cpp', 'cxx', 'cc', 'C', 'c++'], + 'text/x-chdr' => ['h'], + 'text/x-cmake' => ['cmake'], + 'text/x-cobol' => ['cbl', 'cob'], + 'text/x-comma-separated-values' => ['csv'], + 'text/x-csharp' => ['cs'], + 'text/x-csrc' => ['c'], + 'text/x-csv' => ['csv'], + 'text/x-dbus-service' => ['service'], + 'text/x-dcl' => ['dcl'], + 'text/x-diff' => ['diff', 'patch'], + 'text/x-dsl' => ['dsl'], + 'text/x-dsrc' => ['d', 'di'], + 'text/x-dtd' => ['dtd'], + 'text/x-eiffel' => ['e', 'eif'], + 'text/x-emacs-lisp' => ['el'], + 'text/x-erlang' => ['erl'], + 'text/x-fortran' => ['f', 'for', 'f77', 'f90', 'f95'], + 'text/x-genie' => ['gs'], + 'text/x-gettext-translation' => ['po'], + 'text/x-gettext-translation-template' => ['pot'], + 'text/x-gherkin' => ['feature'], + 'text/x-go' => ['go'], + 'text/x-google-video-pointer' => ['gvp'], + 'text/x-haskell' => ['hs'], + 'text/x-idl' => ['idl'], + 'text/x-imelody' => ['imy', 'ime'], + 'text/x-iptables' => ['iptables'], + 'text/x-java' => ['java'], + 'text/x-java-source' => ['java'], + 'text/x-ldif' => ['ldif'], + 'text/x-lilypond' => ['ly'], + 'text/x-literate-haskell' => ['lhs'], + 'text/x-log' => ['log'], + 'text/x-lua' => ['lua'], + 'text/x-lyx' => ['lyx'], + 'text/x-makefile' => ['mk', 'mak'], + 'text/x-markdown' => ['md', 'mkd', 'markdown'], + 'text/x-matlab' => ['m'], + 'text/x-microdvd' => ['sub'], + 'text/x-moc' => ['moc'], + 'text/x-modelica' => ['mo'], + 'text/x-mof' => ['mof'], + 'text/x-mpsub' => ['sub'], + 'text/x-mrml' => ['mrml', 'mrl'], + 'text/x-ms-regedit' => ['reg'], + 'text/x-mup' => ['mup', 'not'], + 'text/x-nfo' => ['nfo'], + 'text/x-objcsrc' => ['m'], + 'text/x-ocaml' => ['ml', 'mli'], + 'text/x-ocl' => ['ocl'], + 'text/x-octave' => ['m'], + 'text/x-ooc' => ['ooc'], + 'text/x-opencl-src' => ['cl'], + 'text/x-opml' => ['opml'], + 'text/x-opml+xml' => ['opml'], + 'text/x-pascal' => ['p', 'pas'], + 'text/x-patch' => ['diff', 'patch'], + 'text/x-perl' => ['pl', 'PL', 'pm', 'al', 'perl', 'pod', 't'], + 'text/x-po' => ['po'], + 'text/x-pot' => ['pot'], + 'text/x-python' => ['py', 'pyx', 'wsgi'], + 'text/x-python3' => ['py', 'py3', 'py3x'], + 'text/x-qml' => ['qml', 'qmltypes', 'qmlproject'], + 'text/x-reject' => ['rej'], + 'text/x-rpm-spec' => ['spec'], + 'text/x-sass' => ['sass'], + 'text/x-scala' => ['scala'], + 'text/x-scheme' => ['scm', 'ss'], + 'text/x-scss' => ['scss'], + 'text/x-setext' => ['etx'], + 'text/x-sfv' => ['sfv'], + 'text/x-sh' => ['sh'], + 'text/x-sql' => ['sql'], + 'text/x-ssa' => ['ssa', 'ass'], + 'text/x-subviewer' => ['sub'], + 'text/x-svhdr' => ['svh'], + 'text/x-svsrc' => ['sv'], + 'text/x-systemd-unit' => ['automount', 'device', 'mount', 'path', 'scope', 'service', 'slice', 'socket', 'swap', 'target', 'timer'], + 'text/x-tcl' => ['tcl', 'tk'], + 'text/x-tex' => ['tex', 'ltx', 'sty', 'cls', 'dtx', 'ins', 'latex'], + 'text/x-texinfo' => ['texi', 'texinfo'], + 'text/x-troff' => ['tr', 'roff', 't'], + 'text/x-troff-me' => ['me'], + 'text/x-troff-mm' => ['mm'], + 'text/x-troff-ms' => ['ms'], + 'text/x-twig' => ['twig'], + 'text/x-txt2tags' => ['t2t'], + 'text/x-uil' => ['uil'], + 'text/x-uuencode' => ['uu', 'uue'], + 'text/x-vala' => ['vala', 'vapi'], + 'text/x-vcalendar' => ['vcs', 'ics'], + 'text/x-vcard' => ['vcf', 'vcard', 'vct', 'gcrd'], + 'text/x-verilog' => ['v'], + 'text/x-vhdl' => ['vhd', 'vhdl'], + 'text/x-xmi' => ['xmi'], + 'text/x-xslfo' => ['fo', 'xslfo'], + 'text/x-yaml' => ['yaml', 'yml'], + 'text/x.gcode' => ['gcode'], + 'text/xml' => ['xml', 'xbl', 'xsd', 'rng'], + 'text/xml-external-parsed-entity' => ['ent'], + 'text/yaml' => ['yaml', 'yml'], + 'video/3gp' => ['3gp', '3gpp', '3ga'], + 'video/3gpp' => ['3gp', '3gpp', '3ga'], + 'video/3gpp-encrypted' => ['3gp', '3gpp', '3ga'], + 'video/3gpp2' => ['3g2', '3gp2', '3gpp2'], + 'video/annodex' => ['axv'], + 'video/avi' => ['avi', 'avf', 'divx'], + 'video/divx' => ['avi', 'avf', 'divx'], + 'video/dv' => ['dv'], + 'video/fli' => ['fli', 'flc'], + 'video/flv' => ['flv'], + 'video/h261' => ['h261'], + 'video/h263' => ['h263'], + 'video/h264' => ['h264'], + 'video/jpeg' => ['jpgv'], + 'video/jpm' => ['jpm', 'jpgm'], + 'video/mj2' => ['mj2', 'mjp2'], + 'video/mp2t' => ['m2t', 'm2ts', 'ts', 'mts', 'cpi', 'clpi', 'mpl', 'mpls', 'bdm', 'bdmv'], + 'video/mp4' => ['mp4', 'mp4v', 'mpg4', 'm4v', 'f4v', 'lrv'], + 'video/mp4v-es' => ['mp4', 'm4v', 'f4v', 'lrv'], + 'video/mpeg' => ['mpeg', 'mpg', 'mpe', 'm1v', 'm2v', 'mp2', 'vob'], + 'video/mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/msvideo' => ['avi', 'avf', 'divx'], + 'video/ogg' => ['ogv', 'ogg'], + 'video/quicktime' => ['qt', 'mov', 'moov', 'qtvr'], + 'video/vivo' => ['viv', 'vivo'], + 'video/vnd.dece.hd' => ['uvh', 'uvvh'], + 'video/vnd.dece.mobile' => ['uvm', 'uvvm'], + 'video/vnd.dece.pd' => ['uvp', 'uvvp'], + 'video/vnd.dece.sd' => ['uvs', 'uvvs'], + 'video/vnd.dece.video' => ['uvv', 'uvvv'], + 'video/vnd.divx' => ['avi', 'avf', 'divx'], + 'video/vnd.dvb.file' => ['dvb'], + 'video/vnd.fvt' => ['fvt'], + 'video/vnd.mpegurl' => ['mxu', 'm4u', 'm1u'], + 'video/vnd.ms-playready.media.pyv' => ['pyv'], + 'video/vnd.rn-realvideo' => ['rv', 'rvx'], + 'video/vnd.uvvu.mp4' => ['uvu', 'uvvu'], + 'video/vnd.vivo' => ['viv', 'vivo'], + 'video/webm' => ['webm'], + 'video/x-anim' => ['anim[1-9j]'], + 'video/x-annodex' => ['axv'], + 'video/x-avi' => ['avi', 'avf', 'divx'], + 'video/x-f4v' => ['f4v'], + 'video/x-fli' => ['fli', 'flc'], + 'video/x-flic' => ['fli', 'flc'], + 'video/x-flv' => ['flv'], + 'video/x-javafx' => ['fxm'], + 'video/x-m4v' => ['m4v', 'mp4', 'f4v', 'lrv'], + 'video/x-matroska' => ['mkv', 'mk3d', 'mks'], + 'video/x-matroska-3d' => ['mk3d'], + 'video/x-mjpeg' => ['mjpeg', 'mjpg'], + 'video/x-mng' => ['mng'], + 'video/x-mpeg' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpeg-system' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpeg2' => ['mpeg', 'mpg', 'mp2', 'mpe', 'vob'], + 'video/x-mpegurl' => ['m1u', 'm4u', 'mxu'], + 'video/x-ms-asf' => ['asf', 'asx'], + 'video/x-ms-asf-plugin' => ['asf'], + 'video/x-ms-vob' => ['vob'], + 'video/x-ms-wax' => ['asx', 'wax', 'wvx', 'wmx'], + 'video/x-ms-wm' => ['wm', 'asf'], + 'video/x-ms-wmv' => ['wmv'], + 'video/x-ms-wmx' => ['wmx', 'asx', 'wax', 'wvx'], + 'video/x-ms-wvx' => ['wvx', 'asx', 'wax', 'wmx'], + 'video/x-msvideo' => ['avi', 'avf', 'divx'], + 'video/x-nsv' => ['nsv'], + 'video/x-ogg' => ['ogv', 'ogg'], + 'video/x-ogm' => ['ogm'], + 'video/x-ogm+ogg' => ['ogm'], + 'video/x-real-video' => ['rv', 'rvx'], + 'video/x-sgi-movie' => ['movie'], + 'video/x-smv' => ['smv'], + 'video/x-theora' => ['ogg'], + 'video/x-theora+ogg' => ['ogg'], + 'x-conference/x-cooltalk' => ['ice'], + 'x-epoc/x-sisx-app' => ['sisx'], + 'zz-application/zz-winassoc-123' => ['123', 'wk1', 'wk3', 'wk4', 'wks'], + 'zz-application/zz-winassoc-cab' => ['cab'], + 'zz-application/zz-winassoc-cdr' => ['cdr'], + 'zz-application/zz-winassoc-doc' => ['doc'], + 'zz-application/zz-winassoc-hlp' => ['hlp'], + 'zz-application/zz-winassoc-mdb' => ['mdb'], + 'zz-application/zz-winassoc-uu' => ['uue'], + 'zz-application/zz-winassoc-xls' => ['xls', 'xlc', 'xll', 'xlm', 'xlw', 'xla', 'xlt', 'xld'], + ]; + + private static $reverseMap = [ + '32x' => ['application/x-genesis-32x-rom'], + '3dml' => ['text/vnd.in3d.3dml'], + '3ds' => ['image/x-3ds'], + '3g2' => ['audio/3gpp2', 'video/3gpp2'], + '3ga' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gp2' => ['audio/3gpp2', 'video/3gpp2'], + '3gpp' => ['audio/3gpp', 'audio/3gpp-encrypted', 'audio/x-rn-3gpp-amr', 'audio/x-rn-3gpp-amr-encrypted', 'audio/x-rn-3gpp-amr-wb', 'audio/x-rn-3gpp-amr-wb-encrypted', 'video/3gp', 'video/3gpp', 'video/3gpp-encrypted'], + '3gpp2' => ['audio/3gpp2', 'video/3gpp2'], + '7z' => ['application/x-7z-compressed'], + 'BLEND' => ['application/x-blender'], + 'C' => ['text/x-c++src'], + 'PAR2' => ['application/x-par2'], + 'PL' => ['application/x-perl', 'text/x-perl'], + 'Z' => ['application/x-compress'], + 'a' => ['application/x-archive'], + 'a26' => ['application/x-atari-2600-rom'], + 'a78' => ['application/x-atari-7800-rom'], + 'aa' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'], + 'aab' => ['application/x-authorware-bin'], + 'aac' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], + 'aam' => ['application/x-authorware-map'], + 'aas' => ['application/x-authorware-seg'], + 'aax' => ['audio/vnd.audible', 'audio/vnd.audible.aax', 'audio/x-pn-audibleaudio'], + 'abw' => ['application/x-abiword'], + 'abw.CRASHED' => ['application/x-abiword'], + 'abw.gz' => ['application/x-abiword'], + 'ac' => ['application/pkix-attr-cert'], + 'ac3' => ['audio/ac3'], + 'acc' => ['application/vnd.americandynamics.acc'], + 'ace' => ['application/x-ace', 'application/x-ace-compressed'], + 'acu' => ['application/vnd.acucobol'], + 'acutc' => ['application/vnd.acucorp'], + 'adb' => ['text/x-adasrc'], + 'adf' => ['application/x-amiga-disk-format'], + 'adp' => ['audio/adpcm'], + 'ads' => ['text/x-adasrc'], + 'adts' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts'], + 'aep' => ['application/vnd.audiograph'], + 'afm' => ['application/x-font-afm', 'application/x-font-type1'], + 'afp' => ['application/vnd.ibm.modcap'], + 'ag' => ['image/x-applix-graphics'], + 'agb' => ['application/x-gba-rom'], + 'ahead' => ['application/vnd.ahead.space'], + 'ai' => ['application/illustrator', 'application/postscript', 'application/vnd.adobe.illustrator'], + 'aif' => ['audio/x-aiff'], + 'aifc' => ['audio/x-aifc', 'audio/x-aiff', 'audio/x-aiffc'], + 'aiff' => ['audio/x-aiff'], + 'aiffc' => ['audio/x-aifc', 'audio/x-aiffc'], + 'air' => ['application/vnd.adobe.air-application-installer-package+zip'], + 'ait' => ['application/vnd.dvb.ait'], + 'al' => ['application/x-perl', 'text/x-perl'], + 'alz' => ['application/x-alz'], + 'ami' => ['application/vnd.amiga.ami'], + 'amr' => ['audio/amr', 'audio/amr-encrypted'], + 'amz' => ['audio/x-amzxml'], + 'ani' => ['application/x-navi-animation'], + 'anim[1-9j]' => ['video/x-anim'], + 'anx' => ['application/annodex', 'application/x-annodex'], + 'ape' => ['audio/x-ape'], + 'apk' => ['application/vnd.android.package-archive'], + 'appcache' => ['text/cache-manifest'], + 'appimage' => ['application/vnd.appimage', 'application/x-iso9660-appimage'], + 'application' => ['application/x-ms-application'], + 'apr' => ['application/vnd.lotus-approach'], + 'aps' => ['application/postscript'], + 'ar' => ['application/x-archive'], + 'arc' => ['application/x-freearc'], + 'arj' => ['application/x-arj'], + 'arw' => ['image/x-sony-arw'], + 'as' => ['application/x-applix-spreadsheet'], + 'asc' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature', 'text/plain'], + 'asf' => ['application/vnd.ms-asf', 'video/x-ms-asf', 'video/x-ms-asf-plugin', 'video/x-ms-wm'], + 'asm' => ['text/x-asm'], + 'aso' => ['application/vnd.accpac.simply.aso'], + 'asp' => ['application/x-asp'], + 'ass' => ['audio/aac', 'audio/x-aac', 'audio/x-hx-aac-adts', 'text/x-ssa'], + 'asx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-asf', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'atc' => ['application/vnd.acucorp'], + 'atom' => ['application/atom+xml'], + 'atomcat' => ['application/atomcat+xml'], + 'atomsvc' => ['application/atomsvc+xml'], + 'atx' => ['application/vnd.antix.game-component'], + 'au' => ['audio/basic'], + 'automount' => ['text/x-systemd-unit'], + 'avf' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'avi' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'aw' => ['application/applixware', 'application/x-applix-word'], + 'awb' => ['audio/amr-wb', 'audio/amr-wb-encrypted'], + 'awk' => ['application/x-awk'], + 'axa' => ['audio/annodex', 'audio/x-annodex'], + 'axv' => ['video/annodex', 'video/x-annodex'], + 'azf' => ['application/vnd.airzip.filesecure.azf'], + 'azs' => ['application/vnd.airzip.filesecure.azs'], + 'azw' => ['application/vnd.amazon.ebook'], + 'bak' => ['application/x-trash'], + 'bat' => ['application/x-msdownload'], + 'bcpio' => ['application/x-bcpio'], + 'bdf' => ['application/x-font-bdf'], + 'bdm' => ['application/vnd.syncml.dm+wbxml', 'video/mp2t'], + 'bdmv' => ['video/mp2t'], + 'bed' => ['application/vnd.realvnc.bed'], + 'bh2' => ['application/vnd.fujitsu.oasysprs'], + 'bib' => ['text/x-bibtex'], + 'bin' => ['application/octet-stream', 'application/x-saturn-rom', 'application/x-sega-cd-rom'], + 'blb' => ['application/x-blorb'], + 'blend' => ['application/x-blender'], + 'blender' => ['application/x-blender'], + 'blorb' => ['application/x-blorb'], + 'bmi' => ['application/vnd.bmi'], + 'bmp' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], + 'book' => ['application/vnd.framemaker'], + 'box' => ['application/vnd.previewsystems.box'], + 'boz' => ['application/x-bzip2'], + 'bpk' => ['application/octet-stream'], + 'bsdiff' => ['application/x-bsdiff'], + 'btif' => ['image/prs.btif'], + 'bz' => ['application/x-bzip', 'application/x-bzip2'], + 'bz2' => ['application/x-bz2', 'application/x-bzip', 'application/x-bzip2'], + 'c' => ['text/x-c', 'text/x-csrc'], + 'c++' => ['text/x-c++src'], + 'c11amc' => ['application/vnd.cluetrust.cartomobile-config'], + 'c11amz' => ['application/vnd.cluetrust.cartomobile-config-pkg'], + 'c4d' => ['application/vnd.clonk.c4group'], + 'c4f' => ['application/vnd.clonk.c4group'], + 'c4g' => ['application/vnd.clonk.c4group'], + 'c4p' => ['application/vnd.clonk.c4group'], + 'c4u' => ['application/vnd.clonk.c4group'], + 'cab' => ['application/vnd.ms-cab-compressed', 'zz-application/zz-winassoc-cab'], + 'caf' => ['audio/x-caf'], + 'cap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'car' => ['application/vnd.curl.car'], + 'cat' => ['application/vnd.ms-pki.seccat'], + 'cb7' => ['application/x-cb7', 'application/x-cbr'], + 'cba' => ['application/x-cbr'], + 'cbl' => ['text/x-cobol'], + 'cbr' => ['application/vnd.comicbook-rar', 'application/x-cbr'], + 'cbt' => ['application/x-cbr', 'application/x-cbt'], + 'cbz' => ['application/vnd.comicbook+zip', 'application/x-cbr', 'application/x-cbz'], + 'cc' => ['text/x-c', 'text/x-c++src'], + 'ccmx' => ['application/x-ccmx'], + 'cct' => ['application/x-director'], + 'ccxml' => ['application/ccxml+xml'], + 'cdbcmsg' => ['application/vnd.contact.cmsg'], + 'cdf' => ['application/x-netcdf'], + 'cdkey' => ['application/vnd.mediastation.cdkey'], + 'cdmia' => ['application/cdmi-capability'], + 'cdmic' => ['application/cdmi-container'], + 'cdmid' => ['application/cdmi-domain'], + 'cdmio' => ['application/cdmi-object'], + 'cdmiq' => ['application/cdmi-queue'], + 'cdr' => ['application/cdr', 'application/coreldraw', 'application/vnd.corel-draw', 'application/x-cdr', 'application/x-coreldraw', 'image/cdr', 'image/x-cdr', 'zz-application/zz-winassoc-cdr'], + 'cdx' => ['chemical/x-cdx'], + 'cdxml' => ['application/vnd.chemdraw+xml'], + 'cdy' => ['application/vnd.cinderella'], + 'cer' => ['application/pkix-cert'], + 'cert' => ['application/x-x509-ca-cert'], + 'cfs' => ['application/x-cfs-compressed'], + 'cgb' => ['application/x-gameboy-color-rom'], + 'cgm' => ['image/cgm'], + 'chat' => ['application/x-chat'], + 'chm' => ['application/vnd.ms-htmlhelp', 'application/x-chm'], + 'chrt' => ['application/vnd.kde.kchart', 'application/x-kchart'], + 'cif' => ['chemical/x-cif'], + 'cii' => ['application/vnd.anser-web-certificate-issue-initiation'], + 'cil' => ['application/vnd.ms-artgalry'], + 'cl' => ['text/x-opencl-src'], + 'cla' => ['application/vnd.claymore'], + 'class' => ['application/java', 'application/java-byte-code', 'application/java-vm', 'application/x-java', 'application/x-java-class', 'application/x-java-vm'], + 'clkk' => ['application/vnd.crick.clicker.keyboard'], + 'clkp' => ['application/vnd.crick.clicker.palette'], + 'clkt' => ['application/vnd.crick.clicker.template'], + 'clkw' => ['application/vnd.crick.clicker.wordbank'], + 'clkx' => ['application/vnd.crick.clicker'], + 'clp' => ['application/x-msclip'], + 'clpi' => ['video/mp2t'], + 'cls' => ['application/x-tex', 'text/x-tex'], + 'cmake' => ['text/x-cmake'], + 'cmc' => ['application/vnd.cosmocaller'], + 'cmdf' => ['chemical/x-cmdf'], + 'cml' => ['chemical/x-cml'], + 'cmp' => ['application/vnd.yellowriver-custom-menu'], + 'cmx' => ['image/x-cmx'], + 'cob' => ['text/x-cobol'], + 'cod' => ['application/vnd.rim.cod'], + 'coffee' => ['application/vnd.coffeescript'], + 'com' => ['application/x-msdownload'], + 'conf' => ['text/plain'], + 'cpi' => ['video/mp2t'], + 'cpio' => ['application/x-cpio'], + 'cpio.gz' => ['application/x-cpio-compressed'], + 'cpp' => ['text/x-c', 'text/x-c++src'], + 'cpt' => ['application/mac-compactpro'], + 'cr2' => ['image/x-canon-cr2'], + 'crd' => ['application/x-mscardfile'], + 'crdownload' => ['application/x-partial-download'], + 'crl' => ['application/pkix-crl'], + 'crt' => ['application/x-x509-ca-cert'], + 'crw' => ['image/x-canon-crw'], + 'cryptonote' => ['application/vnd.rig.cryptonote'], + 'cs' => ['text/x-csharp'], + 'csh' => ['application/x-csh'], + 'csml' => ['chemical/x-csml'], + 'csp' => ['application/vnd.commonspace'], + 'css' => ['text/css'], + 'cst' => ['application/x-director'], + 'csv' => ['text/csv', 'text/x-comma-separated-values', 'text/x-csv'], + 'csvs' => ['text/csv-schema'], + 'cu' => ['application/cu-seeme'], + 'cue' => ['application/x-cue'], + 'cur' => ['image/x-win-bitmap'], + 'curl' => ['text/vnd.curl'], + 'cww' => ['application/prs.cww'], + 'cxt' => ['application/x-director'], + 'cxx' => ['text/x-c', 'text/x-c++src'], + 'd' => ['text/x-dsrc'], + 'dae' => ['model/vnd.collada+xml'], + 'daf' => ['application/vnd.mobius.daf'], + 'dar' => ['application/x-dar'], + 'dart' => ['application/vnd.dart'], + 'dataless' => ['application/vnd.fdsn.seed'], + 'davmount' => ['application/davmount+xml'], + 'dbf' => ['application/dbase', 'application/dbf', 'application/x-dbase', 'application/x-dbf'], + 'dbk' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], + 'dc' => ['application/x-dc-rom'], + 'dcl' => ['text/x-dcl'], + 'dcm' => ['application/dicom'], + 'dcr' => ['application/x-director', 'image/x-kodak-dcr'], + 'dcurl' => ['text/vnd.curl.dcurl'], + 'dd2' => ['application/vnd.oma.dd2+xml'], + 'ddd' => ['application/vnd.fujixerox.ddd'], + 'dds' => ['image/x-dds'], + 'deb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], + 'def' => ['text/plain'], + 'deploy' => ['application/octet-stream'], + 'der' => ['application/x-x509-ca-cert'], + 'desktop' => ['application/x-desktop', 'application/x-gnome-app-info'], + 'device' => ['text/x-systemd-unit'], + 'dfac' => ['application/vnd.dreamfactory'], + 'dgc' => ['application/x-dgc-compressed'], + 'di' => ['text/x-dsrc'], + 'dia' => ['application/x-dia-diagram'], + 'dib' => ['image/bmp', 'image/x-bmp', 'image/x-ms-bmp'], + 'dic' => ['text/x-c'], + 'diff' => ['text/x-diff', 'text/x-patch'], + 'dir' => ['application/x-director'], + 'dis' => ['application/vnd.mobius.dis'], + 'dist' => ['application/octet-stream'], + 'distz' => ['application/octet-stream'], + 'divx' => ['video/avi', 'video/divx', 'video/msvideo', 'video/vnd.divx', 'video/x-avi', 'video/x-msvideo'], + 'djv' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], + 'djvu' => ['image/vnd.djvu', 'image/vnd.djvu+multipage', 'image/x-djvu', 'image/x.djvu'], + 'dll' => ['application/x-msdownload'], + 'dmg' => ['application/x-apple-diskimage'], + 'dmp' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'dms' => ['application/octet-stream'], + 'dna' => ['application/vnd.dna'], + 'dng' => ['image/x-adobe-dng'], + 'doc' => ['application/msword', 'application/vnd.ms-word', 'application/x-msword', 'zz-application/zz-winassoc-doc'], + 'docbook' => ['application/docbook+xml', 'application/vnd.oasis.docbook+xml', 'application/x-docbook+xml'], + 'docm' => ['application/vnd.ms-word.document.macroenabled.12'], + 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + 'dot' => ['application/msword', 'application/msword-template', 'text/vnd.graphviz'], + 'dotm' => ['application/vnd.ms-word.template.macroenabled.12'], + 'dotx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.template'], + 'dp' => ['application/vnd.osgi.dp'], + 'dpg' => ['application/vnd.dpgraph'], + 'dra' => ['audio/vnd.dra'], + 'dsc' => ['text/prs.lines.tag'], + 'dsl' => ['text/x-dsl'], + 'dssc' => ['application/dssc+der'], + 'dtb' => ['application/x-dtbook+xml'], + 'dtd' => ['application/xml-dtd', 'text/x-dtd'], + 'dts' => ['audio/vnd.dts', 'audio/x-dts'], + 'dtshd' => ['audio/vnd.dts.hd', 'audio/x-dtshd'], + 'dtx' => ['application/x-tex', 'text/x-tex'], + 'dump' => ['application/octet-stream'], + 'dv' => ['video/dv'], + 'dvb' => ['video/vnd.dvb.file'], + 'dvi' => ['application/x-dvi'], + 'dvi.bz2' => ['application/x-bzdvi'], + 'dvi.gz' => ['application/x-gzdvi'], + 'dwf' => ['model/vnd.dwf'], + 'dwg' => ['image/vnd.dwg'], + 'dxf' => ['image/vnd.dxf'], + 'dxp' => ['application/vnd.spotfire.dxp'], + 'dxr' => ['application/x-director'], + 'e' => ['text/x-eiffel'], + 'ecelp4800' => ['audio/vnd.nuera.ecelp4800'], + 'ecelp7470' => ['audio/vnd.nuera.ecelp7470'], + 'ecelp9600' => ['audio/vnd.nuera.ecelp9600'], + 'ecma' => ['application/ecmascript'], + 'edm' => ['application/vnd.novadigm.edm'], + 'edx' => ['application/vnd.novadigm.edx'], + 'efif' => ['application/vnd.picsel'], + 'egon' => ['application/x-egon'], + 'ei6' => ['application/vnd.pg.osasli'], + 'eif' => ['text/x-eiffel'], + 'el' => ['text/x-emacs-lisp'], + 'elc' => ['application/octet-stream'], + 'emf' => ['application/emf', 'application/x-emf', 'application/x-msmetafile', 'image/emf', 'image/x-emf'], + 'eml' => ['message/rfc822'], + 'emma' => ['application/emma+xml'], + 'emp' => ['application/vnd.emusic-emusic_package'], + 'emz' => ['application/x-msmetafile'], + 'ent' => ['application/xml-external-parsed-entity', 'text/xml-external-parsed-entity'], + 'eol' => ['audio/vnd.digital-winds'], + 'eot' => ['application/vnd.ms-fontobject'], + 'eps' => ['application/postscript', 'image/x-eps'], + 'eps.bz2' => ['image/x-bzeps'], + 'eps.gz' => ['image/x-gzeps'], + 'epsf' => ['image/x-eps'], + 'epsf.bz2' => ['image/x-bzeps'], + 'epsf.gz' => ['image/x-gzeps'], + 'epsi' => ['image/x-eps'], + 'epsi.bz2' => ['image/x-bzeps'], + 'epsi.gz' => ['image/x-gzeps'], + 'epub' => ['application/epub+zip'], + 'erl' => ['text/x-erlang'], + 'es' => ['application/ecmascript', 'text/ecmascript'], + 'es3' => ['application/vnd.eszigno3+xml'], + 'esa' => ['application/vnd.osgi.subsystem'], + 'esf' => ['application/vnd.epson.esf'], + 'et3' => ['application/vnd.eszigno3+xml'], + 'etheme' => ['application/x-e-theme'], + 'etx' => ['text/x-setext'], + 'eva' => ['application/x-eva'], + 'evy' => ['application/x-envoy'], + 'exe' => ['application/x-ms-dos-executable', 'application/x-msdownload'], + 'exi' => ['application/exi'], + 'exr' => ['image/x-exr'], + 'ext' => ['application/vnd.novadigm.ext'], + 'ez' => ['application/andrew-inset'], + 'ez2' => ['application/vnd.ezpix-album'], + 'ez3' => ['application/vnd.ezpix-package'], + 'f' => ['text/x-fortran'], + 'f4a' => ['audio/m4a', 'audio/mp4', 'audio/x-m4a'], + 'f4b' => ['audio/x-m4b'], + 'f4v' => ['video/mp4', 'video/mp4v-es', 'video/x-f4v', 'video/x-m4v'], + 'f77' => ['text/x-fortran'], + 'f90' => ['text/x-fortran'], + 'f95' => ['text/x-fortran'], + 'fb2' => ['application/x-fictionbook', 'application/x-fictionbook+xml'], + 'fb2.zip' => ['application/x-zip-compressed-fb2'], + 'fbs' => ['image/vnd.fastbidsheet'], + 'fcdt' => ['application/vnd.adobe.formscentral.fcdt'], + 'fcs' => ['application/vnd.isac.fcs'], + 'fd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], + 'fdf' => ['application/vnd.fdf'], + 'fds' => ['application/x-fds-disk'], + 'fe_launch' => ['application/vnd.denovo.fcselayout-link'], + 'feature' => ['text/x-gherkin'], + 'fg5' => ['application/vnd.fujitsu.oasysgp'], + 'fgd' => ['application/x-director'], + 'fh' => ['image/x-freehand'], + 'fh4' => ['image/x-freehand'], + 'fh5' => ['image/x-freehand'], + 'fh7' => ['image/x-freehand'], + 'fhc' => ['image/x-freehand'], + 'fig' => ['application/x-xfig', 'image/x-xfig'], + 'fits' => ['image/fits', 'image/x-fits'], + 'fl' => ['application/x-fluid'], + 'flac' => ['audio/flac', 'audio/x-flac'], + 'flatpak' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], + 'flatpakref' => ['application/vnd.flatpak.ref'], + 'flatpakrepo' => ['application/vnd.flatpak.repo'], + 'flc' => ['video/fli', 'video/x-fli', 'video/x-flic'], + 'fli' => ['video/fli', 'video/x-fli', 'video/x-flic'], + 'flo' => ['application/vnd.micrografx.flo'], + 'flv' => ['video/x-flv', 'application/x-flash-video', 'flv-application/octet-stream', 'video/flv'], + 'flw' => ['application/vnd.kde.kivio', 'application/x-kivio'], + 'flx' => ['text/vnd.fmi.flexstor'], + 'fly' => ['text/vnd.fly'], + 'fm' => ['application/vnd.framemaker', 'application/x-frame'], + 'fnc' => ['application/vnd.frogans.fnc'], + 'fo' => ['text/x-xslfo'], + 'fodg' => ['application/vnd.oasis.opendocument.graphics-flat-xml'], + 'fodp' => ['application/vnd.oasis.opendocument.presentation-flat-xml'], + 'fods' => ['application/vnd.oasis.opendocument.spreadsheet-flat-xml'], + 'fodt' => ['application/vnd.oasis.opendocument.text-flat-xml'], + 'for' => ['text/x-fortran'], + 'fpx' => ['image/vnd.fpx'], + 'frame' => ['application/vnd.framemaker'], + 'fsc' => ['application/vnd.fsc.weblaunch'], + 'fst' => ['image/vnd.fst'], + 'ftc' => ['application/vnd.fluxtime.clip'], + 'fti' => ['application/vnd.anser-web-funds-transfer-initiation'], + 'fvt' => ['video/vnd.fvt'], + 'fxm' => ['video/x-javafx'], + 'fxp' => ['application/vnd.adobe.fxp'], + 'fxpl' => ['application/vnd.adobe.fxp'], + 'fzs' => ['application/vnd.fuzzysheet'], + 'g2w' => ['application/vnd.geoplan'], + 'g3' => ['image/fax-g3', 'image/g3fax'], + 'g3w' => ['application/vnd.geospace'], + 'gac' => ['application/vnd.groove-account'], + 'gam' => ['application/x-tads'], + 'gb' => ['application/x-gameboy-rom'], + 'gba' => ['application/x-gba-rom'], + 'gbc' => ['application/x-gameboy-color-rom'], + 'gbr' => ['application/rpki-ghostbusters', 'image/x-gimp-gbr'], + 'gca' => ['application/x-gca-compressed'], + 'gcode' => ['text/x.gcode'], + 'gcrd' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'gdl' => ['model/vnd.gdl'], + 'ged' => ['application/x-gedcom', 'text/gedcom'], + 'gedcom' => ['application/x-gedcom', 'text/gedcom'], + 'gem' => ['application/x-gtar', 'application/x-tar'], + 'gen' => ['application/x-genesis-rom'], + 'geo' => ['application/vnd.dynageo'], + 'geo.json' => ['application/geo+json', 'application/vnd.geo+json'], + 'geojson' => ['application/geo+json', 'application/vnd.geo+json'], + 'gex' => ['application/vnd.geometry-explorer'], + 'gf' => ['application/x-tex-gf'], + 'gg' => ['application/x-gamegear-rom'], + 'ggb' => ['application/vnd.geogebra.file'], + 'ggt' => ['application/vnd.geogebra.tool'], + 'ghf' => ['application/vnd.groove-help'], + 'gif' => ['image/gif'], + 'gih' => ['image/x-gimp-gih'], + 'gim' => ['application/vnd.groove-identity-message'], + 'glade' => ['application/x-glade'], + 'gml' => ['application/gml+xml'], + 'gmo' => ['application/x-gettext-translation'], + 'gmx' => ['application/vnd.gmx'], + 'gnc' => ['application/x-gnucash'], + 'gnd' => ['application/gnunet-directory'], + 'gnucash' => ['application/x-gnucash'], + 'gnumeric' => ['application/x-gnumeric'], + 'gnuplot' => ['application/x-gnuplot'], + 'go' => ['text/x-go'], + 'gp' => ['application/x-gnuplot'], + 'gpg' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'gph' => ['application/vnd.flographit'], + 'gplt' => ['application/x-gnuplot'], + 'gpx' => ['application/gpx', 'application/gpx+xml', 'application/x-gpx', 'application/x-gpx+xml'], + 'gqf' => ['application/vnd.grafeq'], + 'gqs' => ['application/vnd.grafeq'], + 'gra' => ['application/x-graphite'], + 'gram' => ['application/srgs'], + 'gramps' => ['application/x-gramps-xml'], + 'gre' => ['application/vnd.geometry-explorer'], + 'grv' => ['application/vnd.groove-injector'], + 'grxml' => ['application/srgs+xml'], + 'gs' => ['text/x-genie'], + 'gsf' => ['application/x-font-ghostscript', 'application/x-font-type1'], + 'gsm' => ['audio/x-gsm'], + 'gtar' => ['application/x-gtar', 'application/x-tar'], + 'gtm' => ['application/vnd.groove-tool-message'], + 'gtw' => ['model/vnd.gtw'], + 'gv' => ['text/vnd.graphviz'], + 'gvp' => ['text/google-video-pointer', 'text/x-google-video-pointer'], + 'gxf' => ['application/gxf'], + 'gxt' => ['application/vnd.geonext'], + 'gz' => ['application/x-gzip', 'application/gzip'], + 'h' => ['text/x-c', 'text/x-chdr'], + 'h++' => ['text/x-c++hdr'], + 'h261' => ['video/h261'], + 'h263' => ['video/h263'], + 'h264' => ['video/h264'], + 'h4' => ['application/x-hdf'], + 'h5' => ['application/x-hdf'], + 'hal' => ['application/vnd.hal+xml'], + 'hbci' => ['application/vnd.hbci'], + 'hdf' => ['application/x-hdf'], + 'hdf4' => ['application/x-hdf'], + 'hdf5' => ['application/x-hdf'], + 'heic' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'heif' => ['image/heic', 'image/heic-sequence', 'image/heif', 'image/heif-sequence'], + 'hfe' => ['application/x-hfe-file', 'application/x-hfe-floppy-image'], + 'hh' => ['text/x-c', 'text/x-c++hdr'], + 'hlp' => ['application/winhlp', 'zz-application/zz-winassoc-hlp'], + 'hp' => ['text/x-c++hdr'], + 'hpgl' => ['application/vnd.hp-hpgl'], + 'hpid' => ['application/vnd.hp-hpid'], + 'hpp' => ['text/x-c++hdr'], + 'hps' => ['application/vnd.hp-hps'], + 'hqx' => ['application/stuffit', 'application/mac-binhex40'], + 'hs' => ['text/x-haskell'], + 'htke' => ['application/vnd.kenameaapp'], + 'htm' => ['text/html'], + 'html' => ['text/html'], + 'hvd' => ['application/vnd.yamaha.hv-dic'], + 'hvp' => ['application/vnd.yamaha.hv-voice'], + 'hvs' => ['application/vnd.yamaha.hv-script'], + 'hwp' => ['application/vnd.haansoft-hwp', 'application/x-hwp'], + 'hwt' => ['application/vnd.haansoft-hwt', 'application/x-hwt'], + 'hxx' => ['text/x-c++hdr'], + 'i2g' => ['application/vnd.intergeo'], + 'ica' => ['application/x-ica'], + 'icb' => ['image/x-icb', 'image/x-tga'], + 'icc' => ['application/vnd.iccprofile'], + 'ice' => ['x-conference/x-cooltalk'], + 'icm' => ['application/vnd.iccprofile'], + 'icns' => ['image/x-icns'], + 'ico' => ['application/ico', 'image/ico', 'image/icon', 'image/vnd.microsoft.icon', 'image/x-ico', 'image/x-icon', 'text/ico'], + 'ics' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], + 'idl' => ['text/x-idl'], + 'ief' => ['image/ief'], + 'ifb' => ['text/calendar'], + 'iff' => ['image/x-iff', 'image/x-ilbm'], + 'ifm' => ['application/vnd.shana.informed.formdata'], + 'iges' => ['model/iges'], + 'igl' => ['application/vnd.igloader'], + 'igm' => ['application/vnd.insors.igm'], + 'igs' => ['model/iges'], + 'igx' => ['application/vnd.micrografx.igx'], + 'iif' => ['application/vnd.shana.informed.interchange'], + 'ilbm' => ['image/x-iff', 'image/x-ilbm'], + 'ime' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], + 'img' => ['application/x-raw-disk-image'], + 'img.xz' => ['application/x-raw-disk-image-xz-compressed'], + 'imp' => ['application/vnd.accpac.simply.imp'], + 'ims' => ['application/vnd.ms-ims'], + 'imy' => ['audio/imelody', 'audio/x-imelody', 'text/x-imelody'], + 'in' => ['text/plain'], + 'ink' => ['application/inkml+xml'], + 'inkml' => ['application/inkml+xml'], + 'ins' => ['application/x-tex', 'text/x-tex'], + 'install' => ['application/x-install-instructions'], + 'iota' => ['application/vnd.astraea-software.iota'], + 'ipfix' => ['application/ipfix'], + 'ipk' => ['application/vnd.shana.informed.package'], + 'iptables' => ['text/x-iptables'], + 'ipynb' => ['application/x-ipynb+json'], + 'irm' => ['application/vnd.ibm.rights-management'], + 'irp' => ['application/vnd.irepository.package+xml'], + 'iso' => ['application/x-cd-image', 'application/x-gamecube-iso-image', 'application/x-gamecube-rom', 'application/x-iso9660-image', 'application/x-saturn-rom', 'application/x-sega-cd-rom', 'application/x-wbfs', 'application/x-wia', 'application/x-wii-iso-image', 'application/x-wii-rom'], + 'iso9660' => ['application/x-cd-image', 'application/x-iso9660-image'], + 'it' => ['audio/x-it'], + 'it87' => ['application/x-it87'], + 'itp' => ['application/vnd.shana.informed.formtemplate'], + 'ivp' => ['application/vnd.immervision-ivp'], + 'ivu' => ['application/vnd.immervision-ivu'], + 'j2c' => ['image/x-jp2-codestream'], + 'j2k' => ['image/x-jp2-codestream'], + 'jad' => ['text/vnd.sun.j2me.app-descriptor'], + 'jam' => ['application/vnd.jam'], + 'jar' => ['application/x-java-archive', 'application/java-archive', 'application/x-jar'], + 'java' => ['text/x-java', 'text/x-java-source'], + 'jceks' => ['application/x-java-jce-keystore'], + 'jisp' => ['application/vnd.jisp'], + 'jks' => ['application/x-java-keystore'], + 'jlt' => ['application/vnd.hp-jlyt'], + 'jng' => ['image/x-jng'], + 'jnlp' => ['application/x-java-jnlp-file'], + 'joda' => ['application/vnd.joost.joda-archive'], + 'jp2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], + 'jpc' => ['image/x-jp2-codestream'], + 'jpe' => ['image/jpeg', 'image/pjpeg'], + 'jpeg' => ['image/jpeg', 'image/pjpeg'], + 'jpf' => ['image/jpx'], + 'jpg' => ['image/jpeg', 'image/pjpeg'], + 'jpg2' => ['image/jp2', 'image/jpeg2000', 'image/jpeg2000-image', 'image/x-jpeg2000-image'], + 'jpgm' => ['image/jpm', 'video/jpm'], + 'jpgv' => ['video/jpeg'], + 'jpm' => ['image/jpm', 'video/jpm'], + 'jpr' => ['application/x-jbuilder-project'], + 'jpx' => ['application/x-jbuilder-project', 'image/jpx'], + 'jrd' => ['application/jrd+json'], + 'js' => ['text/javascript', 'application/javascript', 'application/x-javascript'], + 'jsm' => ['application/javascript', 'application/x-javascript', 'text/javascript'], + 'json' => ['application/json'], + 'json-patch' => ['application/json-patch+json'], + 'jsonld' => ['application/ld+json'], + 'jsonml' => ['application/jsonml+json'], + 'k25' => ['image/x-kodak-k25'], + 'k7' => ['application/x-thomson-cassette'], + 'kar' => ['audio/midi', 'audio/x-midi'], + 'karbon' => ['application/vnd.kde.karbon', 'application/x-karbon'], + 'kdc' => ['image/x-kodak-kdc'], + 'kdelnk' => ['application/x-desktop', 'application/x-gnome-app-info'], + 'kexi' => ['application/x-kexiproject-sqlite', 'application/x-kexiproject-sqlite2', 'application/x-kexiproject-sqlite3', 'application/x-vnd.kde.kexi'], + 'kexic' => ['application/x-kexi-connectiondata'], + 'kexis' => ['application/x-kexiproject-shortcut'], + 'key' => ['application/vnd.apple.keynote', 'application/x-iwork-keynote-sffkey'], + 'kfo' => ['application/vnd.kde.kformula', 'application/x-kformula'], + 'kia' => ['application/vnd.kidspiration'], + 'kil' => ['application/x-killustrator'], + 'kino' => ['application/smil', 'application/smil+xml'], + 'kml' => ['application/vnd.google-earth.kml+xml'], + 'kmz' => ['application/vnd.google-earth.kmz'], + 'kne' => ['application/vnd.kinar'], + 'knp' => ['application/vnd.kinar'], + 'kon' => ['application/vnd.kde.kontour', 'application/x-kontour'], + 'kpm' => ['application/x-kpovmodeler'], + 'kpr' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], + 'kpt' => ['application/vnd.kde.kpresenter', 'application/x-kpresenter'], + 'kpxx' => ['application/vnd.ds-keypoint'], + 'kra' => ['application/x-krita'], + 'ks' => ['application/x-java-keystore'], + 'ksp' => ['application/vnd.kde.kspread', 'application/x-kspread'], + 'ktr' => ['application/vnd.kahootz'], + 'ktx' => ['image/ktx'], + 'ktz' => ['application/vnd.kahootz'], + 'kud' => ['application/x-kugar'], + 'kwd' => ['application/vnd.kde.kword', 'application/x-kword'], + 'kwt' => ['application/vnd.kde.kword', 'application/x-kword'], + 'la' => ['application/x-shared-library-la'], + 'lasxml' => ['application/vnd.las.las+xml'], + 'latex' => ['application/x-latex', 'application/x-tex', 'text/x-tex'], + 'lbd' => ['application/vnd.llamagraphics.life-balance.desktop'], + 'lbe' => ['application/vnd.llamagraphics.life-balance.exchange+xml'], + 'lbm' => ['image/x-iff', 'image/x-ilbm'], + 'ldif' => ['text/x-ldif'], + 'les' => ['application/vnd.hhe.lesson-player'], + 'lha' => ['application/x-lha', 'application/x-lzh-compressed'], + 'lhs' => ['text/x-literate-haskell'], + 'lhz' => ['application/x-lhz'], + 'link66' => ['application/vnd.route66.link66+xml'], + 'list' => ['text/plain'], + 'list3820' => ['application/vnd.ibm.modcap'], + 'listafp' => ['application/vnd.ibm.modcap'], + 'lnk' => ['application/x-ms-shortcut'], + 'lnx' => ['application/x-atari-lynx-rom'], + 'loas' => ['audio/usac'], + 'log' => ['text/plain', 'text/x-log'], + 'lostxml' => ['application/lost+xml'], + 'lrf' => ['application/octet-stream'], + 'lrm' => ['application/vnd.ms-lrm'], + 'lrv' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'lrz' => ['application/x-lrzip'], + 'ltf' => ['application/vnd.frogans.ltf'], + 'ltx' => ['application/x-tex', 'text/x-tex'], + 'lua' => ['text/x-lua'], + 'lvp' => ['audio/vnd.lucent.voice'], + 'lwo' => ['image/x-lwo'], + 'lwob' => ['image/x-lwo'], + 'lwp' => ['application/vnd.lotus-wordpro'], + 'lws' => ['image/x-lws'], + 'ly' => ['text/x-lilypond'], + 'lyx' => ['application/x-lyx', 'text/x-lyx'], + 'lz' => ['application/x-lzip'], + 'lz4' => ['application/x-lz4'], + 'lzh' => ['application/x-lha', 'application/x-lzh-compressed'], + 'lzma' => ['application/x-lzma'], + 'lzo' => ['application/x-lzop'], + 'm' => ['text/x-matlab', 'text/x-objcsrc', 'text/x-octave'], + 'm13' => ['application/x-msmediaview'], + 'm14' => ['application/x-msmediaview'], + 'm15' => ['audio/x-mod'], + 'm1u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'm1v' => ['video/mpeg'], + 'm21' => ['application/mp21'], + 'm2a' => ['audio/mpeg'], + 'm2t' => ['video/mp2t'], + 'm2ts' => ['video/mp2t'], + 'm2v' => ['video/mpeg'], + 'm3a' => ['audio/mpeg'], + 'm3u' => ['audio/x-mpegurl', 'application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist'], + 'm3u8' => ['application/m3u', 'application/vnd.apple.mpegurl', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], + 'm4' => ['application/x-m4'], + 'm4a' => ['audio/mp4', 'audio/m4a', 'audio/x-m4a'], + 'm4b' => ['audio/x-m4b'], + 'm4r' => ['audio/x-m4r'], + 'm4u' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'm4v' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'm7' => ['application/x-thomson-cartridge-memo7'], + 'ma' => ['application/mathematica'], + 'mab' => ['application/x-markaby'], + 'mads' => ['application/mads+xml'], + 'mag' => ['application/vnd.ecowin.chart'], + 'mak' => ['text/x-makefile'], + 'maker' => ['application/vnd.framemaker'], + 'man' => ['application/x-troff-man', 'text/troff'], + 'manifest' => ['text/cache-manifest'], + 'mar' => ['application/octet-stream'], + 'markdown' => ['text/markdown', 'text/x-markdown'], + 'mathml' => ['application/mathml+xml'], + 'mb' => ['application/mathematica'], + 'mbk' => ['application/vnd.mobius.mbk'], + 'mbox' => ['application/mbox'], + 'mc1' => ['application/vnd.medcalcdata'], + 'mcd' => ['application/vnd.mcd'], + 'mcurl' => ['text/vnd.curl.mcurl'], + 'md' => ['text/markdown', 'text/x-markdown'], + 'mdb' => ['application/x-msaccess', 'application/mdb', 'application/msaccess', 'application/vnd.ms-access', 'application/vnd.msaccess', 'application/x-mdb', 'zz-application/zz-winassoc-mdb'], + 'mdi' => ['image/vnd.ms-modi'], + 'mdx' => ['application/x-genesis-32x-rom'], + 'me' => ['text/troff', 'text/x-troff-me'], + 'med' => ['audio/x-mod'], + 'mesh' => ['model/mesh'], + 'meta4' => ['application/metalink4+xml'], + 'metalink' => ['application/metalink+xml'], + 'mets' => ['application/mets+xml'], + 'mfm' => ['application/vnd.mfmp'], + 'mft' => ['application/rpki-manifest'], + 'mgp' => ['application/vnd.osgeo.mapguide.package', 'application/x-magicpoint'], + 'mgz' => ['application/vnd.proteus.magazine'], + 'mht' => ['application/x-mimearchive'], + 'mhtml' => ['application/x-mimearchive'], + 'mid' => ['audio/midi', 'audio/x-midi'], + 'midi' => ['audio/midi', 'audio/x-midi'], + 'mie' => ['application/x-mie'], + 'mif' => ['application/vnd.mif', 'application/x-mif'], + 'mime' => ['message/rfc822'], + 'minipsf' => ['audio/x-minipsf'], + 'mj2' => ['video/mj2'], + 'mjp2' => ['video/mj2'], + 'mjpeg' => ['video/x-mjpeg'], + 'mjpg' => ['video/x-mjpeg'], + 'mjs' => ['application/javascript', 'application/x-javascript', 'text/javascript'], + 'mk' => ['text/x-makefile'], + 'mk3d' => ['video/x-matroska', 'video/x-matroska-3d'], + 'mka' => ['audio/x-matroska'], + 'mkd' => ['text/markdown', 'text/x-markdown'], + 'mks' => ['video/x-matroska'], + 'mkv' => ['video/x-matroska'], + 'ml' => ['text/x-ocaml'], + 'mli' => ['text/x-ocaml'], + 'mlp' => ['application/vnd.dolby.mlp'], + 'mm' => ['text/x-troff-mm'], + 'mmd' => ['application/vnd.chipnuts.karaoke-mmd'], + 'mmf' => ['application/vnd.smaf', 'application/x-smaf'], + 'mml' => ['application/mathml+xml', 'text/mathml'], + 'mmr' => ['image/vnd.fujixerox.edmics-mmr'], + 'mng' => ['video/x-mng'], + 'mny' => ['application/x-msmoney'], + 'mo' => ['application/x-gettext-translation', 'text/x-modelica'], + 'mo3' => ['audio/x-mo3'], + 'mobi' => ['application/x-mobipocket-ebook'], + 'moc' => ['text/x-moc'], + 'mod' => ['audio/x-mod'], + 'mods' => ['application/mods+xml'], + 'mof' => ['text/x-mof'], + 'moov' => ['video/quicktime'], + 'mount' => ['text/x-systemd-unit'], + 'mov' => ['video/quicktime'], + 'movie' => ['video/x-sgi-movie'], + 'mp+' => ['audio/x-musepack'], + 'mp2' => ['audio/mp2', 'audio/mpeg', 'audio/x-mp2', 'video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mp21' => ['application/mp21'], + 'mp2a' => ['audio/mpeg'], + 'mp3' => ['audio/mpeg', 'audio/mp3', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], + 'mp4' => ['video/mp4', 'video/mp4v-es', 'video/x-m4v'], + 'mp4a' => ['audio/mp4'], + 'mp4s' => ['application/mp4'], + 'mp4v' => ['video/mp4'], + 'mpc' => ['application/vnd.mophun.certificate', 'audio/x-musepack'], + 'mpe' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpeg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpg' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2'], + 'mpg4' => ['video/mp4'], + 'mpga' => ['audio/mp3', 'audio/mpeg', 'audio/x-mp3', 'audio/x-mpeg', 'audio/x-mpg'], + 'mpkg' => ['application/vnd.apple.installer+xml'], + 'mpl' => ['video/mp2t'], + 'mpls' => ['video/mp2t'], + 'mpm' => ['application/vnd.blueice.multipass'], + 'mpn' => ['application/vnd.mophun.application'], + 'mpp' => ['application/vnd.ms-project', 'audio/x-musepack'], + 'mpt' => ['application/vnd.ms-project'], + 'mpy' => ['application/vnd.ibm.minipay'], + 'mqy' => ['application/vnd.mobius.mqy'], + 'mrc' => ['application/marc'], + 'mrcx' => ['application/marcxml+xml'], + 'mrl' => ['text/x-mrml'], + 'mrml' => ['text/x-mrml'], + 'mrw' => ['image/x-minolta-mrw'], + 'ms' => ['text/troff', 'text/x-troff-ms'], + 'mscml' => ['application/mediaservercontrol+xml'], + 'mseed' => ['application/vnd.fdsn.mseed'], + 'mseq' => ['application/vnd.mseq'], + 'msf' => ['application/vnd.epson.msf'], + 'msh' => ['model/mesh'], + 'msi' => ['application/x-msdownload', 'application/x-msi'], + 'msl' => ['application/vnd.mobius.msl'], + 'msod' => ['image/x-msod'], + 'msty' => ['application/vnd.muvee.style'], + 'msx' => ['application/x-msx-rom'], + 'mtm' => ['audio/x-mod'], + 'mts' => ['model/vnd.mts', 'video/mp2t'], + 'mup' => ['text/x-mup'], + 'mus' => ['application/vnd.musician'], + 'musicxml' => ['application/vnd.recordare.musicxml+xml'], + 'mvb' => ['application/x-msmediaview'], + 'mwf' => ['application/vnd.mfer'], + 'mxf' => ['application/mxf'], + 'mxl' => ['application/vnd.recordare.musicxml'], + 'mxml' => ['application/xv+xml'], + 'mxs' => ['application/vnd.triscape.mxs'], + 'mxu' => ['video/vnd.mpegurl', 'video/x-mpegurl'], + 'n-gage' => ['application/vnd.nokia.n-gage.symbian.install'], + 'n3' => ['text/n3'], + 'n64' => ['application/x-n64-rom'], + 'nb' => ['application/mathematica', 'application/x-mathematica'], + 'nbp' => ['application/vnd.wolfram.player'], + 'nc' => ['application/x-netcdf'], + 'ncx' => ['application/x-dtbncx+xml'], + 'nds' => ['application/x-nintendo-ds-rom'], + 'nef' => ['image/x-nikon-nef'], + 'nes' => ['application/x-nes-rom'], + 'nez' => ['application/x-nes-rom'], + 'nfo' => ['text/x-nfo'], + 'ngc' => ['application/x-neo-geo-pocket-color-rom'], + 'ngdat' => ['application/vnd.nokia.n-gage.data'], + 'ngp' => ['application/x-neo-geo-pocket-rom'], + 'nitf' => ['application/vnd.nitf'], + 'nlu' => ['application/vnd.neurolanguage.nlu'], + 'nml' => ['application/vnd.enliven'], + 'nnd' => ['application/vnd.noblenet-directory'], + 'nns' => ['application/vnd.noblenet-sealer'], + 'nnw' => ['application/vnd.noblenet-web'], + 'not' => ['text/x-mup'], + 'npx' => ['image/vnd.net-fpx'], + 'nsc' => ['application/x-conference', 'application/x-netshow-channel'], + 'nsf' => ['application/vnd.lotus-notes'], + 'nsv' => ['video/x-nsv'], + 'ntf' => ['application/vnd.nitf'], + 'nzb' => ['application/x-nzb'], + 'o' => ['application/x-object'], + 'oa2' => ['application/vnd.fujitsu.oasys2'], + 'oa3' => ['application/vnd.fujitsu.oasys3'], + 'oas' => ['application/vnd.fujitsu.oasys'], + 'obd' => ['application/x-msbinder'], + 'obj' => ['application/x-tgif'], + 'ocl' => ['text/x-ocl'], + 'oda' => ['application/oda'], + 'odb' => ['application/vnd.oasis.opendocument.database', 'application/vnd.sun.xml.base'], + 'odc' => ['application/vnd.oasis.opendocument.chart'], + 'odf' => ['application/vnd.oasis.opendocument.formula'], + 'odft' => ['application/vnd.oasis.opendocument.formula-template'], + 'odg' => ['vnd.oasis.opendocument.graphics', 'application/vnd.oasis.opendocument.graphics'], + 'odi' => ['application/vnd.oasis.opendocument.image'], + 'odm' => ['application/vnd.oasis.opendocument.text-master'], + 'odp' => ['vnd.oasis.opendocument.presentation', 'application/vnd.oasis.opendocument.presentation'], + 'ods' => ['vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.spreadsheet'], + 'odt' => ['vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.text'], + 'oga' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg'], + 'ogg' => ['audio/ogg', 'audio/vorbis', 'audio/x-flac+ogg', 'audio/x-ogg', 'audio/x-oggflac', 'audio/x-speex+ogg', 'audio/x-vorbis', 'audio/x-vorbis+ogg', 'video/ogg', 'video/x-ogg', 'video/x-theora', 'video/x-theora+ogg'], + 'ogm' => ['video/x-ogm', 'video/x-ogm+ogg'], + 'ogv' => ['video/ogg', 'video/x-ogg'], + 'ogx' => ['application/ogg', 'application/x-ogg'], + 'old' => ['application/x-trash'], + 'oleo' => ['application/x-oleo'], + 'omdoc' => ['application/omdoc+xml'], + 'onepkg' => ['application/onenote'], + 'onetmp' => ['application/onenote'], + 'onetoc' => ['application/onenote'], + 'onetoc2' => ['application/onenote'], + 'ooc' => ['text/x-ooc'], + 'opf' => ['application/oebps-package+xml'], + 'opml' => ['text/x-opml', 'text/x-opml+xml'], + 'oprc' => ['application/vnd.palm', 'application/x-palm-database'], + 'opus' => ['audio/ogg', 'audio/x-ogg', 'audio/x-opus+ogg'], + 'ora' => ['image/openraster'], + 'orf' => ['image/x-olympus-orf'], + 'org' => ['application/vnd.lotus-organizer'], + 'osf' => ['application/vnd.yamaha.openscoreformat'], + 'osfpvg' => ['application/vnd.yamaha.openscoreformat.osfpvg+xml'], + 'otc' => ['application/vnd.oasis.opendocument.chart-template'], + 'otf' => ['application/vnd.oasis.opendocument.formula-template', 'application/x-font-otf', 'font/otf'], + 'otg' => ['application/vnd.oasis.opendocument.graphics-template'], + 'oth' => ['application/vnd.oasis.opendocument.text-web'], + 'oti' => ['application/vnd.oasis.opendocument.image-template'], + 'otp' => ['application/vnd.oasis.opendocument.presentation-template'], + 'ots' => ['application/vnd.oasis.opendocument.spreadsheet-template'], + 'ott' => ['application/vnd.oasis.opendocument.text-template'], + 'owl' => ['application/rdf+xml', 'text/rdf'], + 'owx' => ['application/owl+xml'], + 'oxps' => ['application/oxps', 'application/vnd.ms-xpsdocument', 'application/xps'], + 'oxt' => ['application/vnd.openofficeorg.extension'], + 'p' => ['text/x-pascal'], + 'p10' => ['application/pkcs10'], + 'p12' => ['application/pkcs12', 'application/x-pkcs12'], + 'p65' => ['application/x-pagemaker'], + 'p7b' => ['application/x-pkcs7-certificates'], + 'p7c' => ['application/pkcs7-mime'], + 'p7m' => ['application/pkcs7-mime'], + 'p7r' => ['application/x-pkcs7-certreqresp'], + 'p7s' => ['application/pkcs7-signature'], + 'p8' => ['application/pkcs8'], + 'p8e' => ['application/pkcs8-encrypted'], + 'pack' => ['application/x-java-pack200'], + 'pak' => ['application/x-pak'], + 'par2' => ['application/x-par2'], + 'part' => ['application/x-partial-download'], + 'pas' => ['text/x-pascal'], + 'pat' => ['image/x-gimp-pat'], + 'patch' => ['text/x-diff', 'text/x-patch'], + 'path' => ['text/x-systemd-unit'], + 'paw' => ['application/vnd.pawaafile'], + 'pbd' => ['application/vnd.powerbuilder6'], + 'pbm' => ['image/x-portable-bitmap'], + 'pcap' => ['application/pcap', 'application/vnd.tcpdump.pcap', 'application/x-pcap'], + 'pcd' => ['image/x-photo-cd'], + 'pce' => ['application/x-pc-engine-rom'], + 'pcf' => ['application/x-cisco-vpn-settings', 'application/x-font-pcf'], + 'pcf.Z' => ['application/x-font-pcf'], + 'pcf.gz' => ['application/x-font-pcf'], + 'pcl' => ['application/vnd.hp-pcl'], + 'pclxl' => ['application/vnd.hp-pclxl'], + 'pct' => ['image/x-pict'], + 'pcurl' => ['application/vnd.curl.pcurl'], + 'pcx' => ['image/vnd.zbrush.pcx', 'image/x-pcx'], + 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-palm-database'], + 'pdc' => ['application/x-aportisdoc'], + 'pdf' => ['application/pdf', 'application/acrobat', 'application/nappdf', 'application/x-pdf', 'image/pdf'], + 'pdf.bz2' => ['application/x-bzpdf'], + 'pdf.gz' => ['application/x-gzpdf'], + 'pdf.lz' => ['application/x-lzpdf'], + 'pdf.xz' => ['application/x-xzpdf'], + 'pef' => ['image/x-pentax-pef'], + 'pem' => ['application/x-x509-ca-cert'], + 'perl' => ['application/x-perl', 'text/x-perl'], + 'pfa' => ['application/x-font-type1'], + 'pfb' => ['application/x-font-type1'], + 'pfm' => ['application/x-font-type1'], + 'pfr' => ['application/font-tdpfr'], + 'pfx' => ['application/pkcs12', 'application/x-pkcs12'], + 'pgm' => ['image/x-portable-graymap'], + 'pgn' => ['application/vnd.chess-pgn', 'application/x-chess-pgn'], + 'pgp' => ['application/pgp', 'application/pgp-encrypted', 'application/pgp-keys', 'application/pgp-signature'], + 'php' => ['application/x-php'], + 'php3' => ['application/x-php'], + 'php4' => ['application/x-php'], + 'php5' => ['application/x-php'], + 'phps' => ['application/x-php'], + 'pic' => ['image/x-pict'], + 'pict' => ['image/x-pict'], + 'pict1' => ['image/x-pict'], + 'pict2' => ['image/x-pict'], + 'pk' => ['application/x-tex-pk'], + 'pkg' => ['application/octet-stream', 'application/x-xar'], + 'pki' => ['application/pkixcmp'], + 'pkipath' => ['application/pkix-pkipath'], + 'pkr' => ['application/pgp-keys'], + 'pl' => ['application/x-perl', 'text/x-perl'], + 'pla' => ['audio/x-iriver-pla'], + 'plb' => ['application/vnd.3gpp.pic-bw-large'], + 'plc' => ['application/vnd.mobius.plc'], + 'plf' => ['application/vnd.pocketlearn'], + 'pln' => ['application/x-planperfect'], + 'pls' => ['application/pls', 'application/pls+xml', 'audio/scpls', 'audio/x-scpls'], + 'pm' => ['application/x-pagemaker', 'application/x-perl', 'text/x-perl'], + 'pm6' => ['application/x-pagemaker'], + 'pmd' => ['application/x-pagemaker'], + 'pml' => ['application/vnd.ctc-posml'], + 'png' => ['image/png'], + 'pnm' => ['image/x-portable-anymap'], + 'pntg' => ['image/x-macpaint'], + 'po' => ['application/x-gettext', 'text/x-gettext-translation', 'text/x-po'], + 'pod' => ['application/x-perl', 'text/x-perl'], + 'por' => ['application/x-spss-por'], + 'portpkg' => ['application/vnd.macports.portpkg'], + 'pot' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint', 'text/x-gettext-translation-template', 'text/x-pot'], + 'potm' => ['application/vnd.ms-powerpoint.template.macroenabled.12'], + 'potx' => ['application/vnd.openxmlformats-officedocument.presentationml.template'], + 'ppam' => ['application/vnd.ms-powerpoint.addin.macroenabled.12'], + 'ppd' => ['application/vnd.cups-ppd'], + 'ppm' => ['image/x-portable-pixmap'], + 'pps' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], + 'ppsm' => ['application/vnd.ms-powerpoint.slideshow.macroenabled.12'], + 'ppsx' => ['application/vnd.openxmlformats-officedocument.presentationml.slideshow'], + 'ppt' => ['application/vnd.ms-powerpoint', 'application/mspowerpoint', 'application/powerpoint', 'application/x-mspowerpoint'], + 'pptm' => ['application/vnd.ms-powerpoint.presentation.macroenabled.12'], + 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'], + 'ppz' => ['application/mspowerpoint', 'application/powerpoint', 'application/vnd.ms-powerpoint', 'application/x-mspowerpoint'], + 'pqa' => ['application/vnd.palm', 'application/x-palm-database'], + 'prc' => ['application/vnd.palm', 'application/x-mobipocket-ebook', 'application/x-palm-database'], + 'pre' => ['application/vnd.lotus-freelance'], + 'prf' => ['application/pics-rules'], + 'ps' => ['application/postscript'], + 'ps.bz2' => ['application/x-bzpostscript'], + 'ps.gz' => ['application/x-gzpostscript'], + 'psb' => ['application/vnd.3gpp.pic-bw-small'], + 'psd' => ['application/photoshop', 'application/x-photoshop', 'image/photoshop', 'image/psd', 'image/vnd.adobe.photoshop', 'image/x-photoshop', 'image/x-psd'], + 'psf' => ['application/x-font-linux-psf', 'audio/x-psf'], + 'psf.gz' => ['application/x-gz-font-linux-psf'], + 'psflib' => ['audio/x-psflib'], + 'psid' => ['audio/prs.sid'], + 'pskcxml' => ['application/pskc+xml'], + 'psw' => ['application/x-pocket-word'], + 'ptid' => ['application/vnd.pvi.ptid1'], + 'pub' => ['application/vnd.ms-publisher', 'application/x-mspublisher'], + 'pvb' => ['application/vnd.3gpp.pic-bw-var'], + 'pw' => ['application/x-pw'], + 'pwn' => ['application/vnd.3m.post-it-notes'], + 'py' => ['text/x-python', 'text/x-python3'], + 'py3' => ['text/x-python3'], + 'py3x' => ['text/x-python3'], + 'pya' => ['audio/vnd.ms-playready.media.pya'], + 'pyc' => ['application/x-python-bytecode'], + 'pyo' => ['application/x-python-bytecode'], + 'pyv' => ['video/vnd.ms-playready.media.pyv'], + 'pyx' => ['text/x-python'], + 'qam' => ['application/vnd.epson.quickanime'], + 'qbo' => ['application/vnd.intu.qbo'], + 'qd' => ['application/x-fd-file', 'application/x-raw-floppy-disk-image'], + 'qfx' => ['application/vnd.intu.qfx'], + 'qif' => ['application/x-qw', 'image/x-quicktime'], + 'qml' => ['text/x-qml'], + 'qmlproject' => ['text/x-qml'], + 'qmltypes' => ['text/x-qml'], + 'qp' => ['application/x-qpress'], + 'qps' => ['application/vnd.publishare-delta-tree'], + 'qt' => ['video/quicktime'], + 'qti' => ['application/x-qtiplot'], + 'qti.gz' => ['application/x-qtiplot'], + 'qtif' => ['image/x-quicktime'], + 'qtl' => ['application/x-quicktime-media-link', 'application/x-quicktimeplayer'], + 'qtvr' => ['video/quicktime'], + 'qwd' => ['application/vnd.quark.quarkxpress'], + 'qwt' => ['application/vnd.quark.quarkxpress'], + 'qxb' => ['application/vnd.quark.quarkxpress'], + 'qxd' => ['application/vnd.quark.quarkxpress'], + 'qxl' => ['application/vnd.quark.quarkxpress'], + 'qxt' => ['application/vnd.quark.quarkxpress'], + 'ra' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio'], + 'raf' => ['image/x-fuji-raf'], + 'ram' => ['application/ram', 'audio/x-pn-realaudio'], + 'raml' => ['application/raml+yaml'], + 'rar' => ['application/x-rar-compressed', 'application/vnd.rar', 'application/x-rar'], + 'ras' => ['image/x-cmu-raster'], + 'raw' => ['image/x-panasonic-raw', 'image/x-panasonic-rw'], + 'raw-disk-image' => ['application/x-raw-disk-image'], + 'raw-disk-image.xz' => ['application/x-raw-disk-image-xz-compressed'], + 'rax' => ['audio/vnd.m-realaudio', 'audio/vnd.rn-realaudio', 'audio/x-pn-realaudio'], + 'rb' => ['application/x-ruby'], + 'rcprofile' => ['application/vnd.ipunplugged.rcprofile'], + 'rdf' => ['application/rdf+xml', 'text/rdf'], + 'rdfs' => ['application/rdf+xml', 'text/rdf'], + 'rdz' => ['application/vnd.data-vision.rdz'], + 'reg' => ['text/x-ms-regedit'], + 'rej' => ['application/x-reject', 'text/x-reject'], + 'rep' => ['application/vnd.businessobjects'], + 'res' => ['application/x-dtbresource+xml'], + 'rgb' => ['image/x-rgb'], + 'rif' => ['application/reginfo+xml'], + 'rip' => ['audio/vnd.rip'], + 'ris' => ['application/x-research-info-systems'], + 'rl' => ['application/resource-lists+xml'], + 'rlc' => ['image/vnd.fujixerox.edmics-rlc'], + 'rld' => ['application/resource-lists-diff+xml'], + 'rle' => ['image/rle'], + 'rm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmi' => ['audio/midi'], + 'rmj' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmm' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmp' => ['audio/x-pn-realaudio-plugin'], + 'rms' => ['application/vnd.jcp.javame.midlet-rms', 'application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmvb' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rmx' => ['application/vnd.rn-realmedia', 'application/vnd.rn-realmedia-vbr'], + 'rnc' => ['application/relax-ng-compact-syntax', 'application/x-rnc'], + 'rng' => ['application/xml', 'text/xml'], + 'roa' => ['application/rpki-roa'], + 'roff' => ['application/x-troff', 'text/troff', 'text/x-troff'], + 'rp' => ['image/vnd.rn-realpix'], + 'rp9' => ['application/vnd.cloanto.rp9'], + 'rpm' => ['application/x-redhat-package-manager', 'application/x-rpm'], + 'rpss' => ['application/vnd.nokia.radio-presets'], + 'rpst' => ['application/vnd.nokia.radio-preset'], + 'rq' => ['application/sparql-query'], + 'rs' => ['application/rls-services+xml', 'text/rust'], + 'rsd' => ['application/rsd+xml'], + 'rss' => ['application/rss+xml', 'text/rss'], + 'rt' => ['text/vnd.rn-realtext'], + 'rtf' => ['application/rtf', 'text/rtf'], + 'rtx' => ['text/richtext'], + 'rv' => ['video/vnd.rn-realvideo', 'video/x-real-video'], + 'rvx' => ['video/vnd.rn-realvideo', 'video/x-real-video'], + 'rw2' => ['image/x-panasonic-raw2', 'image/x-panasonic-rw2'], + 's' => ['text/x-asm'], + 's3m' => ['audio/s3m', 'audio/x-s3m'], + 'saf' => ['application/vnd.yamaha.smaf-audio'], + 'sam' => ['application/x-amipro'], + 'sami' => ['application/x-sami'], + 'sap' => ['application/x-sap-file', 'application/x-thomson-sap-image'], + 'sass' => ['text/x-sass'], + 'sav' => ['application/x-spss-sav', 'application/x-spss-savefile'], + 'sbml' => ['application/sbml+xml'], + 'sc' => ['application/vnd.ibm.secure-container'], + 'scala' => ['text/x-scala'], + 'scd' => ['application/x-msschedule'], + 'scm' => ['application/vnd.lotus-screencam', 'text/x-scheme'], + 'scope' => ['text/x-systemd-unit'], + 'scq' => ['application/scvp-cv-request'], + 'scs' => ['application/scvp-cv-response'], + 'scss' => ['text/x-scss'], + 'scurl' => ['text/vnd.curl.scurl'], + 'sda' => ['application/vnd.stardivision.draw'], + 'sdc' => ['application/vnd.stardivision.calc'], + 'sdd' => ['application/vnd.stardivision.impress'], + 'sdkd' => ['application/vnd.solent.sdkm+xml'], + 'sdkm' => ['application/vnd.solent.sdkm+xml'], + 'sdp' => ['application/sdp', 'application/vnd.sdp', 'application/vnd.stardivision.impress', 'application/x-sdp'], + 'sds' => ['application/vnd.stardivision.chart'], + 'sdw' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'see' => ['application/vnd.seemail'], + 'seed' => ['application/vnd.fdsn.seed'], + 'sema' => ['application/vnd.sema'], + 'semd' => ['application/vnd.semd'], + 'semf' => ['application/vnd.semf'], + 'ser' => ['application/java-serialized-object'], + 'service' => ['text/x-dbus-service', 'text/x-systemd-unit'], + 'setpay' => ['application/set-payment-initiation'], + 'setreg' => ['application/set-registration-initiation'], + 'sfc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], + 'sfd-hdstx' => ['application/vnd.hydrostatix.sof-data'], + 'sfs' => ['application/vnd.spotfire.sfs'], + 'sfv' => ['text/x-sfv'], + 'sg' => ['application/x-sg1000-rom'], + 'sgb' => ['application/x-gameboy-rom'], + 'sgf' => ['application/x-go-sgf'], + 'sgi' => ['image/sgi', 'image/x-sgi'], + 'sgl' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'sgm' => ['text/sgml'], + 'sgml' => ['text/sgml'], + 'sh' => ['application/x-sh', 'application/x-shellscript', 'text/x-sh'], + 'shape' => ['application/x-dia-shape'], + 'shar' => ['application/x-shar'], + 'shf' => ['application/shf+xml'], + 'shn' => ['application/x-shorten', 'audio/x-shorten'], + 'siag' => ['application/x-siag'], + 'sid' => ['audio/prs.sid', 'image/x-mrsid-image'], + 'sig' => ['application/pgp-signature'], + 'sik' => ['application/x-trash'], + 'sil' => ['audio/silk'], + 'silo' => ['model/mesh'], + 'sis' => ['application/vnd.symbian.install'], + 'sisx' => ['application/vnd.symbian.install', 'x-epoc/x-sisx-app'], + 'sit' => ['application/x-stuffit', 'application/stuffit', 'application/x-sit'], + 'sitx' => ['application/x-stuffitx'], + 'siv' => ['application/sieve'], + 'sk' => ['image/x-skencil'], + 'sk1' => ['image/x-skencil'], + 'skd' => ['application/vnd.koan'], + 'skm' => ['application/vnd.koan'], + 'skp' => ['application/vnd.koan'], + 'skr' => ['application/pgp-keys'], + 'skt' => ['application/vnd.koan'], + 'sldm' => ['application/vnd.ms-powerpoint.slide.macroenabled.12'], + 'sldx' => ['application/vnd.openxmlformats-officedocument.presentationml.slide'], + 'slice' => ['text/x-systemd-unit'], + 'slk' => ['text/spreadsheet'], + 'slt' => ['application/vnd.epson.salt'], + 'sm' => ['application/vnd.stepmania.stepchart'], + 'smaf' => ['application/vnd.smaf', 'application/x-smaf'], + 'smc' => ['application/vnd.nintendo.snes.rom', 'application/x-snes-rom'], + 'smd' => ['application/vnd.stardivision.mail', 'application/x-genesis-rom'], + 'smf' => ['application/vnd.stardivision.math'], + 'smi' => ['application/smil', 'application/smil+xml', 'application/x-sami'], + 'smil' => ['application/smil', 'application/smil+xml'], + 'sml' => ['application/smil', 'application/smil+xml'], + 'sms' => ['application/x-sms-rom'], + 'smv' => ['video/x-smv'], + 'smzip' => ['application/vnd.stepmania.package'], + 'snap' => ['application/vnd.snap'], + 'snd' => ['audio/basic'], + 'snf' => ['application/x-font-snf'], + 'so' => ['application/octet-stream', 'application/x-sharedlib'], + 'socket' => ['text/x-systemd-unit'], + 'spc' => ['application/x-pkcs7-certificates'], + 'spd' => ['application/x-font-speedo'], + 'spec' => ['text/x-rpm-spec'], + 'spf' => ['application/vnd.yamaha.smaf-phrase'], + 'spl' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-futuresplash', 'application/x-shockwave-flash'], + 'spm' => ['application/x-source-rpm'], + 'spot' => ['text/vnd.in3d.spot'], + 'spp' => ['application/scvp-vp-response'], + 'spq' => ['application/scvp-vp-request'], + 'spx' => ['audio/ogg', 'audio/x-speex'], + 'sql' => ['application/sql', 'application/x-sql', 'text/x-sql'], + 'sqlite2' => ['application/x-sqlite2'], + 'sqlite3' => ['application/vnd.sqlite3', 'application/x-sqlite3'], + 'sqsh' => ['application/vnd.squashfs'], + 'sr2' => ['image/x-sony-sr2'], + 'src' => ['application/x-wais-source'], + 'src.rpm' => ['application/x-source-rpm'], + 'srf' => ['image/x-sony-srf'], + 'srt' => ['application/x-srt', 'application/x-subrip'], + 'sru' => ['application/sru+xml'], + 'srx' => ['application/sparql-results+xml'], + 'ss' => ['text/x-scheme'], + 'ssa' => ['text/x-ssa'], + 'ssdl' => ['application/ssdl+xml'], + 'sse' => ['application/vnd.kodak-descriptor'], + 'ssf' => ['application/vnd.epson.ssf'], + 'ssml' => ['application/ssml+xml'], + 'st' => ['application/vnd.sailingtracker.track'], + 'stc' => ['application/vnd.sun.xml.calc.template'], + 'std' => ['application/vnd.sun.xml.draw.template'], + 'stf' => ['application/vnd.wt.stf'], + 'sti' => ['application/vnd.sun.xml.impress.template'], + 'stk' => ['application/hyperstudio'], + 'stl' => ['application/vnd.ms-pki.stl', 'model/stl', 'model/x.stl-ascii', 'model/x.stl-binary'], + 'stm' => ['audio/x-stm'], + 'str' => ['application/vnd.pg.format'], + 'stw' => ['application/vnd.sun.xml.writer.template'], + 'sty' => ['application/x-tex', 'text/x-tex'], + 'sub' => ['image/vnd.dvb.subtitle', 'text/vnd.dvb.subtitle', 'text/x-microdvd', 'text/x-mpsub', 'text/x-subviewer'], + 'sun' => ['image/x-sun-raster'], + 'sus' => ['application/vnd.sus-calendar'], + 'susp' => ['application/vnd.sus-calendar'], + 'sv' => ['text/x-svsrc'], + 'sv4cpio' => ['application/x-sv4cpio'], + 'sv4crc' => ['application/x-sv4crc'], + 'svc' => ['application/vnd.dvb.service'], + 'svd' => ['application/vnd.svd'], + 'svg' => ['image/svg+xml'], + 'svgz' => ['image/svg+xml', 'image/svg+xml-compressed'], + 'svh' => ['text/x-svhdr'], + 'swa' => ['application/x-director'], + 'swap' => ['text/x-systemd-unit'], + 'swf' => ['application/futuresplash', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash'], + 'swi' => ['application/vnd.aristanetworks.swi'], + 'swm' => ['application/x-ms-wim'], + 'sxc' => ['application/vnd.sun.xml.calc'], + 'sxd' => ['application/vnd.sun.xml.draw'], + 'sxg' => ['application/vnd.sun.xml.writer.global'], + 'sxi' => ['application/vnd.sun.xml.impress'], + 'sxm' => ['application/vnd.sun.xml.math'], + 'sxw' => ['application/vnd.sun.xml.writer'], + 'sylk' => ['text/spreadsheet'], + 't' => ['application/x-perl', 'application/x-troff', 'text/troff', 'text/x-perl', 'text/x-troff'], + 't2t' => ['text/x-txt2tags'], + 't3' => ['application/x-t3vm-image'], + 'taglet' => ['application/vnd.mynfc'], + 'tao' => ['application/vnd.tao.intent-module-archive'], + 'tar' => ['application/x-tar', 'application/x-gtar'], + 'tar.Z' => ['application/x-tarz'], + 'tar.bz' => ['application/x-bzip-compressed-tar'], + 'tar.bz2' => ['application/x-bzip-compressed-tar'], + 'tar.gz' => ['application/x-compressed-tar'], + 'tar.lrz' => ['application/x-lrzip-compressed-tar'], + 'tar.lz' => ['application/x-lzip-compressed-tar'], + 'tar.lz4' => ['application/x-lz4-compressed-tar'], + 'tar.lzma' => ['application/x-lzma-compressed-tar'], + 'tar.lzo' => ['application/x-tzo'], + 'tar.xz' => ['application/x-xz-compressed-tar'], + 'target' => ['text/x-systemd-unit'], + 'taz' => ['application/x-tarz'], + 'tb2' => ['application/x-bzip-compressed-tar'], + 'tbz' => ['application/x-bzip-compressed-tar'], + 'tbz2' => ['application/x-bzip-compressed-tar'], + 'tcap' => ['application/vnd.3gpp2.tcap'], + 'tcl' => ['application/x-tcl', 'text/x-tcl'], + 'teacher' => ['application/vnd.smart.teacher'], + 'tei' => ['application/tei+xml'], + 'teicorpus' => ['application/tei+xml'], + 'tex' => ['application/x-tex', 'text/x-tex'], + 'texi' => ['application/x-texinfo', 'text/x-texinfo'], + 'texinfo' => ['application/x-texinfo', 'text/x-texinfo'], + 'text' => ['text/plain'], + 'tfi' => ['application/thraud+xml'], + 'tfm' => ['application/x-tex-tfm'], + 'tga' => ['image/x-icb', 'image/x-tga'], + 'tgz' => ['application/x-compressed-tar'], + 'theme' => ['application/x-theme'], + 'themepack' => ['application/x-windows-themepack'], + 'thmx' => ['application/vnd.ms-officetheme'], + 'tif' => ['image/tiff'], + 'tiff' => ['image/tiff'], + 'timer' => ['text/x-systemd-unit'], + 'tk' => ['text/x-tcl'], + 'tlrz' => ['application/x-lrzip-compressed-tar'], + 'tlz' => ['application/x-lzma-compressed-tar'], + 'tmo' => ['application/vnd.tmobile-livetv'], + 'tnef' => ['application/ms-tnef', 'application/vnd.ms-tnef'], + 'tnf' => ['application/ms-tnef', 'application/vnd.ms-tnef'], + 'toc' => ['application/x-cdrdao-toc'], + 'torrent' => ['application/x-bittorrent'], + 'tpic' => ['image/x-icb', 'image/x-tga'], + 'tpl' => ['application/vnd.groove-tool-template'], + 'tpt' => ['application/vnd.trid.tpt'], + 'tr' => ['application/x-troff', 'text/troff', 'text/x-troff'], + 'tra' => ['application/vnd.trueapp'], + 'trig' => ['application/trig', 'application/x-trig'], + 'trm' => ['application/x-msterminal'], + 'ts' => ['application/x-linguist', 'text/vnd.qt.linguist', 'text/vnd.trolltech.linguist', 'video/mp2t'], + 'tsd' => ['application/timestamped-data'], + 'tsv' => ['text/tab-separated-values'], + 'tta' => ['audio/tta', 'audio/x-tta'], + 'ttc' => ['font/collection'], + 'ttf' => ['application/x-font-truetype', 'application/x-font-ttf', 'font/ttf'], + 'ttl' => ['text/turtle'], + 'ttx' => ['application/x-font-ttx'], + 'twd' => ['application/vnd.simtech-mindmapper'], + 'twds' => ['application/vnd.simtech-mindmapper'], + 'twig' => ['text/x-twig'], + 'txd' => ['application/vnd.genomatix.tuxedo'], + 'txf' => ['application/vnd.mobius.txf'], + 'txt' => ['text/plain'], + 'txz' => ['application/x-xz-compressed-tar'], + 'tzo' => ['application/x-tzo'], + 'u32' => ['application/x-authorware-bin'], + 'udeb' => ['application/vnd.debian.binary-package', 'application/x-deb', 'application/x-debian-package'], + 'ufd' => ['application/vnd.ufdl'], + 'ufdl' => ['application/vnd.ufdl'], + 'ufraw' => ['application/x-ufraw'], + 'ui' => ['application/x-designer', 'application/x-gtk-builder'], + 'uil' => ['text/x-uil'], + 'ult' => ['audio/x-mod'], + 'ulx' => ['application/x-glulx'], + 'umj' => ['application/vnd.umajin'], + 'unf' => ['application/x-nes-rom'], + 'uni' => ['audio/x-mod'], + 'unif' => ['application/x-nes-rom'], + 'unityweb' => ['application/vnd.unity'], + 'uoml' => ['application/vnd.uoml+xml'], + 'uri' => ['text/uri-list'], + 'uris' => ['text/uri-list'], + 'url' => ['application/x-mswinurl'], + 'urls' => ['text/uri-list'], + 'ustar' => ['application/x-ustar'], + 'utz' => ['application/vnd.uiq.theme'], + 'uu' => ['text/x-uuencode'], + 'uue' => ['text/x-uuencode', 'zz-application/zz-winassoc-uu'], + 'uva' => ['audio/vnd.dece.audio'], + 'uvd' => ['application/vnd.dece.data'], + 'uvf' => ['application/vnd.dece.data'], + 'uvg' => ['image/vnd.dece.graphic'], + 'uvh' => ['video/vnd.dece.hd'], + 'uvi' => ['image/vnd.dece.graphic'], + 'uvm' => ['video/vnd.dece.mobile'], + 'uvp' => ['video/vnd.dece.pd'], + 'uvs' => ['video/vnd.dece.sd'], + 'uvt' => ['application/vnd.dece.ttml+xml'], + 'uvu' => ['video/vnd.uvvu.mp4'], + 'uvv' => ['video/vnd.dece.video'], + 'uvva' => ['audio/vnd.dece.audio'], + 'uvvd' => ['application/vnd.dece.data'], + 'uvvf' => ['application/vnd.dece.data'], + 'uvvg' => ['image/vnd.dece.graphic'], + 'uvvh' => ['video/vnd.dece.hd'], + 'uvvi' => ['image/vnd.dece.graphic'], + 'uvvm' => ['video/vnd.dece.mobile'], + 'uvvp' => ['video/vnd.dece.pd'], + 'uvvs' => ['video/vnd.dece.sd'], + 'uvvt' => ['application/vnd.dece.ttml+xml'], + 'uvvu' => ['video/vnd.uvvu.mp4'], + 'uvvv' => ['video/vnd.dece.video'], + 'uvvx' => ['application/vnd.dece.unspecified'], + 'uvvz' => ['application/vnd.dece.zip'], + 'uvx' => ['application/vnd.dece.unspecified'], + 'uvz' => ['application/vnd.dece.zip'], + 'v' => ['text/x-verilog'], + 'v64' => ['application/x-n64-rom'], + 'vala' => ['text/x-vala'], + 'vapi' => ['text/x-vala'], + 'vb' => ['application/x-virtual-boy-rom'], + 'vcard' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'vcd' => ['application/x-cdlink'], + 'vcf' => ['text/x-vcard', 'text/directory', 'text/vcard'], + 'vcg' => ['application/vnd.groove-vcard'], + 'vcs' => ['application/ics', 'text/calendar', 'text/x-vcalendar'], + 'vct' => ['text/directory', 'text/vcard', 'text/x-vcard'], + 'vcx' => ['application/vnd.vcx'], + 'vda' => ['image/x-icb', 'image/x-tga'], + 'vhd' => ['text/x-vhdl'], + 'vhdl' => ['text/x-vhdl'], + 'vis' => ['application/vnd.visionary'], + 'viv' => ['video/vivo', 'video/vnd.vivo'], + 'vivo' => ['video/vivo', 'video/vnd.vivo'], + 'vlc' => ['application/m3u', 'audio/m3u', 'audio/mpegurl', 'audio/x-m3u', 'audio/x-mp3-playlist', 'audio/x-mpegurl'], + 'vob' => ['video/mpeg', 'video/mpeg-system', 'video/x-mpeg', 'video/x-mpeg-system', 'video/x-mpeg2', 'video/x-ms-vob'], + 'voc' => ['audio/x-voc'], + 'vor' => ['application/vnd.stardivision.writer', 'application/vnd.stardivision.writer-global'], + 'vox' => ['application/x-authorware-bin'], + 'vrm' => ['model/vrml'], + 'vrml' => ['model/vrml'], + 'vsd' => ['application/vnd.visio'], + 'vsdm' => ['application/vnd.ms-visio.drawing.macroenabled.main+xml'], + 'vsdx' => ['application/vnd.ms-visio.drawing.main+xml'], + 'vsf' => ['application/vnd.vsf'], + 'vss' => ['application/vnd.visio'], + 'vssm' => ['application/vnd.ms-visio.stencil.macroenabled.main+xml'], + 'vssx' => ['application/vnd.ms-visio.stencil.main+xml'], + 'vst' => ['application/vnd.visio', 'image/x-icb', 'image/x-tga'], + 'vstm' => ['application/vnd.ms-visio.template.macroenabled.main+xml'], + 'vstx' => ['application/vnd.ms-visio.template.main+xml'], + 'vsw' => ['application/vnd.visio'], + 'vtt' => ['text/vtt'], + 'vtu' => ['model/vnd.vtu'], + 'vxml' => ['application/voicexml+xml'], + 'w3d' => ['application/x-director'], + 'wad' => ['application/x-doom', 'application/x-doom-wad', 'application/x-wii-wad'], + 'wav' => ['audio/wav', 'audio/vnd.wave', 'audio/x-wav'], + 'wax' => ['application/x-ms-asx', 'audio/x-ms-asx', 'audio/x-ms-wax', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wb1' => ['application/x-quattropro'], + 'wb2' => ['application/x-quattropro'], + 'wb3' => ['application/x-quattropro'], + 'wbmp' => ['image/vnd.wap.wbmp'], + 'wbs' => ['application/vnd.criticaltools.wbs+xml'], + 'wbxml' => ['application/vnd.wap.wbxml'], + 'wcm' => ['application/vnd.ms-works'], + 'wdb' => ['application/vnd.ms-works'], + 'wdp' => ['image/vnd.ms-photo'], + 'weba' => ['audio/webm'], + 'webm' => ['video/webm'], + 'webp' => ['image/webp'], + 'wg' => ['application/vnd.pmi.widget'], + 'wgt' => ['application/widget'], + 'wim' => ['application/x-ms-wim'], + 'wk1' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wk3' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wk4' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wkdownload' => ['application/x-partial-download'], + 'wks' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/vnd.ms-works', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + 'wm' => ['video/x-ms-wm'], + 'wma' => ['audio/x-ms-wma', 'audio/wma'], + 'wmd' => ['application/x-ms-wmd'], + 'wmf' => ['application/wmf', 'application/x-msmetafile', 'application/x-wmf', 'image/wmf', 'image/x-win-metafile', 'image/x-wmf'], + 'wml' => ['text/vnd.wap.wml'], + 'wmlc' => ['application/vnd.wap.wmlc'], + 'wmls' => ['text/vnd.wap.wmlscript'], + 'wmlsc' => ['application/vnd.wap.wmlscriptc'], + 'wmv' => ['audio/x-ms-wmv', 'video/x-ms-wmv'], + 'wmx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wmz' => ['application/x-ms-wmz', 'application/x-msmetafile'], + 'woff' => ['application/font-woff', 'application/x-font-woff', 'font/woff'], + 'woff2' => ['font/woff', 'font/woff2'], + 'wp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp4' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp5' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wp6' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wpd' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wpg' => ['application/x-wpg'], + 'wpl' => ['application/vnd.ms-wpl'], + 'wpp' => ['application/vnd.wordperfect', 'application/wordperfect', 'application/x-wordperfect'], + 'wps' => ['application/vnd.ms-works'], + 'wqd' => ['application/vnd.wqd'], + 'wri' => ['application/x-mswrite'], + 'wrl' => ['model/vrml'], + 'ws' => ['application/x-wonderswan-rom'], + 'wsc' => ['application/x-wonderswan-color-rom'], + 'wsdl' => ['application/wsdl+xml'], + 'wsgi' => ['text/x-python'], + 'wspolicy' => ['application/wspolicy+xml'], + 'wtb' => ['application/vnd.webturbo'], + 'wv' => ['audio/x-wavpack'], + 'wvc' => ['audio/x-wavpack-correction'], + 'wvp' => ['audio/x-wavpack'], + 'wvx' => ['application/x-ms-asx', 'audio/x-ms-asx', 'video/x-ms-wax', 'video/x-ms-wmx', 'video/x-ms-wvx'], + 'wwf' => ['application/wwf', 'application/x-wwf'], + 'x32' => ['application/x-authorware-bin'], + 'x3d' => ['model/x3d+xml'], + 'x3db' => ['model/x3d+binary'], + 'x3dbz' => ['model/x3d+binary'], + 'x3dv' => ['model/x3d+vrml'], + 'x3dvz' => ['model/x3d+vrml'], + 'x3dz' => ['model/x3d+xml'], + 'x3f' => ['image/x-sigma-x3f'], + 'xac' => ['application/x-gnucash'], + 'xaml' => ['application/xaml+xml'], + 'xap' => ['application/x-silverlight-app'], + 'xar' => ['application/vnd.xara', 'application/x-xar'], + 'xbap' => ['application/x-ms-xbap'], + 'xbd' => ['application/vnd.fujixerox.docuworks.binder'], + 'xbel' => ['application/x-xbel'], + 'xbl' => ['application/xml', 'text/xml'], + 'xbm' => ['image/x-xbitmap'], + 'xcf' => ['image/x-xcf'], + 'xcf.bz2' => ['image/x-compressed-xcf'], + 'xcf.gz' => ['image/x-compressed-xcf'], + 'xdf' => ['application/xcap-diff+xml'], + 'xdgapp' => ['application/vnd.flatpak', 'application/vnd.xdgapp'], + 'xdm' => ['application/vnd.syncml.dm+xml'], + 'xdp' => ['application/vnd.adobe.xdp+xml'], + 'xdssc' => ['application/dssc+xml'], + 'xdw' => ['application/vnd.fujixerox.docuworks'], + 'xenc' => ['application/xenc+xml'], + 'xer' => ['application/patch-ops-error+xml'], + 'xfdf' => ['application/vnd.adobe.xfdf'], + 'xfdl' => ['application/vnd.xfdl'], + 'xhe' => ['audio/usac'], + 'xht' => ['application/xhtml+xml'], + 'xhtml' => ['application/xhtml+xml'], + 'xhvml' => ['application/xv+xml'], + 'xi' => ['audio/x-xi'], + 'xif' => ['image/vnd.xiff'], + 'xla' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlam' => ['application/vnd.ms-excel.addin.macroenabled.12'], + 'xlc' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xld' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlf' => ['application/x-xliff', 'application/x-xliff+xml', 'application/xliff+xml'], + 'xliff' => ['application/x-xliff', 'application/xliff+xml'], + 'xll' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlm' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlr' => ['application/vnd.ms-works'], + 'xls' => ['application/vnd.ms-excel', 'application/msexcel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xlsb' => ['application/vnd.ms-excel.sheet.binary.macroenabled.12'], + 'xlsm' => ['application/vnd.ms-excel.sheet.macroenabled.12'], + 'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + 'xlt' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xltm' => ['application/vnd.ms-excel.template.macroenabled.12'], + 'xltx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.template'], + 'xlw' => ['application/msexcel', 'application/vnd.ms-excel', 'application/x-msexcel', 'zz-application/zz-winassoc-xls'], + 'xm' => ['audio/x-xm', 'audio/xm'], + 'xmf' => ['audio/mobile-xmf', 'audio/x-xmf', 'audio/xmf'], + 'xmi' => ['text/x-xmi'], + 'xml' => ['application/xml', 'text/xml'], + 'xo' => ['application/vnd.olpc-sugar'], + 'xop' => ['application/xop+xml'], + 'xpi' => ['application/x-xpinstall'], + 'xpl' => ['application/xproc+xml'], + 'xpm' => ['image/x-xpixmap', 'image/x-xpm'], + 'xpr' => ['application/vnd.is-xpr'], + 'xps' => ['application/oxps', 'application/vnd.ms-xpsdocument', 'application/xps'], + 'xpw' => ['application/vnd.intercon.formnet'], + 'xpx' => ['application/vnd.intercon.formnet'], + 'xsd' => ['application/xml', 'text/xml'], + 'xsl' => ['application/xml', 'application/xslt+xml'], + 'xslfo' => ['text/x-xslfo'], + 'xslt' => ['application/xslt+xml'], + 'xsm' => ['application/vnd.syncml+xml'], + 'xspf' => ['application/x-xspf+xml', 'application/xspf+xml'], + 'xul' => ['application/vnd.mozilla.xul+xml'], + 'xvm' => ['application/xv+xml'], + 'xvml' => ['application/xv+xml'], + 'xwd' => ['image/x-xwindowdump'], + 'xyz' => ['chemical/x-xyz'], + 'xz' => ['application/x-xz'], + 'yaml' => ['application/x-yaml', 'text/x-yaml', 'text/yaml'], + 'yang' => ['application/yang'], + 'yin' => ['application/yin+xml'], + 'yml' => ['application/x-yaml', 'text/x-yaml', 'text/yaml'], + 'yt' => ['application/vnd.youtube.yt'], + 'z1' => ['application/x-zmachine'], + 'z2' => ['application/x-zmachine'], + 'z3' => ['application/x-zmachine'], + 'z4' => ['application/x-zmachine'], + 'z5' => ['application/x-zmachine'], + 'z6' => ['application/x-zmachine'], + 'z64' => ['application/x-n64-rom'], + 'z7' => ['application/x-zmachine'], + 'z8' => ['application/x-zmachine'], + 'zabw' => ['application/x-abiword'], + 'zaz' => ['application/vnd.zzazz.deck+xml'], + 'zip' => ['application/zip', 'application/x-zip', 'application/x-zip-compressed'], + 'zir' => ['application/vnd.zul'], + 'zirz' => ['application/vnd.zul'], + 'zmm' => ['application/vnd.handheld-entertainment+xml'], + 'zoo' => ['application/x-zoo'], + 'zsav' => ['application/x-spss-sav', 'application/x-spss-savefile'], + 'zz' => ['application/zlib'], + '123' => ['application/lotus123', 'application/vnd.lotus-1-2-3', 'application/wk1', 'application/x-123', 'application/x-lotus123', 'zz-application/zz-winassoc-123'], + '602' => ['application/x-t602'], + '669' => ['audio/x-mod'], + ]; +} diff --git a/vendor/symfony/mime/MimeTypesInterface.php b/vendor/symfony/mime/MimeTypesInterface.php new file mode 100644 index 0000000000..bdf20429a1 --- /dev/null +++ b/vendor/symfony/mime/MimeTypesInterface.php @@ -0,0 +1,34 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +interface MimeTypesInterface extends MimeTypeGuesserInterface +{ + /** + * Gets the extensions for the given MIME type. + * + * @return string[] an array of extensions (first one is the preferred one) + */ + public function getExtensions(string $mimeType): array; + + /** + * Gets the MIME types for the given extension. + * + * @return string[] an array of MIME types (first one is the preferred one) + */ + public function getMimeTypes(string $ext): array; +} diff --git a/vendor/symfony/mime/NamedAddress.php b/vendor/symfony/mime/NamedAddress.php new file mode 100644 index 0000000000..0d58708a1c --- /dev/null +++ b/vendor/symfony/mime/NamedAddress.php @@ -0,0 +1,44 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class NamedAddress extends Address +{ + private $name; + + public function __construct(string $address, string $name) + { + parent::__construct($address); + + $this->name = $name; + } + + public function getName(): string + { + return $this->name; + } + + public function getEncodedNamedAddress(): string + { + return ($n = $this->getName()) ? $n.' <'.$this->getEncodedAddress().'>' : $this->getEncodedAddress(); + } + + public function toString(): string + { + return $this->getEncodedNamedAddress(); + } +} diff --git a/vendor/symfony/mime/Part/AbstractMultipartPart.php b/vendor/symfony/mime/Part/AbstractMultipartPart.php new file mode 100644 index 0000000000..34a94d25bc --- /dev/null +++ b/vendor/symfony/mime/Part/AbstractMultipartPart.php @@ -0,0 +1,87 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +abstract class AbstractMultipartPart extends AbstractPart +{ + private $boundary; + private $parts = []; + + public function __construct(AbstractPart ...$parts) + { + parent::__construct(); + + foreach ($parts as $part) { + $this->parts[] = $part; + } + } + + /** + * @return AbstractPart[] + */ + public function getParts(): array + { + return $this->parts; + } + + public function getMediaType(): string + { + return 'multipart'; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + $headers->setHeaderParameter('Content-Type', 'boundary', $this->getBoundary()); + + return $headers; + } + + public function bodyToString(): string + { + $parts = $this->getParts(); + $string = ''; + foreach ($parts as $part) { + $string .= '--'.$this->getBoundary()."\r\n".$part->toString()."\r\n"; + } + $string .= '--'.$this->getBoundary()."--\r\n"; + + return $string; + } + + public function bodyToIterable(): iterable + { + $parts = $this->getParts(); + foreach ($parts as $part) { + yield '--'.$this->getBoundary()."\r\n"; + yield from $part->toIterable(); + yield "\r\n"; + } + yield '--'.$this->getBoundary()."--\r\n"; + } + + private function getBoundary(): string + { + if (null === $this->boundary) { + $this->boundary = '_=_symfony_'.time().'_'.bin2hex(random_bytes(16)).'_=_'; + } + + return $this->boundary; + } +} diff --git a/vendor/symfony/mime/Part/AbstractPart.php b/vendor/symfony/mime/Part/AbstractPart.php new file mode 100644 index 0000000000..29eaa1ebfd --- /dev/null +++ b/vendor/symfony/mime/Part/AbstractPart.php @@ -0,0 +1,62 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +abstract class AbstractPart +{ + private $headers; + + public function __construct() + { + $this->headers = new Headers(); + } + + public function getHeaders(): Headers + { + return $this->headers; + } + + public function getPreparedHeaders(): Headers + { + $headers = clone $this->headers; + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + + return $headers; + } + + public function toString(): string + { + return $this->getPreparedHeaders()->toString()."\r\n".$this->bodyToString(); + } + + public function toIterable(): iterable + { + yield $this->getPreparedHeaders()->toString(); + yield "\r\n"; + yield from $this->bodyToIterable(); + } + + abstract public function bodyToString(): string; + + abstract public function bodyToIterable(): iterable; + + abstract public function getMediaType(): string; + + abstract public function getMediaSubtype(): string; +} diff --git a/vendor/symfony/mime/Part/DataPart.php b/vendor/symfony/mime/Part/DataPart.php new file mode 100644 index 0000000000..1cfb1e69b0 --- /dev/null +++ b/vendor/symfony/mime/Part/DataPart.php @@ -0,0 +1,150 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\MimeTypes; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class DataPart extends TextPart +{ + private static $mimeTypes; + + private $filename; + private $mediaType; + private $cid; + private $handle; + + /** + * @param resource|string $body + */ + public function __construct($body, string $filename = null, string $contentType = null, string $encoding = null) + { + if (null === $contentType) { + $contentType = 'application/octet-stream'; + } + list($this->mediaType, $subtype) = explode('/', $contentType); + + parent::__construct($body, null, $subtype, $encoding); + + $this->filename = $filename; + $this->setName($filename); + $this->setDisposition('attachment'); + } + + public static function fromPath(string $path, string $name = null, string $contentType = null): self + { + // FIXME: if file is not readable, exception? + + if (null === $contentType) { + $ext = strtolower(substr($path, strrpos($path, '.') + 1)); + if (null === self::$mimeTypes) { + self::$mimeTypes = new MimeTypes(); + } + $contentType = self::$mimeTypes->getMimeTypes($ext)[0] ?? 'application/octet-stream'; + } + + if (false === $handle = @fopen($path, 'r', false)) { + throw new InvalidArgumentException(sprintf('Unable to open path "%s"', $path)); + } + $p = new self($handle, $name ?: basename($path), $contentType); + $p->handle = $handle; + + return $p; + } + + /** + * @return $this + */ + public function asInline() + { + return $this->setDisposition('inline'); + } + + public function getContentId(): string + { + return $this->cid ?: $this->cid = $this->generateContentId(); + } + + public function hasContentId(): bool + { + return null !== $this->cid; + } + + public function getMediaType(): string + { + return $this->mediaType; + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + if (null !== $this->cid) { + $headers->setHeaderBody('Id', 'Content-ID', $this->cid); + } + + if (null !== $this->filename) { + $headers->setHeaderParameter('Content-Disposition', 'filename', $this->filename); + } + + return $headers; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + public function __destruct() + { + if (null !== $this->handle && \is_resource($this->handle)) { + fclose($this->handle); + } + } + + public function __sleep() + { + // converts the body to a string + parent::__sleep(); + + $this->_parent = []; + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setAccessible(true); + $this->_parent[$name] = $r->getValue($this); + } + $this->_headers = $this->getHeaders(); + + return ['_headers', '_parent', 'filename', 'mediaType']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + + foreach (['body', 'charset', 'subtype', 'disposition', 'name', 'encoding'] as $name) { + $r = new \ReflectionProperty(TextPart::class, $name); + $r->setAccessible(true); + $r->setValue($this, $this->_parent[$name]); + } + unset($this->_parent); + } +} diff --git a/vendor/symfony/mime/Part/MessagePart.php b/vendor/symfony/mime/Part/MessagePart.php new file mode 100644 index 0000000000..64a5340422 --- /dev/null +++ b/vendor/symfony/mime/Part/MessagePart.php @@ -0,0 +1,64 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\RawMessage; + +/** + * @final + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class MessagePart extends DataPart +{ + private $message; + + public function __construct(RawMessage $message) + { + if ($message instanceof Message) { + $name = $message->getHeaders()->getHeaderBody('Subject').'.eml'; + } else { + $name = 'email.eml'; + } + parent::__construct('', $name); + + $this->message = $message; + } + + public function getMediaType(): string + { + return 'message'; + } + + public function getMediaSubtype(): string + { + return 'rfc822'; + } + + public function getBody(): string + { + return $this->message->toString(); + } + + public function bodyToString(): string + { + return $this->getBody(); + } + + public function bodyToIterable(): iterable + { + return $this->message->toIterable(); + } +} diff --git a/vendor/symfony/mime/Part/Multipart/AlternativePart.php b/vendor/symfony/mime/Part/Multipart/AlternativePart.php new file mode 100644 index 0000000000..ad316a490a --- /dev/null +++ b/vendor/symfony/mime/Part/Multipart/AlternativePart.php @@ -0,0 +1,27 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class AlternativePart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'alternative'; + } +} diff --git a/vendor/symfony/mime/Part/Multipart/DigestPart.php b/vendor/symfony/mime/Part/Multipart/DigestPart.php new file mode 100644 index 0000000000..6199e5b8db --- /dev/null +++ b/vendor/symfony/mime/Part/Multipart/DigestPart.php @@ -0,0 +1,33 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\MessagePart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class DigestPart extends AbstractMultipartPart +{ + public function __construct(MessagePart ...$parts) + { + parent::__construct(...$parts); + } + + public function getMediaSubtype(): string + { + return 'digest'; + } +} diff --git a/vendor/symfony/mime/Part/Multipart/FormDataPart.php b/vendor/symfony/mime/Part/Multipart/FormDataPart.php new file mode 100644 index 0000000000..75d69a88a0 --- /dev/null +++ b/vendor/symfony/mime/Part/Multipart/FormDataPart.php @@ -0,0 +1,96 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\TextPart; + +/** + * Implements RFC 7578. + * + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class FormDataPart extends AbstractMultipartPart +{ + private $fields = []; + + /** + * @param (string|array|DataPart)[] $fields + */ + public function __construct(array $fields = []) + { + parent::__construct(); + + foreach ($fields as $name => $value) { + if (!\is_string($value) && !\is_array($value) && !$value instanceof TextPart) { + throw new InvalidArgumentException(sprintf('A form field value can only be a string, an array, or an instance of TextPart ("%s" given).', \is_object($value) ? \get_class($value) : \gettype($value))); + } + + $this->fields[$name] = $value; + } + // HTTP does not support \r\n in header values + $this->getHeaders()->setMaxLineLength(PHP_INT_MAX); + } + + public function getMediaSubtype(): string + { + return 'form-data'; + } + + public function getParts(): array + { + return $this->prepareFields($this->fields); + } + + private function prepareFields(array $fields): array + { + $values = []; + array_walk_recursive($fields, function ($item, $key) use (&$values) { + if (!\is_array($item)) { + $values[] = $this->preparePart($key, $item); + } + }); + + return $values; + } + + private function preparePart($name, $value): TextPart + { + if (\is_string($value)) { + return $this->configurePart($name, new TextPart($value, 'utf-8', 'plain', '8bit')); + } + + return $this->configurePart($name, $value); + } + + private function configurePart(string $name, TextPart $part): TextPart + { + static $r; + + if (null === $r) { + $r = new \ReflectionProperty(TextPart::class, 'encoding'); + $r->setAccessible(true); + } + + $part->setDisposition('form-data'); + $part->setName($name); + // HTTP does not support \r\n in header values + $part->getHeaders()->setMaxLineLength(PHP_INT_MAX); + $r->setValue($part, '8bit'); + + return $part; + } +} diff --git a/vendor/symfony/mime/Part/Multipart/MixedPart.php b/vendor/symfony/mime/Part/Multipart/MixedPart.php new file mode 100644 index 0000000000..eaa869fbee --- /dev/null +++ b/vendor/symfony/mime/Part/Multipart/MixedPart.php @@ -0,0 +1,27 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class MixedPart extends AbstractMultipartPart +{ + public function getMediaSubtype(): string + { + return 'mixed'; + } +} diff --git a/vendor/symfony/mime/Part/Multipart/RelatedPart.php b/vendor/symfony/mime/Part/Multipart/RelatedPart.php new file mode 100644 index 0000000000..2d5563073c --- /dev/null +++ b/vendor/symfony/mime/Part/Multipart/RelatedPart.php @@ -0,0 +1,57 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part\Multipart; + +use Symfony\Component\Mime\Part\AbstractMultipartPart; +use Symfony\Component\Mime\Part\AbstractPart; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +final class RelatedPart extends AbstractMultipartPart +{ + private $mainPart; + + public function __construct(AbstractPart $mainPart, AbstractPart $part, AbstractPart ...$parts) + { + $this->mainPart = $mainPart; + $this->prepareParts($part, ...$parts); + + parent::__construct($part, ...$parts); + } + + public function getParts(): array + { + return array_merge([$this->mainPart], parent::getParts()); + } + + public function getMediaSubtype(): string + { + return 'related'; + } + + private function generateContentId(): string + { + return bin2hex(random_bytes(16)).'@symfony'; + } + + private function prepareParts(AbstractPart ...$parts): void + { + foreach ($parts as $part) { + if (!$part->getHeaders()->has('Content-ID')) { + $part->getHeaders()->setHeaderBody('Id', 'Content-ID', $this->generateContentId()); + } + } + } +} diff --git a/vendor/symfony/mime/Part/TextPart.php b/vendor/symfony/mime/Part/TextPart.php new file mode 100644 index 0000000000..6a04185315 --- /dev/null +++ b/vendor/symfony/mime/Part/TextPart.php @@ -0,0 +1,190 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Part; + +use Symfony\Component\Mime\Encoder\Base64ContentEncoder; +use Symfony\Component\Mime\Encoder\ContentEncoderInterface; +use Symfony\Component\Mime\Encoder\EightBitContentEncoder; +use Symfony\Component\Mime\Encoder\QpContentEncoder; +use Symfony\Component\Mime\Exception\InvalidArgumentException; +use Symfony\Component\Mime\Header\Headers; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class TextPart extends AbstractPart +{ + private static $encoders = []; + + private $body; + private $charset; + private $subtype; + private $disposition; + private $name; + private $encoding; + + /** + * @param resource|string $body + */ + public function __construct($body, ?string $charset = 'utf-8', $subtype = 'plain', string $encoding = null) + { + parent::__construct(); + + if (!\is_string($body) && !\is_resource($body)) { + throw new \TypeError(sprintf('The body of "%s" must be a string or a resource (got "%s").', self::class, \is_object($body) ? \get_class($body) : \gettype($body))); + } + + $this->body = $body; + $this->charset = $charset; + $this->subtype = $subtype; + + if (null === $encoding) { + $this->encoding = $this->chooseEncoding(); + } else { + if ('quoted-printable' !== $encoding && 'base64' !== $encoding && '8bit' !== $encoding) { + throw new InvalidArgumentException(sprintf('The encoding must be one of "quoted-printable", "base64", or "8bit" ("%s" given).', $encoding)); + } + $this->encoding = $encoding; + } + } + + public function getMediaType(): string + { + return 'text'; + } + + public function getMediaSubtype(): string + { + return $this->subtype; + } + + /** + * @param string $disposition one of attachment, inline, or form-data + * + * @return $this + */ + public function setDisposition(string $disposition) + { + $this->disposition = $disposition; + + return $this; + } + + /** + * Sets the name of the file (used by FormDataPart). + * + * @return $this + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + public function getBody(): string + { + if (!\is_resource($this->body)) { + return $this->body; + } + + if (stream_get_meta_data($this->body)['seekable'] ?? false) { + rewind($this->body); + } + + return stream_get_contents($this->body) ?: ''; + } + + public function bodyToString(): string + { + return $this->getEncoder()->encodeString($this->getBody(), $this->charset); + } + + public function bodyToIterable(): iterable + { + if (\is_resource($this->body)) { + if (stream_get_meta_data($this->body)['seekable'] ?? false) { + rewind($this->body); + } + yield from $this->getEncoder()->encodeByteStream($this->body); + } else { + yield $this->getEncoder()->encodeString($this->body); + } + } + + public function getPreparedHeaders(): Headers + { + $headers = parent::getPreparedHeaders(); + + $headers->setHeaderBody('Parameterized', 'Content-Type', $this->getMediaType().'/'.$this->getMediaSubtype()); + if ($this->charset) { + $headers->setHeaderParameter('Content-Type', 'charset', $this->charset); + } + if ($this->name) { + $headers->setHeaderParameter('Content-Type', 'name', $this->name); + } + $headers->setHeaderBody('Text', 'Content-Transfer-Encoding', $this->encoding); + + if (!$headers->has('Content-Disposition') && null !== $this->disposition) { + $headers->setHeaderBody('Parameterized', 'Content-Disposition', $this->disposition); + if ($this->name) { + $headers->setHeaderParameter('Content-Disposition', 'name', $this->name); + } + } + + return $headers; + } + + private function getEncoder(): ContentEncoderInterface + { + if ('8bit' === $this->encoding) { + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new EightBitContentEncoder()); + } + + if ('quoted-printable' === $this->encoding) { + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new QpContentEncoder()); + } + + return self::$encoders[$this->encoding] ?? (self::$encoders[$this->encoding] = new Base64ContentEncoder()); + } + + private function chooseEncoding(): string + { + if (null === $this->charset) { + return 'base64'; + } + + return 'quoted-printable'; + } + + public function __sleep() + { + // convert resources to strings for serialization + if (\is_resource($this->body)) { + $this->body = $this->getBody(); + } + + $this->_headers = $this->getHeaders(); + + return ['_headers', 'body', 'charset', 'subtype', 'disposition', 'name', 'encoding']; + } + + public function __wakeup() + { + $r = new \ReflectionProperty(AbstractPart::class, 'headers'); + $r->setAccessible(true); + $r->setValue($this, $this->_headers); + unset($this->_headers); + } +} diff --git a/vendor/symfony/mime/README.md b/vendor/symfony/mime/README.md new file mode 100644 index 0000000000..32882461e2 --- /dev/null +++ b/vendor/symfony/mime/README.md @@ -0,0 +1,18 @@ +MIME Component +============== + +The MIME component allows manipulating MIME messages. + +**This Component is experimental**. +[Experimental features](https://symfony.com/doc/current/contributing/code/experimental.html) +are not covered by Symfony's +[Backward Compatibility Promise](https://symfony.com/doc/current/contributing/code/bc.html). + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/mime.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/mime/RawMessage.php b/vendor/symfony/mime/RawMessage.php new file mode 100644 index 0000000000..16b090c954 --- /dev/null +++ b/vendor/symfony/mime/RawMessage.php @@ -0,0 +1,87 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime; + +/** + * @author Fabien Potencier <fabien@symfony.com> + * + * @experimental in 4.3 + */ +class RawMessage implements \Serializable +{ + private $message; + + /** + * @param iterable|string $message + */ + public function __construct($message) + { + $this->message = $message; + } + + public function toString(): string + { + if (\is_string($this->message)) { + return $this->message; + } + + return $this->message = implode('', iterator_to_array($this->message, false)); + } + + public function toIterable(): iterable + { + if (\is_string($this->message)) { + yield $this->message; + + return; + } + + $message = ''; + foreach ($this->message as $chunk) { + $message .= $chunk; + yield $chunk; + } + $this->message = $message; + } + + /** + * @internal + */ + final public function serialize() + { + return serialize($this->__serialize()); + } + + /** + * @internal + */ + final public function unserialize($serialized) + { + $this->__unserialize(unserialize($serialized)); + } + + /** + * @internal + */ + public function __serialize(): array + { + return [$this->message]; + } + + /** + * @internal + */ + public function __unserialize(array $data): void + { + [$this->message] = $data; + } +} diff --git a/vendor/symfony/mime/Resources/bin/update_mime_types.php b/vendor/symfony/mime/Resources/bin/update_mime_types.php new file mode 100644 index 0000000000..0311d0d30a --- /dev/null +++ b/vendor/symfony/mime/Resources/bin/update_mime_types.php @@ -0,0 +1,170 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// load new map +$data = file_get_contents('https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types'); +$new = []; +foreach (explode("\n", $data) as $line) { + if (!$line || '#' == $line[0]) { + continue; + } + $mimeType = substr($line, 0, strpos($line, "\t")); + $extensions = explode(' ', substr($line, strrpos($line, "\t") + 1)); + $new[$mimeType] = $extensions; +} + +$xml = simplexml_load_string(file_get_contents('https://raw.github.com/minad/mimemagic/master/script/freedesktop.org.xml')); +foreach ($xml as $node) { + $exts = []; + foreach ($node->glob as $glob) { + $pattern = (string) $glob['pattern']; + if ('*' != $pattern[0] || '.' != $pattern[1]) { + continue; + } + + $exts[] = substr($pattern, 2); + } + + if (!$exts) { + continue; + } + + $mt = strtolower((string) $node['type']); + $new[$mt] = array_merge($new[$mt] ?? [], $exts); + foreach ($node->alias as $alias) { + $mt = strtolower((string) $alias['type']); + $new[$mt] = array_merge($new[$mt] ?? [], $exts); + } +} + +// load current map +$data = file_get_contents($output = __DIR__.'/../../MimeTypes.php'); +$current = []; +$pre = ''; +$post = ''; +foreach (explode("\n", $data) as $line) { + if (!preg_match("{^ '([^']+/[^']+)' => \['(.+)'\],$}", $line, $matches)) { + if (!$current) { + $pre .= $line."\n"; + } else { + $post .= $line."\n"; + } + continue; + } + $current[$matches[1]] = explode("', '", $matches[2]); +} + +// we merge the 2 maps (we never remove old mime types) +$map = array_replace_recursive($current, $new); +ksort($map); + +$data = $pre; +foreach ($map as $mimeType => $exts) { + $data .= sprintf(" '%s' => ['%s'],\n", $mimeType, implode("', '", array_unique($exts))); +} +$data .= $post; + +// reverse map +// we prefill the extensions with some preferences for content-types +$exts = [ + 'aif' => ['audio/x-aiff'], + 'aiff' => ['audio/x-aiff'], + 'aps' => ['application/postscript'], + 'avi' => ['video/avi'], + 'bmp' => ['image/bmp'], + 'bz2' => ['application/x-bz2'], + 'css' => ['text/css'], + 'csv' => ['text/csv'], + 'dmg' => ['application/x-apple-diskimage'], + 'doc' => ['application/msword'], + 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], + 'eml' => ['message/rfc822'], + 'exe' => ['application/x-ms-dos-executable'], + 'flv' => ['video/x-flv'], + 'gif' => ['image/gif'], + 'gz' => ['application/x-gzip'], + 'hqx' => ['application/stuffit'], + 'htm' => ['text/html'], + 'html' => ['text/html'], + 'jar' => ['application/x-java-archive'], + 'jpeg' => ['image/jpeg'], + 'jpg' => ['image/jpeg'], + 'js' => ['text/javascript'], + 'm3u' => ['audio/x-mpegurl'], + 'm4a' => ['audio/mp4'], + 'mdb' => ['application/x-msaccess'], + 'mid' => ['audio/midi'], + 'midi' => ['audio/midi'], + 'mov' => ['video/quicktime'], + 'mp3' => ['audio/mpeg'], + 'mp4' => ['video/mp4'], + 'mpeg' => ['video/mpeg'], + 'mpg' => ['video/mpeg'], + 'odg' => ['vnd.oasis.opendocument.graphics'], + 'odp' => ['vnd.oasis.opendocument.presentation'], + 'ods' => ['vnd.oasis.opendocument.spreadsheet'], + 'odt' => ['vnd.oasis.opendocument.text'], + 'ogg' => ['audio/ogg'], + 'pdf' => ['application/pdf'], + 'php' => ['application/x-php'], + 'php3' => ['application/x-php'], + 'php4' => ['application/x-php'], + 'php5' => ['application/x-php'], + 'png' => ['image/png'], + 'ppt' => ['application/vnd.ms-powerpoint'], + 'pptx' => ['application/vnd.openxmlformats-officedocument.presentationml.presentation'], + 'ps' => ['application/postscript'], + 'rar' => ['application/x-rar-compressed'], + 'rtf' => ['application/rtf'], + 'sit' => ['application/x-stuffit'], + 'svg' => ['image/svg+xml'], + 'tar' => ['application/x-tar'], + 'tif' => ['image/tiff'], + 'tiff' => ['image/tiff'], + 'ttf' => ['application/x-font-truetype'], + 'txt' => ['text/plain'], + 'vcf' => ['text/x-vcard'], + 'wav' => ['audio/wav'], + 'wma' => ['audio/x-ms-wma'], + 'wmv' => ['audio/x-ms-wmv'], + 'xls' => ['application/vnd.ms-excel'], + 'xlsx' => ['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + 'xml' => ['application/xml'], + 'zip' => ['application/zip'], +]; +foreach ($map as $mimeType => $extensions) { + foreach ($extensions as $extension) { + $exts[$extension][] = $mimeType; + } +} +ksort($exts); + +$updated = ''; +$state = 0; +foreach (explode("\n", $data) as $line) { + if (!preg_match("{^ '([^'/]+)' => \['(.+)'\],$}", $line, $matches)) { + if (1 === $state) { + $state = 2; + foreach ($exts as $ext => $mimeTypes) { + $updated .= sprintf(" '%s' => ['%s'],\n", $ext, implode("', '", array_unique($mimeTypes))); + } + } + $updated .= $line."\n"; + continue; + } + $state = 1; +} + +$updated = preg_replace('{Updated from upstream on .+?\.}', 'Updated from upstream on '.date('Y-m-d'), $updated, -1); + +file_put_contents($output, rtrim($updated, "\n")."\n"); + +echo "Done.\n"; diff --git a/vendor/symfony/mime/Tests/AbstractMimeTypeGuesserTest.php b/vendor/symfony/mime/Tests/AbstractMimeTypeGuesserTest.php new file mode 100644 index 0000000000..f9f5ec5703 --- /dev/null +++ b/vendor/symfony/mime/Tests/AbstractMimeTypeGuesserTest.php @@ -0,0 +1,102 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\MimeTypeGuesserInterface; + +abstract class AbstractMimeTypeGuesserTest extends TestCase +{ + public static function tearDownAfterClass() + { + $path = __DIR__.'/Fixtures/mimetypes/to_delete'; + if (file_exists($path)) { + @chmod($path, 0666); + @unlink($path); + } + } + + abstract protected function getGuesser(): MimeTypeGuesserInterface; + + public function testGuessImageWithoutExtension() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/test')); + } + + public function testGuessImageWithDirectory() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + $this->expectException('\InvalidArgumentException'); + $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/directory'); + } + + public function testGuessImageWithKnownExtension() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + $this->assertEquals('image/gif', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/test.gif')); + } + + public function testGuessFileWithUnknownExtension() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + $this->assertEquals('application/octet-stream', $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/.unknownextension')); + } + + public function testGuessWithIncorrectPath() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + $this->expectException('\InvalidArgumentException'); + $this->getGuesser()->guessMimeType(__DIR__.'/Fixtures/mimetypes/not_here'); + } + + public function testGuessWithNonReadablePath() + { + if (!$this->getGuesser()->isGuesserSupported()) { + $this->markTestSkipped('Guesser is not supported'); + } + + 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/mimetypes/to_delete'; + touch($path); + @chmod($path, 0333); + + if ('0333' == substr(sprintf('%o', fileperms($path)), -4)) { + $this->expectException('\InvalidArgumentException'); + $this->getGuesser()->guessMimeType($path); + } else { + $this->markTestSkipped('Can not verify chmod operations, change of file permissions failed'); + } + } +} diff --git a/vendor/symfony/mime/Tests/AddressTest.php b/vendor/symfony/mime/Tests/AddressTest.php new file mode 100644 index 0000000000..dd7d3cebf6 --- /dev/null +++ b/vendor/symfony/mime/Tests/AddressTest.php @@ -0,0 +1,61 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\NamedAddress; + +class AddressTest extends TestCase +{ + public function testConstructor() + { + $a = new Address('fabien@symfonï.com'); + $this->assertEquals('fabien@symfonï.com', $a->getAddress()); + $this->assertEquals('fabien@xn--symfon-nwa.com', $a->toString()); + $this->assertEquals('fabien@xn--symfon-nwa.com', $a->getEncodedAddress()); + } + + public function testConstructorWithInvalidAddress() + { + $this->expectException(\InvalidArgumentException::class); + new Address('fab pot@symfony.com'); + } + + public function testCreate() + { + $this->assertSame($a = new Address('fabien@symfony.com'), Address::create($a)); + $this->assertSame($b = new NamedAddress('helene@symfony.com', 'Helene'), Address::create($b)); + $this->assertEquals($a, Address::create('fabien@symfony.com')); + } + + public function testCreateWrongArg() + { + $this->expectException(\InvalidArgumentException::class); + Address::create(new \stdClass()); + } + + public function testCreateArray() + { + $fabien = new Address('fabien@symfony.com'); + $helene = new NamedAddress('helene@symfony.com', 'Helene'); + $this->assertSame([$fabien, $helene], Address::createArray([$fabien, $helene])); + + $this->assertEquals([$fabien], Address::createArray(['fabien@symfony.com'])); + } + + public function testCreateArrayWrongArg() + { + $this->expectException(\InvalidArgumentException::class); + Address::createArray([new \stdClass()]); + } +} diff --git a/vendor/symfony/mime/Tests/CharacterStreamTest.php b/vendor/symfony/mime/Tests/CharacterStreamTest.php new file mode 100644 index 0000000000..62f4dc6fe8 --- /dev/null +++ b/vendor/symfony/mime/Tests/CharacterStreamTest.php @@ -0,0 +1,87 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\CharacterStream; + +class CharacterStreamTest extends TestCase +{ + public function testReadCharactersAreInTact() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + )); + $this->assertSame(pack('C*', 0xD0, 0x94), $stream->read(1)); + $this->assertSame(pack('C*', 0xD0, 0xB6, 0xD0, 0xBE), $stream->read(2)); + $this->assertSame(pack('C*', 0xD0, 0xBB), $stream->read(1)); + $this->assertSame(pack('C*', 0xD1, 0x8E, 0xD0, 0xB1, 0xD1, 0x8B), $stream->read(3)); + $this->assertSame(pack('C*', 0xD1, 0x85), $stream->read(1)); + $this->assertNull($stream->read(1)); + } + + public function testCharactersCanBeReadAsByteArrays() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $stream->write(pack('C*', + 0xD0, 0xBB, + 0xD1, 0x8E, + 0xD0, 0xB1, + 0xD1, 0x8B, + 0xD1, 0x85 + )); + $this->assertEquals([0xD0, 0x94], $stream->readBytes(1)); + $this->assertEquals([0xD0, 0xB6, 0xD0, 0xBE], $stream->readBytes(2)); + $this->assertEquals([0xD0, 0xBB], $stream->readBytes(1)); + $this->assertEquals([0xD1, 0x8E, 0xD0, 0xB1, 0xD1, 0x8B], $stream->readBytes(3)); + $this->assertEquals([0xD1, 0x85], $stream->readBytes(1)); + $this->assertNull($stream->readBytes(1)); + } + + public function testRequestingLargeCharCountPastEndOfStream() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $this->assertSame(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE), $stream->read(100)); + $this->assertNull($stream->read(1)); + } + + public function testRequestingByteArrayCountPastEndOfStream() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $this->assertEquals([0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE], $stream->readBytes(100)); + $this->assertNull($stream->readBytes(1)); + } + + public function testPointerOffsetCanBeSet() + { + $stream = new CharacterStream(pack('C*', 0xD0, 0x94, 0xD0, 0xB6, 0xD0, 0xBE)); + $this->assertSame(pack('C*', 0xD0, 0x94), $stream->read(1)); + $stream->setPointer(0); + $this->assertSame(pack('C*', 0xD0, 0x94), $stream->read(1)); + $stream->setPointer(2); + $this->assertSame(pack('C*', 0xD0, 0xBE), $stream->read(1)); + } + + public function testAlgorithmWithFixedWidthCharsets() + { + $stream = new CharacterStream(pack('C*', 0xD1, 0x8D, 0xD0, 0xBB, 0xD0, 0xB0)); + $this->assertSame(pack('C*', 0xD1, 0x8D), $stream->read(1)); + $this->assertSame(pack('C*', 0xD0, 0xBB), $stream->read(1)); + $this->assertSame(pack('C*', 0xD0, 0xB0), $stream->read(1)); + $this->assertNull($stream->read(1)); + } +} diff --git a/vendor/symfony/mime/Tests/DependencyInjection/AddMimeTypeGuesserPassTest.php b/vendor/symfony/mime/Tests/DependencyInjection/AddMimeTypeGuesserPassTest.php new file mode 100644 index 0000000000..cf40a4675f --- /dev/null +++ b/vendor/symfony/mime/Tests/DependencyInjection/AddMimeTypeGuesserPassTest.php @@ -0,0 +1,42 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\Mime\DependencyInjection\AddMimeTypeGuesserPass; +use Symfony\Component\Mime\FileinfoMimeTypeGuesser; +use Symfony\Component\Mime\MimeTypes; + +class AddMimeTypeGuesserPassTest extends TestCase +{ + public function testTags() + { + $container = new ContainerBuilder(); + $container->addCompilerPass(new AddMimeTypeGuesserPass()); + + $definition = new Definition(FileinfoMimeTypeGuesser::class); + $definition->addArgument('/path/to/magic/file'); + $definition->addTag('mime.mime_type_guesser'); + $container->setDefinition('some_mime_type_guesser', $definition->setPublic(true)); + $container->register('mime_types', MimeTypes::class)->setPublic(true); + $container->compile(); + + $router = $container->getDefinition('mime_types'); + $calls = $router->getMethodCalls(); + $this->assertCount(1, $calls); + $this->assertEquals('registerGuesser', $calls[0][0]); + $this->assertEquals(new Reference('some_mime_type_guesser'), $calls[0][1][0]); + } +} diff --git a/vendor/symfony/mime/Tests/EmailTest.php b/vendor/symfony/mime/Tests/EmailTest.php new file mode 100644 index 0000000000..1d45cab9f4 --- /dev/null +++ b/vendor/symfony/mime/Tests/EmailTest.php @@ -0,0 +1,385 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\NamedAddress; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; +use Symfony\Component\Mime\Part\Multipart\MixedPart; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +class EmailTest extends TestCase +{ + public function testSubject() + { + $e = new Email(); + $e->subject('Subject'); + $this->assertEquals('Subject', $e->getSubject()); + } + + public function testDate() + { + $e = new Email(); + $e->date($d = new \DateTimeImmutable()); + $this->assertSame($d, $e->getDate()); + } + + public function testReturnPath() + { + $e = new Email(); + $e->returnPath('fabien@symfony.com'); + $this->assertEquals(new Address('fabien@symfony.com'), $e->getReturnPath()); + } + + public function testSender() + { + $e = new Email(); + $e->sender('fabien@symfony.com'); + $this->assertEquals(new Address('fabien@symfony.com'), $e->getSender()); + + $e->sender($fabien = new Address('fabien@symfony.com')); + $this->assertSame($fabien, $e->getSender()); + } + + public function testFrom() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->from('fabien@symfony.com', $helene, $thomas)); + $v = $e->getFrom(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addFrom('lucas@symfony.com', $caramel)); + $v = $e->getFrom(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addFrom('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getFrom()); + + $e = new Email(); + $e->from('lucas@symfony.com'); + $e->from($caramel); + $this->assertSame([$caramel], $e->getFrom()); + } + + public function testReplyTo() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->replyTo('fabien@symfony.com', $helene, $thomas)); + $v = $e->getReplyTo(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addReplyTo('lucas@symfony.com', $caramel)); + $v = $e->getReplyTo(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addReplyTo('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getReplyTo()); + + $e = new Email(); + $e->replyTo('lucas@symfony.com'); + $e->replyTo($caramel); + $this->assertSame([$caramel], $e->getReplyTo()); + } + + public function testTo() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->to('fabien@symfony.com', $helene, $thomas)); + $v = $e->getTo(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addTo('lucas@symfony.com', $caramel)); + $v = $e->getTo(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addTo('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getTo()); + + $e = new Email(); + $e->to('lucas@symfony.com'); + $e->to($caramel); + $this->assertSame([$caramel], $e->getTo()); + } + + public function testCc() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->cc('fabien@symfony.com', $helene, $thomas)); + $v = $e->getCc(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addCc('lucas@symfony.com', $caramel)); + $v = $e->getCc(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addCc('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getCc()); + + $e = new Email(); + $e->cc('lucas@symfony.com'); + $e->cc($caramel); + $this->assertSame([$caramel], $e->getCc()); + } + + public function testBcc() + { + $e = new Email(); + $helene = new Address('helene@symfony.com'); + $thomas = new NamedAddress('thomas@symfony.com', 'Thomas'); + $caramel = new Address('caramel@symfony.com'); + + $this->assertSame($e, $e->bcc('fabien@symfony.com', $helene, $thomas)); + $v = $e->getBcc(); + $this->assertCount(3, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + + $this->assertSame($e, $e->addBcc('lucas@symfony.com', $caramel)); + $v = $e->getBcc(); + $this->assertCount(5, $v); + $this->assertEquals(new Address('fabien@symfony.com'), $v[0]); + $this->assertSame($helene, $v[1]); + $this->assertSame($thomas, $v[2]); + $this->assertEquals(new Address('lucas@symfony.com'), $v[3]); + $this->assertSame($caramel, $v[4]); + + $e = new Email(); + $e->addBcc('lucas@symfony.com', $caramel); + $this->assertCount(2, $e->getBcc()); + + $e = new Email(); + $e->bcc('lucas@symfony.com'); + $e->bcc($caramel); + $this->assertSame([$caramel], $e->getBcc()); + } + + public function testPriority() + { + $e = new Email(); + $this->assertEquals(3, $e->getPriority()); + + $e->priority(1); + $this->assertEquals(1, $e->getPriority()); + $e->priority(10); + $this->assertEquals(5, $e->getPriority()); + $e->priority(-10); + $this->assertEquals(1, $e->getPriority()); + } + + public function testGenerateBodyThrowsWhenEmptyBody() + { + $this->expectException(\LogicException::class); + (new Email())->getBody(); + } + + public function testGetBody() + { + $e = new Email(); + $e->setBody($text = new TextPart('text content')); + $this->assertEquals($text, $e->getBody()); + } + + public function testGenerateBody() + { + $text = new TextPart('text content'); + $html = new TextPart('html content', 'utf-8', 'html'); + $att = new DataPart($file = fopen(__DIR__.'/Fixtures/mimetypes/test', 'r')); + $img = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r'), 'test.gif'); + + $e = new Email(); + $e->text('text content'); + $this->assertEquals($text, $e->getBody()); + $this->assertEquals('text content', $e->getTextBody()); + + $e = new Email(); + $e->html('html content'); + $this->assertEquals($html, $e->getBody()); + $this->assertEquals('html content', $e->getHtmlBody()); + + $e = new Email(); + $e->html('html content'); + $e->text('text content'); + $this->assertEquals(new AlternativePart($text, $html), $e->getBody()); + + $e = new Email(); + $e->html('html content', 'iso-8859-1'); + $e->text('text content', 'iso-8859-1'); + $this->assertEquals('iso-8859-1', $e->getTextCharset()); + $this->assertEquals('iso-8859-1', $e->getHtmlCharset()); + $this->assertEquals(new AlternativePart(new TextPart('text content', 'iso-8859-1'), new TextPart('html content', 'iso-8859-1', 'html')), $e->getBody()); + + $e = new Email(); + $e->attach($file); + $e->text('text content'); + $this->assertEquals(new MixedPart($text, $att), $e->getBody()); + + $e = new Email(); + $e->attach($file); + $e->html('html content'); + $this->assertEquals(new MixedPart($html, $att), $e->getBody()); + + $e = new Email(); + $e->html('html content'); + $e->text('text content'); + $e->attach($file); + $this->assertEquals(new MixedPart(new AlternativePart($text, $html), $att), $e->getBody()); + + $e = new Email(); + $e->html('html content'); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $this->assertEquals(new MixedPart(new AlternativePart($text, $html), $att, $img), $e->getBody()); + + $e = new Email(); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $this->assertEquals(new MixedPart($text, $att, $img), $e->getBody()); + + $e = new Email(); + $e->html($content = 'html content <img src="test.gif">'); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $fullhtml = new TextPart($content, 'utf-8', 'html'); + $this->assertEquals(new MixedPart(new AlternativePart($text, $fullhtml), $att, $img), $e->getBody()); + + $e = new Email(); + $e->html($content = 'html content <img src="cid:test.gif">'); + $e->text('text content'); + $e->attach($file); + $e->attach($image, 'test.gif'); + $fullhtml = new TextPart($content, 'utf-8', 'html'); + $inlinedimg = (new DataPart($image, 'test.gif'))->asInline(); + $body = $e->getBody(); + $this->assertInstanceOf(MixedPart::class, $body); + $this->assertCount(2, $related = $body->getParts()); + $this->assertInstanceOf(RelatedPart::class, $related[0]); + $this->assertEquals($att, $related[1]); + $this->assertCount(2, $parts = $related[0]->getParts()); + $this->assertInstanceOf(AlternativePart::class, $parts[0]); + $generatedHtml = $parts[0]->getParts()[1]; + $this->assertContains('cid:'.$parts[1]->getContentId(), $generatedHtml->getBody()); + + $content = 'html content <img src="cid:test.gif">'; + $r = fopen('php://memory', 'r+', false); + fwrite($r, $content); + rewind($r); + + $e = new Email(); + $e->html($r); + // embedding the same image twice results in one image only in the email + $e->embed($image, 'test.gif'); + $e->embed($image, 'test.gif'); + $body = $e->getBody(); + $this->assertInstanceOf(RelatedPart::class, $body); + // 2 parts only, not 3 (text + embedded image once) + $this->assertCount(2, $parts = $body->getParts()); + $this->assertStringMatchesFormat('html content <img src=3D"cid:%s@symfony">', $parts[0]->bodyToString()); + } + + public function testAttachments() + { + $contents = file_get_contents($name = __DIR__.'/Fixtures/mimetypes/test', 'r'); + $att = new DataPart($file = fopen($name, 'r'), 'test'); + $inline = (new DataPart($contents, 'test'))->asInline(); + $e = new Email(); + $e->attach($file, 'test'); + $e->embed($contents, 'test'); + $this->assertEquals([$att, $inline], $e->getAttachments()); + + $att = DataPart::fromPath($name, 'test'); + $inline = DataPart::fromPath($name, 'test')->asInline(); + $e = new Email(); + $e->attachFromPath($name); + $e->embedFromPath($name); + $this->assertEquals([$att->bodyToString(), $inline->bodyToString()], array_map(function (DataPart $a) { return $a->bodyToString(); }, $e->getAttachments())); + $this->assertEquals([$att->getPreparedHeaders(), $inline->getPreparedHeaders()], array_map(function (DataPart $a) { return $a->getPreparedHeaders(); }, $e->getAttachments())); + } + + public function testSerialize() + { + $r = fopen('php://memory', 'r+', false); + fwrite($r, 'Text content'); + rewind($r); + + $e = new Email(); + $e->from('fabien@symfony.com'); + $e->text($r); + $e->html($r); + $contents = file_get_contents($name = __DIR__.'/Fixtures/mimetypes/test', 'r'); + $file = fopen($name, 'r'); + $e->attach($file, 'test'); + $expected = clone $e; + $n = unserialize(serialize($e)); + $this->assertEquals($expected->getHeaders(), $n->getHeaders()); + $this->assertEquals($e->getBody(), $n->getBody()); + } +} diff --git a/vendor/symfony/mime/Tests/Encoder/Base64EncoderTest.php b/vendor/symfony/mime/Tests/Encoder/Base64EncoderTest.php new file mode 100644 index 0000000000..a90fbb70fc --- /dev/null +++ b/vendor/symfony/mime/Tests/Encoder/Base64EncoderTest.php @@ -0,0 +1,158 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\Base64Encoder; + +class Base64EncoderTest extends TestCase +{ + /* + There's really no point in testing the entire base64 encoding to the + level QP encoding has been tested. base64_encode() has been in PHP for + years. + */ + + public function testInputOutputRatioIs3to4Bytes() + { + /* + RFC 2045, 6.8 + + The encoding process represents 24-bit groups of input bits as output + strings of 4 encoded characters. Proceeding from left to right, a + 24-bit input group is formed by concatenating 3 8bit input groups. + These 24 bits are then treated as 4 concatenated 6-bit groups, each + of which is translated into a single digit in the base64 alphabet. + */ + + $encoder = new Base64Encoder(); + $this->assertEquals('MTIz', $encoder->encodeString('123'), '3 bytes of input should yield 4 bytes of output'); + $this->assertEquals('MTIzNDU2', $encoder->encodeString('123456'), '6 bytes in input should yield 8 bytes of output'); + $this->assertEquals('MTIzNDU2Nzg5', $encoder->encodeString('123456789'), '%s: 9 bytes in input should yield 12 bytes of output'); + } + + public function testPadLength() + { + /* + RFC 2045, 6.8 + + Special processing is performed if fewer than 24 bits are available + at the end of the data being encoded. A full encoding quantum is + always completed at the end of a body. When fewer than 24 input bits + are available in an input group, zero bits are added (on the right) + to form an integral number of 6-bit groups. Padding at the end of + the data is performed using the "=" character. Since all base64 + input is an integral number of octets, only the following cases can + arise: (1) the final quantum of encoding input is an integral + multiple of 24 bits; here, the final unit of encoded output will be + an integral multiple of 4 characters with no "=" padding, (2) the + final quantum of encoding input is exactly 8 bits; here, the final + unit of encoded output will be two characters followed by two "=" + padding characters, or (3) the final quantum of encoding input is + exactly 16 bits; here, the final unit of encoded output will be three + characters followed by one "=" padding character. + */ + + $encoder = new Base64Encoder(); + for ($i = 0; $i < 30; ++$i) { + $input = pack('C', random_int(0, 255)); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{2}==$~', $encoder->encodeString($input), 'A single byte should have 2 bytes of padding'); + } + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C*', random_int(0, 255), random_int(0, 255)); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{3}=$~', $encoder->encodeString($input), 'Two bytes should have 1 byte of padding'); + } + + for ($i = 0; $i < 30; ++$i) { + $input = pack('C*', random_int(0, 255), random_int(0, 255), random_int(0, 255)); + $this->assertRegExp('~^[a-zA-Z0-9/\+]{4}$~', $encoder->encodeString($input), 'Three bytes should have no padding'); + } + } + + public function testMaximumLineLengthIs76Characters() + { + /* + The encoded output stream must be represented in lines of no more + than 76 characters each. All line breaks or other characters not + found in Table 1 must be ignored by decoding software. + */ + + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0xNTk9QUVJTVFVWV1hZWjEyMzQ1'."\r\n".//76 * + 'Njc4OTBhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3'.//38 + 'h5ekFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla'."\r\n".//76 * + 'MTIzNDU2Nzg5MEFCQ0RFRkdISUpLTE1OT1BRUl'.//38 + 'NUVVZXWFla'; //48 + + $encoder = new Base64Encoder(); + $this->assertEquals($output, $encoder->encodeString($input), 'Lines should be no more than 76 characters'); + } + + public function testMaximumLineLengthCanBeSpecified() + { + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0'."\r\n".//50 * + 'xNTk9QUVJTVFVWV1hZWjEyMzQ1Njc4OTBhYmNk'.//38 + 'ZWZnaGlqa2xt'."\r\n".//50 * + 'bm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLTE1OT1'.//38 + 'BRUlNUVVZXWF'."\r\n".//50 * + 'laMTIzNDU2Nzg5MEFCQ0RFRkdISUpLTE1OT1BR'.//38 + 'UlNUVVZXWFla'; //50 * + + $encoder = new Base64Encoder(); + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 0, 50), 'Lines should be no more than 100 characters'); + } + + public function testFirstLineLengthCanBeDifferent() + { + $input = + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + '1234567890'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + + $output = + 'YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQk'.//38 + 'NERUZHSElKS0xNTk9QU'."\r\n".//57 * + 'VJTVFVWV1hZWjEyMzQ1Njc4OTBhYmNkZWZnaGl'.//38 + 'qa2xtbm9wcXJzdHV2d3h5ekFCQ0RFRkdISUpLT'."\r\n".//76 * + 'E1OT1BRUlNUVVZXWFlaMTIzNDU2Nzg5MEFCQ0R'.//38 + 'FRkdISUpLTE1OT1BRUlNUVVZXWFla'; //67 + + $encoder = new Base64Encoder(); + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 19), 'First line offset is 19 so first line should be 57 chars long'); + } +} diff --git a/vendor/symfony/mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php b/vendor/symfony/mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php new file mode 100644 index 0000000000..34bfe0d47c --- /dev/null +++ b/vendor/symfony/mime/Tests/Encoder/Base64MimeHeaderEncoderTest.php @@ -0,0 +1,23 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\Base64MimeHeaderEncoder; + +class Base64MimeHeaderEncoderTest extends TestCase +{ + public function testNameIsB() + { + $this->assertEquals('B', (new Base64MimeHeaderEncoder())->getName()); + } +} diff --git a/vendor/symfony/mime/Tests/Encoder/QpEncoderTest.php b/vendor/symfony/mime/Tests/Encoder/QpEncoderTest.php new file mode 100644 index 0000000000..bf08b2f095 --- /dev/null +++ b/vendor/symfony/mime/Tests/Encoder/QpEncoderTest.php @@ -0,0 +1,213 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\QpEncoder; + +class QpEncoderTest extends TestCase +{ + /* -- RFC 2045, 6.7 -- + (1) (General 8bit representation) Any octet, except a CR or + LF that is part of a CRLF line break of the canonical + (standard) form of the data being encoded, may be + represented by an "=" followed by a two digit + hexadecimal representation of the octet's value. The + digits of the hexadecimal alphabet, for this purpose, + are "0123456789ABCDEF". Uppercase letters must be + used; lowercase letters are not allowed. Thus, for + example, the decimal value 12 (US-ASCII form feed) can + be represented by "=0C", and the decimal value 61 (US- + ASCII EQUAL SIGN) can be represented by "=3D". This + rule must be followed except when the following rules + allow an alternative encoding. + */ + + public function testPermittedCharactersAreNotEncoded() + { + /* -- RFC 2045, 6.7 -- + (2) (Literal representation) Octets with decimal values of + 33 through 60 inclusive, and 62 through 126, inclusive, + MAY be represented as the US-ASCII characters which + correspond to those octets (EXCLAMATION POINT through + LESS THAN, and GREATER THAN through TILDE, + respectively). + */ + + $encoder = new QpEncoder(); + foreach (array_merge(range(33, 60), range(62, 126)) as $ordinal) { + $char = \chr($ordinal); + $this->assertSame($char, $encoder->encodeString($char)); + } + } + + public function testWhiteSpaceAtLineEndingIsEncoded() + { + /* -- RFC 2045, 6.7 -- + (3) (White Space) Octets with values of 9 and 32 MAY be + represented as US-ASCII TAB (HT) and SPACE characters, + respectively, but MUST NOT be so represented at the end + of an encoded line. Any TAB (HT) or SPACE characters + on an encoded line MUST thus be followed on that line + by a printable character. In particular, an "=" at the + end of an encoded line, indicating a soft line break + (see rule #5) may follow one or more TAB (HT) or SPACE + characters. It follows that an octet with decimal + value 9 or 32 appearing at the end of an encoded line + must be represented according to Rule #1. This rule is + necessary because some MTAs (Message Transport Agents, + programs which transport messages from one user to + another, or perform a portion of such transfers) are + known to pad lines of text with SPACEs, and others are + known to remove "white space" characters from the end + of a line. Therefore, when decoding a Quoted-Printable + body, any trailing white space on a line must be + deleted, as it will necessarily have been added by + intermediate transport agents. + */ + + $encoder = new QpEncoder(); + + $HT = \chr(0x09); // 9 + $SPACE = \chr(0x20); // 32 + + // HT + $string = 'a'.$HT.$HT."\r\n".'b'; + $this->assertEquals('a'.$HT.'=09'."\r\n".'b', $encoder->encodeString($string)); + + // SPACE + $string = 'a'.$SPACE.$SPACE."\r\n".'b'; + $this->assertEquals('a'.$SPACE.'=20'."\r\n".'b', $encoder->encodeString($string)); + } + + public function testCRLFIsLeftAlone() + { + /* + (4) (Line Breaks) A line break in a text body, represented + as a CRLF sequence in the text canonical form, must be + represented by a (RFC 822) line break, which is also a + CRLF sequence, in the Quoted-Printable encoding. Since + the canonical representation of media types other than + text do not generally include the representation of + line breaks as CRLF sequences, no hard line breaks + (i.e. line breaks that are intended to be meaningful + and to be displayed to the user) can occur in the + quoted-printable encoding of such types. Sequences + like "=0D", "=0A", "=0A=0D" and "=0D=0A" will routinely + appear in non-text data represented in quoted- + printable, of course. + + Note that many implementations may elect to encode the + local representation of various content types directly + rather than converting to canonical form first, + encoding, and then converting back to local + representation. In particular, this may apply to plain + text material on systems that use newline conventions + other than a CRLF terminator sequence. Such an + implementation optimization is permissible, but only + when the combined canonicalization-encoding step is + equivalent to performing the three steps separately. + */ + + $encoder = new QpEncoder(); + $string = 'a'."\r\n".'b'."\r\n".'c'."\r\n"; + $this->assertEquals($string, $encoder->encodeString($string)); + } + + public function testLinesLongerThan76CharactersAreSoftBroken() + { + /* + (5) (Soft Line Breaks) The Quoted-Printable encoding + REQUIRES that encoded lines be no more than 76 + characters long. If longer lines are to be encoded + with the Quoted-Printable encoding, "soft" line breaks + must be used. An equal sign as the last character on a + encoded line indicates such a non-significant ("soft") + line break in the encoded text. + */ + + $encoder = new QpEncoder(); + $input = str_repeat('a', 140); + $output = ''; + for ($i = 0; $i < 140; ++$i) { + // we read 4 chars at a time (max is 75) + if (18 * 4 /* 72 */ == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $this->assertEquals($output, $encoder->encodeString($input)); + } + + public function testMaxLineLengthCanBeSpecified() + { + $encoder = new QpEncoder(); + $input = str_repeat('a', 100); + $output = ''; + for ($i = 0; $i < 100; ++$i) { + // we read 4 chars at a time (max is 53) + if (13 * 4 /* 52 */ == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 0, 54)); + } + + public function testBytesBelowPermittedRangeAreEncoded() + { + // According to Rule (1 & 2) + $encoder = new QpEncoder(); + foreach (range(0, 32) as $ordinal) { + $char = \chr($ordinal); + $this->assertEquals(sprintf('=%02X', $ordinal), $encoder->encodeString($char)); + } + } + + public function testDecimalByte61IsEncoded() + { + // According to Rule (1 & 2) + $encoder = new QpEncoder(); + $this->assertEquals('=3D', $encoder->encodeString('=')); + } + + public function testBytesAbovePermittedRangeAreEncoded() + { + // According to Rule (1 & 2) + $encoder = new QpEncoder(); + foreach (range(127, 255) as $ordinal) { + $this->assertSame(sprintf('=%02X', $ordinal), $encoder->encodeString(\chr($ordinal), 'iso-8859-1')); + } + } + + public function testFirstLineLengthCanBeDifferent() + { + $encoder = new QpEncoder(); + $input = str_repeat('a', 140); + $output = ''; + for ($i = 0; $i < 140; ++$i) { + // we read 4 chars at a time (max is 54 for the first line and 75 for the second one) + if (13 * 4 == $i || 13 * 4 + 18 * 4 == $i) { + $output .= "=\r\n"; + } + $output .= 'a'; + } + $this->assertEquals($output, $encoder->encodeString($input, 'utf-8', 22), 'First line should start at offset 22 so can only have max length 54'); + } + + public function testTextIsPreWrapped() + { + $encoder = new QpEncoder(); + $input = str_repeat('a', 70)."\r\n".str_repeat('a', 70)."\r\n".str_repeat('a', 70); + $this->assertEquals($input, $encoder->encodeString($input)); + } +} diff --git a/vendor/symfony/mime/Tests/Encoder/QpMimeHeaderEncoderTest.php b/vendor/symfony/mime/Tests/Encoder/QpMimeHeaderEncoderTest.php new file mode 100644 index 0000000000..f075452cbb --- /dev/null +++ b/vendor/symfony/mime/Tests/Encoder/QpMimeHeaderEncoderTest.php @@ -0,0 +1,139 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\QpMimeHeaderEncoder; + +class QpMimeHeaderEncoderTest extends TestCase +{ + public function testNameIsQ() + { + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('Q', $encoder->getName()); + } + + public function testSpaceAndTabNeverAppear() + { + /* -- RFC 2047, 4. + Only a subset of the printable ASCII characters may be used in + 'encoded-text'. Space and tab characters are not allowed, so that + the beginning and end of an 'encoded-word' are obvious. + */ + + $encoder = new QpMimeHeaderEncoder(); + $this->assertNotRegExp('~[ \t]~', $encoder->encodeString("a \t b"), 'encoded-words in headers cannot contain LWSP as per RFC 2047.'); + } + + public function testSpaceIsRepresentedByUnderscore() + { + /* -- RFC 2047, 4.2. + (2) The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be + represented as "_" (underscore, ASCII 95.). (This character may + not pass through some internetwork mail gateways, but its use + will greatly enhance readability of "Q" encoded data with mail + readers that do not support this encoding.) Note that the "_" + always represents hexadecimal 20, even if the SPACE character + occupies a different code position in the character set in use. + */ + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('a_b', $encoder->encodeString('a b'), 'Spaces can be represented by more readable underscores as per RFC 2047.'); + } + + public function testEqualsAndQuestionAndUnderscoreAreEncoded() + { + /* -- RFC 2047, 4.2. + (3) 8-bit values which correspond to printable ASCII characters other + than "=", "?", and "_" (underscore), MAY be represented as those + characters. (But see section 5 for restrictions.) In + particular, SPACE and TAB MUST NOT be represented as themselves + within encoded words. + */ + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('=3D=3F=5F', $encoder->encodeString('=?_'), 'Chars =, ? and _ (underscore) may not appear as per RFC 2047.'); + } + + public function testParensAndQuotesAreEncoded() + { + /* -- RFC 2047, 5 (2). + A "Q"-encoded 'encoded-word' which appears in a 'comment' MUST NOT + contain the characters "(", ")" or " + */ + + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals('=28=22=29', $encoder->encodeString('(")'), 'Chars (, " (DQUOTE) and ) may not appear as per RFC 2047.'); + } + + public function testOnlyCharactersAllowedInPhrasesAreUsed() + { + /* -- RFC 2047, 5. + (3) As a replacement for a 'word' entity within a 'phrase', for example, + one that precedes an address in a From, To, or Cc header. The ABNF + definition for 'phrase' from RFC 822 thus becomes: + + phrase = 1*( encoded-word / word ) + + In this case the set of characters that may be used in a "Q"-encoded + 'encoded-word' is restricted to: <upper and lower case ASCII + letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_" + (underscore, ASCII 95.)>. An 'encoded-word' that appears within a + 'phrase' MUST be separated from any adjacent 'word', 'text' or + 'special' by 'linear-white-space'. + */ + + $allowedBytes = array_merge( + range(\ord('a'), \ord('z')), range(\ord('A'), \ord('Z')), + range(\ord('0'), \ord('9')), + [\ord('!'), \ord('*'), \ord('+'), \ord('-'), \ord('/')] + ); + $encoder = new QpMimeHeaderEncoder(); + foreach (range(0x00, 0xFF) as $byte) { + $char = pack('C', $byte); + $encodedChar = $encoder->encodeString($char, 'iso-8859-1'); + if (\in_array($byte, $allowedBytes)) { + $this->assertEquals($char, $encodedChar, 'Character '.$char.' should not be encoded.'); + } elseif (0x20 == $byte) { + // special case + $this->assertEquals('_', $encodedChar, 'Space character should be replaced.'); + } else { + $this->assertEquals(sprintf('=%02X', $byte), $encodedChar, 'Byte '.$byte.' should be encoded.'); + } + } + } + + public function testEqualsNeverAppearsAtEndOfLine() + { + /* -- RFC 2047, 5 (3). + The 'encoded-text' in an 'encoded-word' must be self-contained; + 'encoded-text' MUST NOT be continued from one 'encoded-word' to + another. This implies that the 'encoded-text' portion of a "B" + 'encoded-word' will be a multiple of 4 characters long; for a "Q" + 'encoded-word', any "=" character that appears in the 'encoded-text' + portion will be followed by two hexadecimal characters. + */ + + $input = str_repeat('a', 140); + + $output = ''; + $seq = 0; + for (; $seq < 140; ++$seq) { + // compute the end of line (multiple of 4 chars) + if (18 * 4 === $seq) { + $output .= "\r\n"; // =\r\n + } + $output .= 'a'; + } + + $encoder = new QpMimeHeaderEncoder(); + $this->assertEquals($output, $encoder->encodeString($input)); + } +} diff --git a/vendor/symfony/mime/Tests/Encoder/Rfc2231EncoderTest.php b/vendor/symfony/mime/Tests/Encoder/Rfc2231EncoderTest.php new file mode 100644 index 0000000000..edcb15fcec --- /dev/null +++ b/vendor/symfony/mime/Tests/Encoder/Rfc2231EncoderTest.php @@ -0,0 +1,129 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Encoder; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Encoder\Rfc2231Encoder; + +class Rfc2231EncoderTest extends TestCase +{ + private $rfc2045Token = '/^[\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7E]+$/D'; + + /* -- + This algorithm is described in RFC 2231, but is barely touched upon except + for mentioning bytes can be represented as their octet values (e.g. %20 for + the SPACE character). + + The tests here focus on how to use that representation to always generate text + which matches RFC 2045's definition of "token". + */ + + public function testEncodingAsciiCharactersProducesValidToken() + { + $string = ''; + foreach (range(0x00, 0x7F) as $octet) { + $char = pack('C', $octet); + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string); + + foreach (explode("\r\n", $encoded) as $line) { + $this->assertRegExp($this->rfc2045Token, $line, 'Encoder should always return a valid RFC 2045 token.'); + } + } + + public function testEncodingNonAsciiCharactersProducesValidToken() + { + $string = ''; + foreach (range(0x80, 0xFF) as $octet) { + $char = pack('C', $octet); + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string); + + foreach (explode("\r\n", $encoded) as $line) { + $this->assertRegExp($this->rfc2045Token, $line, 'Encoder should always return a valid RFC 2045 token.'); + } + } + + public function testMaximumLineLengthCanBeSet() + { + $string = ''; + for ($x = 0; $x < 200; ++$x) { + $char = 'a'; + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string, 'utf-8', 0, 75); + + // 72 here and not 75 as we read 4 chars at a time + $this->assertEquals( + str_repeat('a', 72)."\r\n". + str_repeat('a', 72)."\r\n". + str_repeat('a', 56), + $encoded, + 'Lines should be wrapped at each 72 characters' + ); + } + + public function testFirstLineCanHaveShorterLength() + { + $string = ''; + for ($x = 0; $x < 200; ++$x) { + $char = 'a'; + $string .= $char; + } + $encoder = new Rfc2231Encoder(); + $encoded = $encoder->encodeString($string, 'utf-8', 24, 72); + + $this->assertEquals( + str_repeat('a', 48)."\r\n". + str_repeat('a', 72)."\r\n". + str_repeat('a', 72)."\r\n". + str_repeat('a', 8), + $encoded, + 'First line should be 24 bytes shorter than the others.' + ); + } + + public function testEncodingAndDecodingSamples() + { + $dir = realpath(__DIR__.'/../Fixtures/samples/charsets'); + $sampleFp = opendir($dir); + while (false !== $encoding = readdir($sampleFp)) { + if ('.' == substr($encoding, 0, 1)) { + continue; + } + + $encoder = new Rfc2231Encoder(); + if (is_dir($dir.'/'.$encoding)) { + $fileFp = opendir($dir.'/'.$encoding); + while (false !== $sampleFile = readdir($fileFp)) { + if ('.' == substr($sampleFile, 0, 1)) { + continue; + } + + $text = file_get_contents($dir.'/'.$encoding.'/'.$sampleFile); + $encodedText = $encoder->encodeString($text, $encoding); + $this->assertEquals( + urldecode(implode('', explode("\r\n", $encodedText))), $text, + 'Encoded string should decode back to original string for sample '.$dir.'/'.$encoding.'/'.$sampleFile + ); + } + closedir($fileFp); + } + } + closedir($sampleFp); + } +} diff --git a/vendor/symfony/mime/Tests/FileBinaryMimeTypeGuesserTest.php b/vendor/symfony/mime/Tests/FileBinaryMimeTypeGuesserTest.php new file mode 100644 index 0000000000..0742732895 --- /dev/null +++ b/vendor/symfony/mime/Tests/FileBinaryMimeTypeGuesserTest.php @@ -0,0 +1,23 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use Symfony\Component\Mime\FileBinaryMimeTypeGuesser; +use Symfony\Component\Mime\MimeTypeGuesserInterface; + +class FileBinaryMimeTypeGuesserTest extends AbstractMimeTypeGuesserTest +{ + protected function getGuesser(): MimeTypeGuesserInterface + { + return new FileBinaryMimeTypeGuesser(); + } +} diff --git a/vendor/symfony/mime/Tests/FileinfoMimeTypeGuesserTest.php b/vendor/symfony/mime/Tests/FileinfoMimeTypeGuesserTest.php new file mode 100644 index 0000000000..d2e6930a4b --- /dev/null +++ b/vendor/symfony/mime/Tests/FileinfoMimeTypeGuesserTest.php @@ -0,0 +1,26 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use Symfony\Component\Mime\FileinfoMimeTypeGuesser; +use Symfony\Component\Mime\MimeTypeGuesserInterface; + +/** + * @requires extension fileinfo + */ +class FileinfoMimeTypeGuesserTest extends AbstractMimeTypeGuesserTest +{ + protected function getGuesser(): MimeTypeGuesserInterface + { + return new FileinfoMimeTypeGuesser(); + } +} diff --git a/vendor/symfony/mime/Tests/Fixtures/mimetypes/.unknownextension b/vendor/symfony/mime/Tests/Fixtures/mimetypes/.unknownextension new file mode 100644 index 0000000000..4d1ae35ba2 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/mimetypes/.unknownextension @@ -0,0 +1 @@ +f
\ No newline at end of file diff --git a/vendor/symfony/mime/Tests/Fixtures/mimetypes/directory/.empty b/vendor/symfony/mime/Tests/Fixtures/mimetypes/directory/.empty new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/mimetypes/directory/.empty diff --git a/vendor/symfony/mime/Tests/Fixtures/mimetypes/other-file.example b/vendor/symfony/mime/Tests/Fixtures/mimetypes/other-file.example new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/mimetypes/other-file.example diff --git a/vendor/symfony/mime/Tests/Fixtures/mimetypes/test b/vendor/symfony/mime/Tests/Fixtures/mimetypes/test Binary files differnew file mode 100644 index 0000000000..b636f4b8df --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/mimetypes/test diff --git a/vendor/symfony/mime/Tests/Fixtures/mimetypes/test.gif b/vendor/symfony/mime/Tests/Fixtures/mimetypes/test.gif Binary files differnew file mode 100644 index 0000000000..b636f4b8df --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/mimetypes/test.gif diff --git a/vendor/symfony/mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt new file mode 100644 index 0000000000..c2923deb98 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/iso-2022-jp/one.txt @@ -0,0 +1,11 @@ +ISO-2022-JPは、インターネット上(特に電子メール)などで使われる日本の文字用の文字符号化方式。ISO/IEC 2022のエスケープシーケンスを利用して文字集合を切り替える7ビットのコードであることを特徴とする (アナウンス機能のエスケープシーケンスは省略される)。俗に「JISコード」と呼ばれることもある。
+
+概要
+日本語表記への利用が想定されている文字コードであり、日本語の利用されるネットワークにおいて、日本の規格を応用したものである。また文字集合としては、日本語で用いられる漢字、ひらがな、カタカナはもちろん、ラテン文字、ギリシア文字、キリル文字なども含んでおり、学術や産業の分野での利用も考慮たものとなっている。規格名に、ISOの日本語の言語コードであるjaではなく、国・地域名コードのJPが示されているゆえんである。
+文字集合としてJIS X 0201のC0集合(制御文字)、JIS X 0201のラテン文字集合、ISO 646の国際基準版図形文字、JIS X 0208の1978年版(JIS C 6226-1978)と1983年および1990年版が利用できる。JIS X 0201の片仮名文字集合は利用できない。1986年以降、日本の電子メールで用いられてきたJUNETコードを、村井純・Mark Crispin・Erik van der Poelが1993年にRFC化したもの(RFC 1468)。後にJIS X 0208:1997の附属書2としてJISに規定された。MIMEにおける文字符号化方式の識別用の名前として IANA に登録されている。
+なお、符号化の仕様についてはISO/IEC 2022#ISO-2022-JPも参照。
+
+ISO-2022-JPと非標準的拡張使用
+「JISコード」(または「ISO-2022-JP」)というコード名の規定下では、その仕様通りの使用が求められる。しかし、Windows OS上では、実際にはCP932コード (MicrosoftによるShift JISを拡張した亜種。ISO-2022-JP規定外文字が追加されている。)による独自拡張(の文字)を断りなく使うアプリケーションが多い。この例としてInternet ExplorerやOutlook Expressがある。また、EmEditor、秀丸エディタやThunderbirdのようなMicrosoft社以外のWindowsアプリケーションでも同様の場合がある。この場合、ISO-2022-JPの範囲外の文字を使ってしまうと、異なる製品間では未定義不明文字として認識されるか、もしくは文字化けを起こす原因となる。そのため、Windows用の電子メールクライアントであっても独自拡張の文字を使用すると警告を出したり、あえて使えないように制限しているものも存在する。さらにはISO-2022-JPの範囲内であってもCP932は非標準文字(FULLWIDTH TILDE等)を持つので文字化けの原因になり得る。
+また、符号化方式名をISO-2022-JPとしているのに、文字集合としてはJIS X 0212 (いわゆる補助漢字) やJIS X 0201の片仮名文字集合 (いわゆる半角カナ) をも符号化している例があるが、ISO-2022-JPではこれらの文字を許容していない。これらの符号化は独自拡張の実装であり、中にはISO/IEC 2022の仕様に準拠すらしていないものもある[2]。従って受信側の電子メールクライアントがこれらの独自拡張に対応していない場合、その文字あるいはその文字を含む行、時にはテキスト全体が文字化けすることがある。
+
diff --git a/vendor/symfony/mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt new file mode 100644 index 0000000000..3101178af2 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/iso-8859-1/one.txt @@ -0,0 +1,19 @@ +Op mat eraus hinnen beschte, rou zënne schaddreg ké. Ké sin Eisen Kaffi prächteg, den haut esou Fielse wa, Well zielen d'Welt am dir. Aus grousse rëschten d'Stroos do, as dat Kléder gewëss d'Kàchen. Schied gehéiert d'Vioule net hu, rou ke zënter Säiten d'Hierz. Ze eise Fletschen mat, gei as gréng d'Lëtzebuerger. Wäit räich no mat. + +Säiten d'Liewen aus en. Un gëtt bléit lossen wee, da wéi alle weisen Kolrettchen. Et deser d'Pan d'Kirmes vun, en wuel Benn rëschten méi. En get drem ménger beschte, da wär Stad welle. Nun Dach d'Pied do, mä gét ruffen gehéiert. Ze onser ugedon fir, d'Liewen Plett'len ech no, si Räis wielen bereet wat. Iwer spilt fir jo. + +An hin däischter Margréitchen, eng ke Frot brommt, vu den Räis néierens. Da hir Hunn Frot nozegon, rout Fläiß Himmel zum si, net gutt Kaffi Gesträich fu. Vill lait Gaart sou wa, Land Mamm Schuebersonndeg rei do. Gei geet Minutt en, gei d'Leit beschte Kolrettchen et, Mamm fergiess un hun. + +Et gutt Heck kommen oft, Lann rëscht rei um, Hunn rëscht schéinste ke der. En lait zielen schnéiwäiss hir, fu rou botze éiweg Minutt, rem fest gudden schaddreg en. Noper bereet Margréitchen mat op, dem denkt d'Leit d'Vioule no, oft ké Himmel Hämmel. En denkt blénken Fréijor net, Gart Schiet d'Natur no wou. No hin Ierd Frot d'Kirmes. Hire aremt un rou, ké den éiweg wielen Milliounen. + +Mir si Hunn Blénkeg. Ké get ston derfir d'Kàchen. Haut d'Pan fu ons, dé frou löschteg d'Meereische rei. Sou op wuel Léift. Stret schlon grousse gin hu. Mä denkt d'Leit hinnen net, ké gét haut fort rëscht. + +Koum d'Pan hannendrun ass ké, ké den brét Kaffi geplot. Schéi Hären d'Pied fu gét, do d'Mier néierens bei. Rëm päift Hämmel am, wee Engel beschéngt mä. Brommt klinzecht der ke, wa rout jeitzt dén. Get Zalot d'Vioule däischter da, jo fir Bänk päift duerch, bei d'Beem schéinen Plett'len jo. Den haut Faarwen ze, eng en Biereg Kirmesdag, um sin alles Faarwen d'Vioule. + +Eng Hunn Schied et, wat wa Frot fest gebotzt. Bei jo bleiwe ruffen Klarinett. Un Feld klinzecht gét, rifft Margréitchen rem ke. Mir dé Noper duurch gewëss, ston sech kille sin en. Gei Stret d'Wise um, Haus Gart wee as. Monn ménger an blo, wat da Gart gefällt Hämmelsbrot. + +Brommt geplot och ze, dat wa Räis Well Kaffi. Do get spilt prächteg, as wär kille bleiwe gewalteg. Onser frësch Margréitchen rem ke, blo en huet ugedon. Onser Hemecht wär de, hu eraus d'Sonn dat, eise deser hannendrun da och. + +As durch Himmel hun, no fest iw'rem schéinste mir, Hunn séngt Hierz ke zum. Séngt iw'rem d'Natur zum an. Ke wär gutt Grénge. Kënnt gudden prächteg mä rei. Dé dir Blénkeg Klarinett Kolrettchen, da fort muerges d'Kanner wou, main Feld ruffen vu wéi. Da gin esou Zalot gewalteg, gét vill Hemecht blénken dé. + +Haut gréng nun et, nei vu Bass gréng d'Gaassen. Fest d'Beem uechter si gin. Oft vu sinn wellen kréien. Et ass lait Zalot schéinen.
\ No newline at end of file diff --git a/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/one.txt b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/one.txt new file mode 100644 index 0000000000..26c94d5d23 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/one.txt @@ -0,0 +1,22 @@ +Код одно гринспана руководишь на. Его вы знания движение. Ты две начать +одиночку, сказать основатель удовольствием но миф. Бы какие система тем. +Полностью использует три мы, человек клоунов те нас, бы давать творческую +эзотерическая шеф. + +Мог не помнить никакого сэкономленного, две либо какие пишите бы. Должен +компанию кто те, этот заключалась проектировщик не ты. Глупые периоды ты +для. Вам который хороший он. Те любых кремния концентрируются мог, +собирать принадлежите без вы. + +Джоэла меньше хорошего вы миф, за тем году разработки. Даже управляющим +руководители был не. Три коде выпускать заботиться ну. То его система +удовольствием безостановочно, или ты главной процессорах. Мы без джоэл +знания получат, статьи остальные мы ещё. + +Них русском касается поскольку по, образование должником +систематизированный ну мои. Прийти кандидата университет но нас, для бы +должны никакого, биг многие причин интервьюирования за. + +Тем до плиту почему. Вот учёт такие одного бы, об биг разным внешних +промежуток. Вас до какому возможностей безответственный, были погодите бы +его, по них глупые долгий количества. diff --git a/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/three.txt b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/three.txt new file mode 100644 index 0000000000..c81ccd598b --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/three.txt @@ -0,0 +1,45 @@ +Αν ήδη διάβασε γλιτώσει μεταγλωτίσει, αυτήν θυμάμαι μου μα. Την κατάσταση χρησιμοποίησέ να! Τα διαφορά φαινόμενο διολισθήσεις πες, υψηλότερη προκαλείς περισσότερες όχι κι. Με ελέγχου γίνεται σας, μικρής δημιουργούν τη του. Τις τα γράψει εικόνες απαράδεκτη? + +Να ότι πρώτοι απαραίτητο. Άμεση πετάνε κακόκεφος τον ώς, να χώρου πιθανότητες του. Το μέχρι ορίστε λιγότερους σας. Πω ναί φυσικά εικόνες. + +Μου οι κώδικα αποκλειστικούς, λες το μάλλον συνεχώς. Νέου σημεία απίστευτα σας μα. Χρόνου μεταγλωτιστής σε νέα, τη τις πιάνει μπορούσες προγραμματιστές. Των κάνε βγαίνει εντυπωσιακό τα? Κρατάει τεσσαρών δυστυχώς της κι, ήδη υψηλότερη εξακολουθεί τα? + +Ώρα πετάνε μπορούσε λιγότερους αν, τα απαράδεκτη συγχωνευτεί ροή. Τη έγραψες συνηθίζουν σαν. Όλα με υλικό στήλες χειρότερα. Ανώδυνη δουλέψει επί ως, αν διαδίκτυο εσωτερικών παράγοντες από. Κεντρικό επιτυχία πες το. + +Πω ναι λέει τελειώσει, έξι ως έργων τελειώσει. Με αρχεία βουτήξουν ανταγωνιστής ώρα, πολύ γραφικά σελίδων τα στη. Όρο οέλεγχος δημιουργούν δε, ας θέλεις ελέγχου συντακτικό όρο! Της θυμάμαι επιδιόρθωση τα. Για μπορούσε περισσότερο αν, μέγιστη σημαίνει αποφάσισε τα του, άτομο αποτελέσει τι στα. + +Τι στην αφήσεις διοίκηση στη. Τα εσφαλμένη δημιουργια επιχείριση έξι! Βήμα μαγικά εκτελέσει ανά τη. Όλη αφήσεις συνεχώς εμπορικά αν, το λες κόλπα επιτυχία. Ότι οι ζώνη κειμένων. Όρο κι ρωτάει γραμμής πελάτες, τελειώσει διολισθήσεις καθυστερούσε αν εγώ? Τι πετούν διοίκηση προβλήματα ήδη. + +Τη γλιτώσει αποθηκευτικού μια. Πω έξι δημιουργια πιθανότητες, ως πέντε ελέγχους εκτελείται λες. Πως ερωτήσεις διοικητικό συγκεντρωμένοι οι, ας συνεχώς διοικητικό αποστηθίσει σαν. Δε πρώτες συνεχώς διολισθήσεις έχω, από τι κανένας βουτήξουν, γειτονιάς προσεκτικά ανταγωνιστής κι σαν. + +Δημιουργια συνηθίζουν κλπ τι? Όχι ποσοστό διακοπής κι. Κλπ φακέλους δεδομένη εξοργιστικά θα? Υποψήφιο καθορίζουν με όλη, στα πήρε προσοχή εταιρείες πω, ώς τον συνάδελφος διοικητικό δημιουργήσεις! Δούλευε επιτίθενται σας θα, με ένας παραγωγικής ένα, να ναι σημεία μέγιστη απαράδεκτη? + +Σας τεσσαρών συνεντεύξης τη, αρπάζεις σίγουρος μη για', επί τοπικές εντολές ακούσει θα? Ως δυστυχής μεταγλωτιστής όλη, να την είχαν σφάλμα απαραίτητο! Μην ώς άτομο διορθώσει χρησιμοποιούνταν. Δεν τα κόλπα πετάξαμε, μη που άγχος υόρκη άμεση, αφού δυστυχώς διακόψουμε όρο αν! Όλη μαγικά πετάνε επιδιορθώσεις δε, ροή φυσικά αποτελέσει πω. + +Άπειρα παραπάνω φαινόμενο πω ώρα, σαν πόρτες κρατήσουν συνηθίζουν ως. Κι ώρα τρέξει είχαμε εφαρμογή. Απλό σχεδιαστής μεταγλωτιστής ας επί, τις τα όταν έγραψες γραμμής? Όλα κάνεις συνάδελφος εργαζόμενοι θα, χαρτιού χαμηλός τα ροή. Ως ναι όροφο έρθει, μην πελάτες αποφάσισε μεταφραστής με, να βιαστικά εκδόσεις αναζήτησης λες. Των φταίει εκθέσεις προσπαθήσεις οι, σπίτι αποστηθίσει ας λες? + +Ώς που υπηρεσία απαραίτητο δημιουργείς. Μη άρα χαρά καθώς νύχτας, πω ματ μπουν είχαν. Άμεση δημιουργείς ώς ροή, γράψει γραμμής σίγουρος στα τι! Αν αφού πρώτοι εργαζόμενων ναί. + +Άμεση διορθώσεις με δύο? Έχουν παράδειγμα των θα, μου έρθει θυμάμαι περισσότερο το. Ότι θα αφού χρειάζονται περισσότερες. Σαν συνεχώς περίπου οι. + +Ώς πρώτης πετάξαμε λες, όρο κι πρώτες ζητήσεις δυστυχής. Ανά χρόνου διακοπή επιχειρηματίες ας, ώς μόλις άτομο χειρότερα όρο, κρατάει σχεδιαστής προσπαθήσεις νέο το. Πουλάς προσθέσει όλη πω, τύπου χαρακτηριστικό εγώ σε, πω πιο δούλευε αναζήτησης? Αναφορά δίνοντας σαν μη, μάθε δεδομένη εσωτερικών με ναι, αναφέρονται περιβάλλοντος ώρα αν. Και λέει απόλαυσε τα, που το όροφο προσπαθούν? + +Πάντα χρόνου χρήματα ναι το, σαν σωστά θυμάμαι σκεφτείς τα. Μα αποτελέσει ανεπιθύμητη την, πιο το τέτοιο ατόμου, τη των τρόπο εργαλείων επιδιόρθωσης. Περιβάλλον παραγωγικής σου κι, κλπ οι τύπου κακόκεφους αποστηθίσει, δε των πλέον τρόποι. Πιθανότητες χαρακτηριστικών σας κι, γραφικά δημιουργήσεις μια οι, πω πολλοί εξαρτάται προσεκτικά εδώ. Σταματάς παράγοντες για' ώς, στις ρωτάει το ναι! Καρέκλα ζητήσεις συνδυασμούς τη ήδη! + +Για μαγικά συνεχώς ακούσει το. Σταματάς προϊόντα βουτήξουν ώς ροή. Είχαν πρώτες οι ναι, μα λες αποστηθίσει ανακαλύπτεις. Όροφο άλγεβρα παραπάνω εδώ τη, πρόσληψη λαμβάνουν καταλάθος ήδη ας? Ως και εισαγωγή κρατήσουν, ένας κακόκεφους κι μας, όχι κώδικάς παίξουν πω. Πω νέα κρατάει εκφράσουν, τότε τελικών τη όχι, ας της τρέξει αλλάζοντας αποκλειστικούς. + +Ένας βιβλίο σε άρα, ναι ως γράψει ταξινομεί διορθώσεις! Εδώ να γεγονός συγγραφείς, ώς ήδη διακόψουμε επιχειρηματίες? Ότι πακέτων εσφαλμένη κι, θα όρο κόλπα παραγωγικής? Αν έχω κεντρικό υψηλότερη, κι δεν ίδιο πετάνε παρατηρούμενη! Που λοιπόν σημαντικό μα, προκαλείς χειροκροτήματα ως όλα, μα επί κόλπα άγχος γραμμές! Δε σου κάνεις βουτήξουν, μη έργων επενδυτής χρησιμοποίησέ στα, ως του πρώτες διάσημα σημαντικό. + +Βιβλίο τεράστιο προκύπτουν σαν το, σαν τρόπο επιδιόρθωση ας. Είχαν προσοχή προσπάθεια κι ματ, εδώ ως έτσι σελίδων συζήτηση. Και στην βγαίνει εσφαλμένη με, δυστυχής παράδειγμα δε μας, από σε υόρκη επιδιόρθωσης. Νέα πω νέου πιθανό, στήλες συγγραφείς μπαίνοντας μα για', το ρωτήσει κακόκεφους της? Μου σε αρέσει συγγραφής συγχωνευτεί, μη μου υόρκη ξέχασε διακοπής! Ώς επί αποφάσισε αποκλειστικούς χρησιμοποιώντας, χρήματα σελίδων ταξινομεί ναι με. + +Μη ανά γραμμή απόλαυσε, πω ναι μάτσο διασφαλίζεται. Τη έξι μόλις εργάστηκε δημιουργούν, έκδοση αναφορά δυσκολότερο οι νέο. Σας ως μπορούσε παράδειγμα, αν ότι δούλευε μπορούσε αποκλειστικούς, πιο λέει βουτήξουν διορθώσει ως. Έχω τελευταία κακόκεφους ας, όσο εργαζόμενων δημιουργήσεις τα. + +Του αν δουλέψει μπορούσε, πετούν χαμηλός εδώ ας? Κύκλο τύπους με που, δεν σε έχουν συνεχώς χειρότερα, τις τι απαράδεκτη συνηθίζουν? Θα μην τους αυτήν, τη ένα πήρε πακέτων, κι προκύπτουν περιβάλλον πως. Μα για δουλέψει απόλαυσε εφαμοργής, ώς εδώ σημαίνει μπορούσες, άμεση ακούσει προσοχή τη εδώ? + +Στα δώσε αθόρυβες λιγότερους οι, δε αναγκάζονται αποκλειστικούς όλα! Ας μπουν διοικητικό μια, πάντα ελέγχου διορθώσεις ώς τον. Ότι πήρε κανόνα μα. Που άτομα κάνεις δημιουργίες τα, οι μας αφού κόλπα προγραμματιστής, αφού ωραίο προκύπτουν στα ως. Θέμα χρησιμοποιήσει αν όλα, του τα άλγεβρα σελίδων. Τα ότι ανώδυνη δυστυχώς συνδυασμούς, μας οι πάντα γνωρίζουμε ανταγωνιστής, όχι τα δοκιμάσεις σχεδιαστής! Στην συνεντεύξης επιδιόρθωση πιο τα, μα από πουλάς περιβάλλον παραγωγικής. + +Έχουν μεταγλωτίσει σε σας, σε πάντα πρώτης μειώσει των, γράψει ρουτίνα δυσκολότερο ήδη μα? Ταξινομεί διορθώσεις να μας. Θα της προσπαθούν περιεχόμενα, δε έχω τοπικές στέλνοντάς. Ανά δε αλφα άμεση, κάποιο ρωτάει γνωρίζουμε πω στη, φράση μαγικά συνέχεια δε δύο! Αν είχαμε μειώσει ροή, μας μετράει καθυστερούσε επιδιορθώσεις μη. Χάος υόρκη κεντρικό έχω σε, ανά περίπου αναγκάζονται πω. + +Όσο επιστρέφουν χρονοδιαγράμματα μη. Πως ωραίο κακόκεφος διαχειριστής ως, τις να διακοπής αναζήτησης. Κάποιο ποσοστό ταξινομεί επί τη? Μάθε άμεση αλλάζοντας δύο με, μου νέου πάντα να. + +Πω του δυστυχώς πιθανότητες. Κι ρωτάει υψηλότερη δημιουργια ότι, πω εισαγωγή τελευταία απομόνωση ναι. Των ζητήσεις γνωρίζουμε ώς? Για' μη παραδοτέου αναφέρονται! Ύψος παραγωγικά ροή ως, φυσικά διάβασε εικόνες όσο σε? Δεν υόρκη διορθώσεις επεξεργασία θα, ως μέση σύστημα χρησιμοποιήσει τις.
\ No newline at end of file diff --git a/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/two.txt b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/two.txt new file mode 100644 index 0000000000..2443fc4d88 --- /dev/null +++ b/vendor/symfony/mime/Tests/Fixtures/samples/charsets/utf-8/two.txt @@ -0,0 +1,3 @@ +रखति आवश्यकत प्रेरना मुख्यतह हिंदी किएलोग असक्षम कार्यलय करते विवरण किके मानसिक दिनांक पुर्व संसाध एवम् कुशलता अमितकुमार प्रोत्साहित जनित देखने उदेशीत विकसित बलवान ब्रौशर किएलोग विश्लेषण लोगो कैसे जागरुक प्रव्रुति प्रोत्साहित सदस्य आवश्यकत प्रसारन उपलब्धता अथवा हिंदी जनित दर्शाता यन्त्रालय बलवान अतित सहयोग शुरुआत सभीकुछ माहितीवानीज्य लिये खरिदे है।अभी एकत्रित सम्पर्क रिती मुश्किल प्राथमिक भेदनक्षमता विश्व उन्हे गटको द्वारा तकरीबन + +विश्व द्वारा व्याख्या सके। आजपर वातावरण व्याख्यान पहोच। हमारी कीसे प्राथमिक विचारशिलता पुर्व करती कम्प्युटर भेदनक्षमता लिये बलवान और्४५० यायेका वार्तालाप सुचना भारत शुरुआत लाभान्वित पढाए संस्था वर्णित मार्गदर्शन चुनने
\ No newline at end of file diff --git a/vendor/symfony/mime/Tests/Header/DateHeaderTest.php b/vendor/symfony/mime/Tests/Header/DateHeaderTest.php new file mode 100644 index 0000000000..4fc92b96ae --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/DateHeaderTest.php @@ -0,0 +1,80 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\DateHeader; + +class DateHeaderTest extends TestCase +{ + /* -- + The following tests refer to RFC 2822, section 3.6.1 and 3.3. + */ + + public function testGetDateTime() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable()); + $this->assertSame($dateTime, $header->getDateTime()); + } + + public function testDateTimeCanBeSetBySetter() + { + $header = new DateHeader('Date', new \DateTimeImmutable()); + $header->setDateTime($dateTime = new \DateTimeImmutable()); + $this->assertSame($dateTime, $header->getDateTime()); + } + + public function testDateTimeIsConvertedToImmutable() + { + $dateTime = new \DateTime(); + $header = new DateHeader('Date', $dateTime); + $this->assertInstanceOf('DateTimeImmutable', $header->getDateTime()); + $this->assertEquals($dateTime->getTimestamp(), $header->getDateTime()->getTimestamp()); + $this->assertEquals($dateTime->getTimezone(), $header->getDateTime()->getTimezone()); + } + + public function testDateTimeIsImmutable() + { + $header = new DateHeader('Date', $dateTime = new \DateTime('2000-01-01 12:00:00 Europe/Berlin')); + $dateTime->setDate(2002, 2, 2); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getDateTime()->format('r')); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getBodyAsString()); + } + + public function testDateTimeIsConvertedToRfc2822Date() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin')); + $header->setDateTime($dateTime); + $this->assertEquals('Sat, 01 Jan 2000 12:00:00 +0100', $header->getBodyAsString()); + } + + public function testSetBody() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable()); + $header->setBody($dateTime); + $this->assertEquals($dateTime->format('r'), $header->getBodyAsString()); + } + + public function testGetBody() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable()); + $header->setDateTime($dateTime); + $this->assertEquals($dateTime, $header->getBody()); + } + + public function testToString() + { + $header = new DateHeader('Date', $dateTime = new \DateTimeImmutable('2000-01-01 12:00:00 Europe/Berlin')); + $header->setDateTime($dateTime); + $this->assertEquals('Date: Sat, 01 Jan 2000 12:00:00 +0100', $header->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/Header/HeadersTest.php b/vendor/symfony/mime/Tests/Header/HeadersTest.php new file mode 100644 index 0000000000..2f4a1dd635 --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/HeadersTest.php @@ -0,0 +1,245 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\IdentificationHeader; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; + +class HeadersTest extends TestCase +{ + public function testAddMailboxListHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addMailboxListHeader('From', ['person@domain']); + $this->assertNotNull($headers->get('From')); + } + + public function testAddDateHeaderDelegatesToFactory() + { + $dateTime = new \DateTimeImmutable(); + $headers = new Headers(); + $headers->addDateHeader('Date', $dateTime); + $this->assertNotNull($headers->get('Date')); + } + + public function testAddTextHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addTextHeader('Subject', 'some text'); + $this->assertNotNull($headers->get('Subject')); + } + + public function testAddParameterizedHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']); + $this->assertNotNull($headers->get('Content-Type')); + } + + public function testAddIdHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertNotNull($headers->get('Message-ID')); + } + + public function testAddPathHeaderDelegatesToFactory() + { + $headers = new Headers(); + $headers->addPathHeader('Return-Path', 'some@path'); + $this->assertNotNull($headers->get('Return-Path')); + } + + public function testHasReturnsFalseWhenNoHeaders() + { + $headers = new Headers(); + $this->assertFalse($headers->has('Some-Header')); + } + + public function testAddedMailboxListHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addMailboxListHeader('From', ['person@domain']); + $this->assertTrue($headers->has('From')); + } + + public function testAddedDateHeaderIsSeenByHas() + { + $dateTime = new \DateTimeImmutable(); + $headers = new Headers(); + $headers->addDateHeader('Date', $dateTime); + $this->assertTrue($headers->has('Date')); + } + + public function testAddedTextHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addTextHeader('Subject', 'some text'); + $this->assertTrue($headers->has('Subject')); + } + + public function testAddedParameterizedHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']); + $this->assertTrue($headers->has('Content-Type')); + } + + public function testAddedIdHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($headers->has('Message-ID')); + } + + public function testAddedPathHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->addPathHeader('Return-Path', 'some@path'); + $this->assertTrue($headers->has('Return-Path')); + } + + public function testNewlySetHeaderIsSeenByHas() + { + $headers = new Headers(); + $headers->add(new UnstructuredHeader('X-Foo', 'bar')); + $this->assertTrue($headers->has('X-Foo')); + } + + public function testHasCanDistinguishMultipleHeaders() + { + $headers = new Headers(); + $headers->addTextHeader('X-Test', 'some@id'); + $headers->addTextHeader('X-Test', 'other@id'); + $this->assertTrue($headers->has('X-Test')); + } + + public function testGet() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals($header->toString(), $headers->get('Message-ID')->toString()); + } + + public function testGetReturnsNullIfHeaderNotSet() + { + $headers = new Headers(); + $this->assertNull($headers->get('Message-ID')); + } + + public function testGetAllReturnsAllHeadersMatchingName() + { + $header0 = new UnstructuredHeader('X-Test', 'some@id'); + $header1 = new UnstructuredHeader('X-Test', 'other@id'); + $header2 = new UnstructuredHeader('X-Test', 'more@id'); + $headers = new Headers(); + $headers->addTextHeader('X-Test', 'some@id'); + $headers->addTextHeader('X-Test', 'other@id'); + $headers->addTextHeader('X-Test', 'more@id'); + $this->assertEquals([$header0, $header1, $header2], iterator_to_array($headers->getAll('X-Test'))); + } + + public function testGetAllReturnsAllHeadersIfNoArguments() + { + $header0 = new IdentificationHeader('Message-ID', 'some@id'); + $header1 = new UnstructuredHeader('Subject', 'thing'); + $header2 = new MailboxListHeader('To', [new Address('person@example.org')]); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $headers->addTextHeader('Subject', 'thing'); + $headers->addMailboxListHeader('To', [new Address('person@example.org')]); + $this->assertEquals(['message-id' => $header0, 'subject' => $header1, 'to' => $header2], iterator_to_array($headers->getAll())); + } + + public function testGetAllReturnsEmptyArrayIfNoneSet() + { + $headers = new Headers(); + $this->assertEquals([], iterator_to_array($headers->getAll('Received'))); + } + + public function testRemoveRemovesAllHeadersWithName() + { + $header0 = new UnstructuredHeader('X-Test', 'some@id'); + $header1 = new UnstructuredHeader('X-Test', 'other@id'); + $headers = new Headers(); + $headers->addIdHeader('X-Test', 'some@id'); + $headers->addIdHeader('X-Test', 'other@id'); + $headers->remove('X-Test'); + $this->assertFalse($headers->has('X-Test')); + $this->assertFalse($headers->has('X-Test')); + } + + public function testHasIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertTrue($headers->has('message-id')); + } + + public function testGetIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals($header, $headers->get('message-id')); + } + + public function testGetAllIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $this->assertEquals([$header], iterator_to_array($headers->getAll('message-id'))); + } + + public function testRemoveIsNotCaseSensitive() + { + $header = new IdentificationHeader('Message-ID', 'some@id'); + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $headers->remove('message-id'); + $this->assertFalse($headers->has('Message-ID')); + } + + public function testToStringJoinsHeadersTogether() + { + $headers = new Headers(); + $headers->addTextHeader('Foo', 'bar'); + $headers->addTextHeader('Zip', 'buttons'); + $this->assertEquals("Foo: bar\r\nZip: buttons\r\n", $headers->toString()); + } + + public function testHeadersWithoutBodiesAreNotDisplayed() + { + $headers = new Headers(); + $headers->addTextHeader('Foo', 'bar'); + $headers->addTextHeader('Zip', ''); + $this->assertEquals("Foo: bar\r\n", $headers->toString()); + } + + public function testToArray() + { + $headers = new Headers(); + $headers->addIdHeader('Message-ID', 'some@id'); + $headers->addTextHeader('Foo', str_repeat('a', 60).pack('C', 0x8F)); + $this->assertEquals([ + 'Message-ID: <some@id>', + "Foo: =?utf-8?Q?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa?=\r\n =?utf-8?Q?aaaa?=", + ], $headers->toArray()); + } +} diff --git a/vendor/symfony/mime/Tests/Header/IdentificationHeaderTest.php b/vendor/symfony/mime/Tests/Header/IdentificationHeaderTest.php new file mode 100644 index 0000000000..7d94d4d19d --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/IdentificationHeaderTest.php @@ -0,0 +1,179 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\IdentificationHeader; + +class IdentificationHeaderTest extends TestCase +{ + public function testValueMatchesMsgIdSpec() + { + /* -- RFC 2822, 3.6.4. + message-id = "Message-ID:" msg-id CRLF + + in-reply-to = "In-Reply-To:" 1*msg-id CRLF + + references = "References:" 1*msg-id CRLF + + msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] + + id-left = dot-atom-text / no-fold-quote / obs-id-left + + id-right = dot-atom-text / no-fold-literal / obs-id-right + + no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE + + no-fold-literal = "[" *(dtext / quoted-pair) "]" + */ + + $header = new IdentificationHeader('Message-ID', 'id-left@id-right'); + $this->assertEquals('<id-left@id-right>', $header->getBodyAsString()); + } + + public function testIdCanBeRetrievedVerbatim() + { + $header = new IdentificationHeader('Message-ID', 'id-left@id-right'); + $this->assertEquals('id-left@id-right', $header->getId()); + } + + public function testMultipleIdsCanBeSet() + { + $header = new IdentificationHeader('References', 'c@d'); + $header->setIds(['a@b', 'x@y']); + $this->assertEquals(['a@b', 'x@y'], $header->getIds()); + } + + public function testSettingMultipleIdsProducesAListValue() + { + /* -- RFC 2822, 3.6.4. + The "References:" and "In-Reply-To:" field each contain one or more + unique message identifiers, optionally separated by CFWS. + + .. SNIP .. + + in-reply-to = "In-Reply-To:" 1*msg-id CRLF + + references = "References:" 1*msg-id CRLF + */ + + $header = new IdentificationHeader('References', ['a@b', 'x@y']); + $this->assertEquals('<a@b> <x@y>', $header->getBodyAsString()); + } + + public function testIdLeftCanBeQuoted() + { + /* -- RFC 2822, 3.6.4. + id-left = dot-atom-text / no-fold-quote / obs-id-left + */ + + $header = new IdentificationHeader('References', '"ab"@c'); + $this->assertEquals('"ab"@c', $header->getId()); + $this->assertEquals('<"ab"@c>', $header->getBodyAsString()); + } + + public function testIdLeftCanContainAnglesAsQuotedPairs() + { + /* -- RFC 2822, 3.6.4. + no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE + */ + + $header = new IdentificationHeader('References', '"a\\<\\>b"@c'); + $this->assertEquals('"a\\<\\>b"@c', $header->getId()); + $this->assertEquals('<"a\\<\\>b"@c>', $header->getBodyAsString()); + } + + public function testIdLeftCanBeDotAtom() + { + $header = new IdentificationHeader('References', 'a.b+&%$.c@d'); + $this->assertEquals('a.b+&%$.c@d', $header->getId()); + $this->assertEquals('<a.b+&%$.c@d>', $header->getBodyAsString()); + } + + /** + * @expectedException \Exception + * @expectedMessageException "a b c" is not valid id-left + */ + public function testInvalidIdLeftThrowsException() + { + $header = new IdentificationHeader('References', 'a b c@d'); + } + + public function testIdRightCanBeDotAtom() + { + /* -- RFC 2822, 3.6.4. + id-right = dot-atom-text / no-fold-literal / obs-id-right + */ + + $header = new IdentificationHeader('References', 'a@b.c+&%$.d'); + $this->assertEquals('a@b.c+&%$.d', $header->getId()); + $this->assertEquals('<a@b.c+&%$.d>', $header->getBodyAsString()); + } + + public function testIdRightCanBeLiteral() + { + /* -- RFC 2822, 3.6.4. + no-fold-literal = "[" *(dtext / quoted-pair) "]" + */ + + $header = new IdentificationHeader('References', 'a@[1.2.3.4]'); + $this->assertEquals('a@[1.2.3.4]', $header->getId()); + $this->assertEquals('<a@[1.2.3.4]>', $header->getBodyAsString()); + } + + public function testIdRigthIsIdnEncoded() + { + $header = new IdentificationHeader('References', 'a@ä'); + $this->assertEquals('a@ä', $header->getId()); + $this->assertEquals('<a@xn--4ca>', $header->getBodyAsString()); + } + + /** + * @expectedException \Exception + * @expectedMessageException "b c d" is not valid id-right + */ + public function testInvalidIdRightThrowsException() + { + $header = new IdentificationHeader('References', 'a@b c d'); + } + + /** + * @expectedException \Exception + * @expectedMessageException "abc" is does not contain @ + */ + public function testMissingAtSignThrowsException() + { + /* -- RFC 2822, 3.6.4. + msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] + */ + $header = new IdentificationHeader('References', 'abc'); + } + + public function testSetBody() + { + $header = new IdentificationHeader('Message-ID', 'c@d'); + $header->setBody('a@b'); + $this->assertEquals(['a@b'], $header->getIds()); + } + + public function testGetBody() + { + $header = new IdentificationHeader('Message-ID', 'a@b'); + $this->assertEquals(['a@b'], $header->getBody()); + } + + public function testStringValue() + { + $header = new IdentificationHeader('References', ['a@b', 'x@y']); + $this->assertEquals('References: <a@b> <x@y>', $header->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/Header/MailboxHeaderTest.php b/vendor/symfony/mime/Tests/Header/MailboxHeaderTest.php new file mode 100644 index 0000000000..11a7ac9c54 --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/MailboxHeaderTest.php @@ -0,0 +1,79 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\MailboxHeader; +use Symfony\Component\Mime\NamedAddress; + +class MailboxHeaderTest extends TestCase +{ + public function testConstructor() + { + $header = new MailboxHeader('Sender', $address = new Address('fabien@symfony.com')); + $this->assertEquals($address, $header->getAddress()); + $this->assertEquals($address, $header->getBody()); + } + + public function testAddress() + { + $header = new MailboxHeader('Sender', new Address('fabien@symfony.com')); + $header->setBody($address = new Address('helene@symfony.com')); + $this->assertEquals($address, $header->getAddress()); + $this->assertEquals($address, $header->getBody()); + $header->setAddress($address = new Address('thomas@symfony.com')); + $this->assertEquals($address, $header->getAddress()); + $this->assertEquals($address, $header->getBody()); + } + + public function testgetBodyAsString() + { + $header = new MailboxHeader('Sender', new Address('fabien@symfony.com')); + $this->assertEquals('fabien@symfony.com', $header->getBodyAsString()); + + $header->setAddress(new Address('fabien@sïmfony.com')); + $this->assertEquals('fabien@xn--smfony-iwa.com', $header->getBodyAsString()); + + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier')); + $this->assertEquals('Fabien Potencier <fabien@symfony.com>', $header->getBodyAsString()); + + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier, "from Symfony"')); + $this->assertEquals('"Fabien Potencier, \"from Symfony\"" <fabien@symfony.com>', $header->getBodyAsString()); + + $header = new MailboxHeader('From', new NamedAddress('fabien@symfony.com', 'Fabien Potencier, \\escaped\\')); + $this->assertEquals('"Fabien Potencier, \\\\escaped\\\\" <fabien@symfony.com>', $header->getBodyAsString()); + + $name = 'P'.pack('C', 0x8F).'tencier'; + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien '.$name)); + $header->setCharset('iso-8859-1'); + $this->assertEquals('Fabien =?'.$header->getCharset().'?Q?P=8Ftencier?= <fabien@symfony.com>', $header->getBodyAsString()); + } + + /** + * @expectedException \Symfony\Component\Mime\Exception\AddressEncoderException + */ + public function testUtf8CharsInLocalPartThrows() + { + $header = new MailboxHeader('Sender', new Address('fabïen@symfony.com')); + $header->getBodyAsString(); + } + + public function testToString() + { + $header = new MailboxHeader('Sender', new Address('fabien@symfony.com')); + $this->assertEquals('Sender: fabien@symfony.com', $header->toString()); + + $header = new MailboxHeader('Sender', new NamedAddress('fabien@symfony.com', 'Fabien Potencier')); + $this->assertEquals('Sender: Fabien Potencier <fabien@symfony.com>', $header->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/Header/MailboxListHeaderTest.php b/vendor/symfony/mime/Tests/Header/MailboxListHeaderTest.php new file mode 100644 index 0000000000..a2a28050f1 --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/MailboxListHeaderTest.php @@ -0,0 +1,133 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\NamedAddress; + +class MailboxListHeaderTest extends TestCase +{ + // RFC 2822, 3.6.2 for all tests + + public function testMailboxIsSetForAddress() + { + $header = new MailboxListHeader('From', [new Address('chris@swiftmailer.org')]); + $this->assertEquals(['chris@swiftmailer.org'], $header->getAddressStrings()); + } + + public function testMailboxIsRenderedForNameAddress() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn')]); + $this->assertEquals(['Chris Corbyn <chris@swiftmailer.org>'], $header->getAddressStrings()); + } + + public function testAddressCanBeReturnedForAddress() + { + $header = new MailboxListHeader('From', $addresses = [new Address('chris@swiftmailer.org')]); + $this->assertEquals($addresses, $header->getAddresses()); + } + + public function testQuotesInNameAreQuoted() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, "DHE"')]); + $this->assertEquals(['"Chris Corbyn, \"DHE\"" <chris@swiftmailer.org>'], $header->getAddressStrings()); + } + + public function testEscapeCharsInNameAreQuoted() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, \\escaped\\')]); + $this->assertEquals(['"Chris Corbyn, \\\\escaped\\\\" <chris@swiftmailer.org>'], $header->getAddressStrings()); + } + + public function testUtf8CharsInDomainAreIdnEncoded() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swïftmailer.org', 'Chris Corbyn')]); + $this->assertEquals(['Chris Corbyn <chris@xn--swftmailer-78a.org>'], $header->getAddressStrings()); + } + + /** + * @expectedException \Symfony\Component\Mime\Exception\AddressEncoderException + */ + public function testUtf8CharsInLocalPartThrows() + { + $header = new MailboxListHeader('From', [new NamedAddress('chrïs@swiftmailer.org', 'Chris Corbyn')]); + $header->getAddressStrings(); + } + + public function testGetMailboxesReturnsNameValuePairs() + { + $header = new MailboxListHeader('From', $addresses = [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn, DHE')]); + $this->assertEquals($addresses, $header->getAddresses()); + } + + public function testMultipleAddressesAsMailboxStrings() + { + $header = new MailboxListHeader('From', [new Address('chris@swiftmailer.org'), new Address('mark@swiftmailer.org')]); + $this->assertEquals(['chris@swiftmailer.org', 'mark@swiftmailer.org'], $header->getAddressStrings()); + } + + public function testNameIsEncodedIfNonAscii() + { + $name = 'C'.pack('C', 0x8F).'rbyn'; + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris '.$name)]); + $header->setCharset('iso-8859-1'); + $addresses = $header->getAddressStrings(); + $this->assertEquals('Chris =?'.$header->getCharset().'?Q?C=8Frbyn?= <chris@swiftmailer.org>', array_shift($addresses)); + } + + public function testEncodingLineLengthCalculations() + { + /* -- RFC 2047, 2. + An 'encoded-word' may not be more than 75 characters long, including + 'charset', 'encoding', 'encoded-text', and delimiters. + */ + + $name = 'C'.pack('C', 0x8F).'rbyn'; + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris '.$name)]); + $header->setCharset('iso-8859-1'); + $addresses = $header->getAddressStrings(); + $this->assertEquals('Chris =?'.$header->getCharset().'?Q?C=8Frbyn?= <chris@swiftmailer.org>', array_shift($addresses)); + } + + public function testGetValueReturnsMailboxStringValue() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn')]); + $this->assertEquals('Chris Corbyn <chris@swiftmailer.org>', $header->getBodyAsString()); + } + + public function testGetValueReturnsMailboxStringValueForMultipleMailboxes() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@swiftmailer.org', 'Chris Corbyn'), new NamedAddress('mark@swiftmailer.org', 'Mark Corbyn')]); + $this->assertEquals('Chris Corbyn <chris@swiftmailer.org>, Mark Corbyn <mark@swiftmailer.org>', $header->getBodyAsString()); + } + + public function testSetBody() + { + $header = new MailboxListHeader('From', []); + $header->setBody($addresses = [new Address('chris@swiftmailer.org')]); + $this->assertEquals($addresses, $header->getAddresses()); + } + + public function testGetBody() + { + $header = new MailboxListHeader('From', $addresses = [new Address('chris@swiftmailer.org')]); + $this->assertEquals($addresses, $header->getBody()); + } + + public function testToString() + { + $header = new MailboxListHeader('From', [new NamedAddress('chris@example.org', 'Chris Corbyn'), new NamedAddress('mark@example.org', 'Mark Corbyn')]); + $this->assertEquals('From: Chris Corbyn <chris@example.org>, Mark Corbyn <mark@example.org>', $header->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/Header/ParameterizedHeaderTest.php b/vendor/symfony/mime/Tests/Header/ParameterizedHeaderTest.php new file mode 100644 index 0000000000..aa8265814b --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/ParameterizedHeaderTest.php @@ -0,0 +1,274 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\ParameterizedHeader; + +class ParameterizedHeaderTest extends TestCase +{ + private $charset = 'utf-8'; + private $lang = 'en-us'; + + public function testValueIsReturnedVerbatim() + { + $header = new ParameterizedHeader('Content-Type', 'text/plain'); + $this->assertEquals('text/plain', $header->getValue()); + } + + public function testParametersAreAppended() + { + /* -- RFC 2045, 5.1 + parameter := attribute "=" value + + attribute := token + ; Matching of attributes + ; is ALWAYS case-insensitive. + + value := token / quoted-string + + token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, + or tspecials> + + tspecials := "(" / ")" / "<" / ">" / "@" / + "," / ";" / ":" / "\" / <"> + "/" / "[" / "]" / "?" / "=" + ; Must be in quoted-string, + ; to use within parameter values + */ + + $header = new ParameterizedHeader('Content-Type', 'text/plain'); + $header->setParameters(['charset' => 'utf-8']); + $this->assertEquals('text/plain; charset=utf-8', $header->getBodyAsString()); + } + + public function testSpaceInParamResultsInQuotedString() + { + $header = new ParameterizedHeader('Content-Type', 'attachment'); + $header->setParameters(['filename' => 'my file.txt']); + $this->assertEquals('attachment; filename="my file.txt"', $header->getBodyAsString()); + } + + public function testLongParamsAreBrokenIntoMultipleAttributeStrings() + { + /* -- RFC 2231, 3. + The asterisk character ("*") followed + by a decimal count is employed to indicate that multiple parameters + are being used to encapsulate a single parameter value. The count + starts at 0 and increments by 1 for each subsequent section of the + parameter value. Decimal values are used and neither leading zeroes + nor gaps in the sequence are allowed. + + The original parameter value is recovered by concatenating the + various sections of the parameter, in order. For example, the + content-type field + + Content-Type: message/external-body; access-type=URL; + URL*0="ftp://"; + URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + + is semantically identical to + + Content-Type: message/external-body; access-type=URL; + URL="ftp://cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar" + + Note that quotes around parameter values are part of the value + syntax; they are NOT part of the value itself. Furthermore, it is + explicitly permitted to have a mixture of quoted and unquoted + continuation fields. + */ + + $value = str_repeat('a', 180); + + $header = new ParameterizedHeader('Content-Disposition', 'attachment'); + $header->setParameters(['filename' => $value]); + $this->assertEquals( + 'attachment; '. + 'filename*0*=utf-8\'\''.str_repeat('a', 60).";\r\n ". + 'filename*1*='.str_repeat('a', 60).";\r\n ". + 'filename*2*='.str_repeat('a', 60), + $header->getBodyAsString() + ); + } + + public function testEncodedParamDataIncludesCharsetAndLanguage() + { + /* -- RFC 2231, 4. + Asterisks ("*") are reused to provide the indicator that language and + character set information is present and encoding is being used. A + single quote ("'") is used to delimit the character set and language + information at the beginning of the parameter value. Percent signs + ("%") are used as the encoding flag, which agrees with RFC 2047. + + Specifically, an asterisk at the end of a parameter name acts as an + indicator that character set and language information may appear at + the beginning of the parameter value. A single quote is used to + separate the character set, language, and actual value information in + the parameter value string, and an percent sign is used to flag + octets encoded in hexadecimal. For example: + + Content-Type: application/x-stuff; + title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A + + Note that it is perfectly permissible to leave either the character + set or language field blank. Note also that the single quote + delimiters MUST be present even when one of the field values is + omitted. + */ + + $value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 10); + $header = new ParameterizedHeader('Content-Disposition', 'attachment'); + $header->setCharset('iso-8859-1'); + $header->setValue('attachment'); + $header->setParameters(['filename' => $value]); + $header->setLanguage($this->lang); + $this->assertEquals( + 'attachment; filename*='.$header->getCharset()."'".$this->lang."'". + str_repeat('a', 20).'%8F'.str_repeat('a', 10), + $header->getBodyAsString() + ); + } + + public function testMultipleEncodedParamLinesAreFormattedCorrectly() + { + /* -- RFC 2231, 4.1. + Character set and language information may be combined with the + parameter continuation mechanism. For example: + + Content-Type: application/x-stuff + title*0*=us-ascii'en'This%20is%20even%20more%20 + title*1*=%2A%2A%2Afun%2A%2A%2A%20 + title*2="isn't it!" + + Note that: + + (1) Language and character set information only appear at + the beginning of a given parameter value. + + (2) Continuations do not provide a facility for using more + than one character set or language in the same + parameter value. + + (3) A value presented using multiple continuations may + contain a mixture of encoded and unencoded segments. + + (4) The first segment of a continuation MUST be encoded if + language and character set information are given. + + (5) If the first segment of a continued parameter value is + encoded the language and character set field delimiters + MUST be present even when the fields are left blank. + */ + + $value = str_repeat('a', 20).pack('C', 0x8F).str_repeat('a', 60); + $header = new ParameterizedHeader('Content-Disposition', 'attachment'); + $header->setValue('attachment'); + $header->setCharset('utf-6'); + $header->setParameters(['filename' => $value]); + $header->setLanguage($this->lang); + $this->assertEquals( + 'attachment; filename*0*='.$header->getCharset()."'".$this->lang."'". + str_repeat('a', 20).'%8F'.str_repeat('a', 23).";\r\n ". + 'filename*1*='.str_repeat('a', 37), + $header->getBodyAsString() + ); + } + + public function testToString() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setParameters(['charset' => 'utf-8']); + $this->assertEquals('Content-Type: text/html; charset=utf-8', $header->toString()); + } + + public function testValueCanBeEncodedIfNonAscii() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', $value); + $header->setCharset('iso-8859-1'); + $header->setParameters(['lookslike' => 'foobar']); + $this->assertEquals('X-Foo: =?'.$header->getCharset().'?Q?fo=8Fbar?=; lookslike=foobar', $header->toString()); + } + + public function testValueAndParamCanBeEncodedIfNonAscii() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', $value); + $header->setCharset('iso-8859-1'); + $header->setParameters(['says' => $value]); + $this->assertEquals('X-Foo: =?'.$header->getCharset().'?Q?fo=8Fbar?=; says="=?'.$header->getCharset().'?Q?fo=8Fbar?="', $header->toString()); + } + + public function testParamsAreEncodedWithEncodedWordsIfNoParamEncoderSet() + { + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', 'bar'); + $header->setCharset('iso-8859-1'); + $header->setParameters(['says' => $value]); + $this->assertEquals('X-Foo: bar; says="=?'.$header->getCharset().'?Q?fo=8Fbar?="', $header->toString()); + } + + public function testLanguageInformationAppearsInEncodedWords() + { + /* -- RFC 2231, 5. + 5. Language specification in Encoded Words + + RFC 2047 provides support for non-US-ASCII character sets in RFC 822 + message header comments, phrases, and any unstructured text field. + This is done by defining an encoded word construct which can appear + in any of these places. Given that these are fields intended for + display, it is sometimes necessary to associate language information + with encoded words as well as just the character set. This + specification extends the definition of an encoded word to allow the + inclusion of such information. This is simply done by suffixing the + character set specification with an asterisk followed by the language + tag. For example: + + From: =?US-ASCII*EN?Q?Keith_Moore?= <moore@cs.utk.edu> + */ + + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new ParameterizedHeader('X-Foo', $value); + $header->setCharset('iso-8859-1'); + $header->setLanguage('en'); + $header->setParameters(['says' => $value]); + $this->assertEquals('X-Foo: =?'.$header->getCharset().'*en?Q?fo=8Fbar?=; says="=?'.$header->getCharset().'*en?Q?fo=8Fbar?="', $header->toString()); + } + + public function testSetBody() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setBody('text/plain'); + $this->assertEquals('text/plain', $header->getValue()); + } + + public function testGetBody() + { + $header = new ParameterizedHeader('Content-Type', 'text/plain'); + $this->assertEquals('text/plain', $header->getBody()); + } + + public function testSetParameter() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setParameters(['charset' => 'utf-8', 'delsp' => 'yes']); + $header->setParameter('delsp', 'no'); + $this->assertEquals(['charset' => 'utf-8', 'delsp' => 'no'], $header->getParameters()); + } + + public function testGetParameter() + { + $header = new ParameterizedHeader('Content-Type', 'text/html'); + $header->setParameters(['charset' => 'utf-8', 'delsp' => 'yes']); + $this->assertEquals('utf-8', $header->getParameter('charset')); + } +} diff --git a/vendor/symfony/mime/Tests/Header/PathHeaderTest.php b/vendor/symfony/mime/Tests/Header/PathHeaderTest.php new file mode 100644 index 0000000000..8f41959944 --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/PathHeaderTest.php @@ -0,0 +1,81 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\PathHeader; + +class PathHeaderTest extends TestCase +{ + public function testSingleAddressCanBeSetAndFetched() + { + $header = new PathHeader('Return-Path', $address = new Address('chris@swiftmailer.org')); + $this->assertEquals($address, $header->getAddress()); + } + + /** + * @expectedException \Exception + */ + public function testAddressMustComplyWithRfc2822() + { + $header = new PathHeader('Return-Path', new Address('chr is@swiftmailer.org')); + } + + public function testValueIsAngleAddrWithValidAddress() + { + /* -- RFC 2822, 3.6.7. + + return = "Return-Path:" path CRLF + + path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / + obs-path + */ + + $header = new PathHeader('Return-Path', new Address('chris@swiftmailer.org')); + $this->assertEquals('<chris@swiftmailer.org>', $header->getBodyAsString()); + } + + public function testAddressIsIdnEncoded() + { + $header = new PathHeader('Return-Path', new Address('chris@swïftmailer.org')); + $this->assertEquals('<chris@xn--swftmailer-78a.org>', $header->getBodyAsString()); + } + + /** + * @expectedException \Symfony\Component\Mime\Exception\AddressEncoderException + */ + public function testAddressMustBeEncodable() + { + $header = new PathHeader('Return-Path', new Address('chrïs@swiftmailer.org')); + $header->getBodyAsString(); + } + + public function testSetBody() + { + $header = new PathHeader('Return-Path', new Address('foo@example.com')); + $header->setBody($address = new Address('foo@bar.tld')); + $this->assertEquals($address, $header->getAddress()); + } + + public function testGetBody() + { + $header = new PathHeader('Return-Path', $address = new Address('foo@bar.tld')); + $this->assertEquals($address, $header->getBody()); + } + + public function testToString() + { + $header = new PathHeader('Return-Path', new Address('chris@swiftmailer.org')); + $this->assertEquals('Return-Path: <chris@swiftmailer.org>', $header->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/Header/UnstructuredHeaderTest.php b/vendor/symfony/mime/Tests/Header/UnstructuredHeaderTest.php new file mode 100644 index 0000000000..3e065bf268 --- /dev/null +++ b/vendor/symfony/mime/Tests/Header/UnstructuredHeaderTest.php @@ -0,0 +1,247 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Header; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\UnstructuredHeader; + +class UnstructuredHeaderTest extends TestCase +{ + private $charset = 'utf-8'; + + public function testGetNameReturnsNameVerbatim() + { + $header = new UnstructuredHeader('Subject', ''); + $this->assertEquals('Subject', $header->getName()); + } + + public function testGetValueReturnsValueVerbatim() + { + $header = new UnstructuredHeader('Subject', 'Test'); + $this->assertEquals('Test', $header->getValue()); + } + + public function testBasicStructureIsKeyValuePair() + { + /* -- RFC 2822, 2.2 + Header fields are lines composed of a field name, followed by a colon + (":"), followed by a field body, and terminated by CRLF. + */ + $header = new UnstructuredHeader('Subject', 'Test'); + $this->assertEquals('Subject: Test', $header->toString()); + } + + public function testLongHeadersAreFoldedAtWordBoundary() + { + /* -- RFC 2822, 2.2.3 + Each header field is logically a single line of characters comprising + the field name, the colon, and the field body. For convenience + however, and to deal with the 998/78 character limitations per line, + the field body portion of a header field can be split into a multiple + line representation; this is called "folding". The general rule is + that wherever this standard allows for folding white space (not + simply WSP characters), a CRLF may be inserted before any WSP. + */ + + $value = 'The quick brown fox jumped over the fence, he was a very very '. + 'scary brown fox with a bushy tail'; + $header = new UnstructuredHeader('X-Custom-Header', $value); + /* + X-Custom-Header: The quick brown fox jumped over the fence, he was a very very + scary brown fox with a bushy tail + */ + $this->assertEquals( + 'X-Custom-Header: The quick brown fox jumped over the fence, he was a'. + ' very'."\r\n".//Folding + ' very scary brown fox with a bushy tail', + $header->toString(), '%s: The header should have been folded at 76th char' + ); + } + + public function testPrintableAsciiOnlyAppearsInHeaders() + { + /* -- RFC 2822, 2.2. + A field name MUST be composed of printable US-ASCII characters (i.e., + characters that have values between 33 and 126, inclusive), except + colon. A field body may be composed of any US-ASCII characters, + except for CR and LF. + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $this->assertRegExp('~^[^:\x00-\x20\x80-\xFF]+: [^\x80-\xFF\r\n]+$~s', $header->toString()); + } + + public function testEncodedWordsFollowGeneralStructure() + { + /* -- RFC 2047, 1. + Generally, an "encoded-word" is a sequence of printable ASCII + characters that begins with "=?", ends with "?=", and has two "?"s in + between. + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $this->assertRegExp('~^X-Test: \=?.*?\?.*?\?.*?\?=$~s', $header->toString()); + } + + public function testEncodedWordIncludesCharsetAndEncodingMethodAndText() + { + /* -- RFC 2047, 2. + An 'encoded-word' is defined by the following ABNF grammar. The + notation of RFC 822 is used, with the exception that white space + characters MUST NOT appear between components of an 'encoded-word'. + + encoded-word = "=?" charset "?" encoding "?" encoded-text "?=" + */ + + $nonAsciiChar = pack('C', 0x8F); + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8F?=', $header->toString()); + } + + public function testEncodedWordsAreUsedToEncodedNonPrintableAscii() + { + // SPACE and TAB permitted + $nonPrintableBytes = array_merge(range(0x00, 0x08), range(0x10, 0x19), [0x7F]); + foreach ($nonPrintableBytes as $byte) { + $char = pack('C', $byte); + $encodedChar = sprintf('=%02X', $byte); + $header = new UnstructuredHeader('X-A', $char); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-A: =?'.$header->getCharset().'?Q?'.$encodedChar.'?=', $header->toString(), 'Non-printable ascii should be encoded'); + } + } + + public function testEncodedWordsAreUsedToEncode8BitOctets() + { + foreach (range(0x80, 0xFF) as $byte) { + $char = pack('C', $byte); + $encodedChar = sprintf('=%02X', $byte); + $header = new UnstructuredHeader('X-A', $char); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-A: =?'.$header->getCharset().'?Q?'.$encodedChar.'?=', $header->toString(), '8-bit octets should be encoded'); + } + } + + public function testEncodedWordsAreNoMoreThan75CharsPerLine() + { + /* -- RFC 2047, 2. + An 'encoded-word' may not be more than 75 characters long, including + 'charset', 'encoding', 'encoded-text', and delimiters. + + ... SNIP ... + + While there is no limit to the length of a multiple-line header + field, each line of a header field that contains one or more + 'encoded-word's is limited to 76 characters. + */ + + $nonAsciiChar = pack('C', 0x8F); + + //Note that multi-line headers begin with LWSP which makes 75 + 1 = 76 + //Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63 + + //* X-Test: is 8 chars + $header = new UnstructuredHeader('X-Test', $nonAsciiChar); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8F?=', $header->toString()); + } + + public function testFWSPIsUsedWhenEncoderReturnsMultipleLines() + { + /* --RFC 2047, 2. + If it is desirable to encode more text than will fit in an 'encoded-word' of + 75 characters, multiple 'encoded-word's (separated by CRLF SPACE) may + be used. + */ + + // Note that multi-line headers begin with LWSP which makes 75 + 1 = 76 + // Note also that =?utf-8?q??= is 12 chars which makes 75 - 12 = 63 + + //* X-Test: is 8 chars + $header = new UnstructuredHeader('X-Test', pack('C', 0x8F).'line_one_here'."\r\n".'line_two_here'); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: =?'.$header->getCharset().'?Q?=8Fline=5Fone=5Fhere?='."\r\n".' =?'.$header->getCharset().'?Q?line=5Ftwo=5Fhere?=', $header->toString()); + } + + public function testAdjacentWordsAreEncodedTogether() + { + /* -- RFC 2047, 5 (1) + Ordinary ASCII text and 'encoded-word's may appear together in the + same header field. However, an 'encoded-word' that appears in a + header field defined as '*text' MUST be separated from any adjacent + 'encoded-word' or 'text' by 'linear-white-space'. + + -- RFC 2047, 2. + IMPORTANT: 'encoded-word's are designed to be recognized as 'atom's + by an RFC 822 parser. As a consequence, unencoded white space + characters (such as SPACE and HTAB) are FORBIDDEN within an + 'encoded-word'. + */ + + // It would be valid to encode all words needed, however it's probably + // easiest to encode the longest amount required at a time + + $word = 'w'.pack('C', 0x8F).'rd'; + $text = 'start '.$word.' '.$word.' then '.$word; + // 'start', ' word word', ' and end', ' word' + + $header = new UnstructuredHeader('X-Test', $text); + $header->setCharset('iso-8859-1'); + $this->assertEquals('X-Test: start =?'.$header->getCharset().'?Q?'. + 'w=8Frd_w=8Frd?= then =?'.$header->getCharset().'?Q?'. + 'w=8Frd?=', $header->toString(), + 'Adjacent encoded words should appear grouped with WSP encoded' + ); + } + + public function testLanguageInformationAppearsInEncodedWords() + { + /* -- RFC 2231, 5. + 5. Language specification in Encoded Words + + RFC 2047 provides support for non-US-ASCII character sets in RFC 822 + message header comments, phrases, and any unstructured text field. + This is done by defining an encoded word construct which can appear + in any of these places. Given that these are fields intended for + display, it is sometimes necessary to associate language information + with encoded words as well as just the character set. This + specification extends the definition of an encoded word to allow the + inclusion of such information. This is simply done by suffixing the + character set specification with an asterisk followed by the language + tag. For example: + + From: =?US-ASCII*EN?Q?Keith_Moore?= <moore@cs.utk.edu> + */ + + $value = 'fo'.pack('C', 0x8F).'bar'; + $header = new UnstructuredHeader('Subject', $value); + $header->setLanguage('en'); + $header->setCharset('iso-8859-1'); + $this->assertEquals('Subject: =?iso-8859-1*en?Q?fo=8Fbar?=', $header->toString()); + } + + public function testSetBody() + { + $header = new UnstructuredHeader('X-Test', ''); + $header->setBody('test'); + $this->assertEquals('test', $header->getValue()); + } + + public function testGetBody() + { + $header = new UnstructuredHeader('Subject', 'test'); + $this->assertEquals('test', $header->getBody()); + } +} diff --git a/vendor/symfony/mime/Tests/MessageConverterTest.php b/vendor/symfony/mime/Tests/MessageConverterTest.php new file mode 100644 index 0000000000..6a78086246 --- /dev/null +++ b/vendor/symfony/mime/Tests/MessageConverterTest.php @@ -0,0 +1,81 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\MessageConverter; + +class MessageConverterTest extends TestCase +{ + public function testToEmail() + { + $file = file_get_contents(__DIR__.'/Fixtures/mimetypes/test.gif'); + $email = (new Email())->from('fabien@symfony.com'); + $this->assertSame($email, MessageConverter::toEmail($email)); + + $this->assertConversion((clone $email)->text('text content')); + $this->assertConversion((clone $email)->html('HTML content <img src="cid:test.jpg" />')); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content <img src="cid:test.jpg" />') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content <img src="cid:test.jpg" />') + ->embed($file, 'test.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content <img src="cid:test.jpg" />') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->html('HTML content <img src="cid:test.jpg" />') + ->embed($file, 'test.jpg', 'image/gif') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->html('HTML content <img src="cid:test.jpg" />') + ->attach($file, 'test_attached.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->html('HTML content <img src="cid:test.jpg" />') + ->embed($file, 'test.jpg', 'image/gif') + ); + $this->assertConversion((clone $email) + ->text('text content') + ->embed($file, 'test_attached.jpg', 'image/gif') + ); + } + + private function assertConversion(Email $expected) + { + $r = new \ReflectionMethod($expected, 'generateBody'); + $r->setAccessible(true); + + $message = new Message($expected->getHeaders(), $r->invoke($expected)); + $converted = MessageConverter::toEmail($message); + if ($expected->getHtmlBody()) { + $this->assertStringMatchesFormat(str_replace('cid:test.jpg', 'cid:%s', $expected->getHtmlBody()), $converted->getHtmlBody()); + $expected->html('HTML content'); + $converted->html('HTML content'); + } + $this->assertEquals($expected, $converted); + } +} diff --git a/vendor/symfony/mime/Tests/MessageTest.php b/vendor/symfony/mime/Tests/MessageTest.php new file mode 100644 index 0000000000..dbeb0a5544 --- /dev/null +++ b/vendor/symfony/mime/Tests/MessageTest.php @@ -0,0 +1,151 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\MailboxListHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\NamedAddress; +use Symfony\Component\Mime\Part\TextPart; + +class MessageTest extends TestCase +{ + public function testConstruct() + { + $m = new Message(); + $this->assertNull($m->getBody()); + $this->assertEquals(new Headers(), $m->getHeaders()); + + $m = new Message($h = (new Headers())->addDateHeader('Date', new \DateTime()), $b = new TextPart('content')); + $this->assertSame($b, $m->getBody()); + $this->assertEquals($h, $m->getHeaders()); + + $m = new Message(); + $m->setBody($b); + $m->setHeaders($h); + $this->assertSame($b, $m->getBody()); + $this->assertSame($h, $m->getHeaders()); + } + + public function testGetPreparedHeadersThrowsWhenNoFrom() + { + $this->expectException(\LogicException::class); + (new Message())->getPreparedHeaders(); + } + + public function testGetPreparedHeadersCloneHeaders() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $this->assertNotSame($message->getPreparedHeaders(), $message->getHeaders()); + } + + public function testGetPreparedHeadersSetRequiredHeaders() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $headers = $message->getPreparedHeaders(); + $this->assertTrue($headers->has('MIME-Version')); + $this->assertTrue($headers->has('Message-ID')); + $this->assertTrue($headers->has('Date')); + $this->assertFalse($headers->has('Bcc')); + } + + public function testGetPreparedHeaders() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $h = $message->getPreparedHeaders(); + $this->assertCount(4, iterator_to_array($h->getAll())); + $this->assertEquals(new MailboxListHeader('From', [new Address('fabien@symfony.com')]), $h->get('From')); + $this->assertEquals(new UnstructuredHeader('MIME-Version', '1.0'), $h->get('mime-version')); + $this->assertTrue($h->has('Message-Id')); + $this->assertTrue($h->has('Date')); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $message->getHeaders()->addDateHeader('Date', $n = new \DateTimeImmutable()); + $this->assertEquals($n, $message->getPreparedHeaders()->get('Date')->getDateTime()); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $message->getHeaders()->addMailboxListHeader('Bcc', ['fabien@symfony.com']); + $this->assertNull($message->getPreparedHeaders()->get('Bcc')); + } + + public function testGetPreparedHeadersWithNoFrom() + { + $this->expectException(\LogicException::class); + (new Message())->getPreparedHeaders(); + } + + public function testGetPreparedHeadersWithNamedFrom() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', [new NamedAddress('fabien@symfony.com', 'Fabien')]); + $h = $message->getPreparedHeaders(); + $this->assertEquals(new MailboxListHeader('From', [new NamedAddress('fabien@symfony.com', 'Fabien')]), $h->get('From')); + $this->assertTrue($h->has('Message-Id')); + } + + public function testGetPreparedHeadersHasSenderWhenNeeded() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $this->assertNull($message->getPreparedHeaders()->get('Sender')); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com', 'lucas@symfony.com']); + $this->assertEquals('fabien@symfony.com', $message->getPreparedHeaders()->get('Sender')->getAddress()->getAddress()); + + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com', 'lucas@symfony.com']); + $message->getHeaders()->addMailboxHeader('Sender', 'thomas@symfony.com'); + $this->assertEquals('thomas@symfony.com', $message->getPreparedHeaders()->get('Sender')->getAddress()->getAddress()); + } + + public function testToString() + { + $message = new Message(); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $expected = <<<EOF +From: fabien@symfony.com +MIME-Version: 1.0 +Date: %s +Message-ID: <%s@symfony.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + + +EOF; + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", $message->toString())); + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable(), false)))); + + $message = new Message(null, new TextPart('content')); + $message->getHeaders()->addMailboxListHeader('From', ['fabien@symfony.com']); + $expected = <<<EOF +From: fabien@symfony.com +MIME-Version: 1.0 +Date: %s +Message-ID: <%s@symfony.com> +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: quoted-printable + +content +EOF; + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", $message->toString())); + $this->assertStringMatchesFormat($expected, str_replace("\r\n", "\n", implode('', iterator_to_array($message->toIterable(), false)))); + } +} diff --git a/vendor/symfony/mime/Tests/MimeTypesTest.php b/vendor/symfony/mime/Tests/MimeTypesTest.php new file mode 100644 index 0000000000..c5ff262b80 --- /dev/null +++ b/vendor/symfony/mime/Tests/MimeTypesTest.php @@ -0,0 +1,61 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use Symfony\Component\Mime\Exception\RuntimeException; +use Symfony\Component\Mime\MimeTypeGuesserInterface; +use Symfony\Component\Mime\MimeTypes; + +/** + * @requires extension fileinfo + */ +class MimeTypesTest extends AbstractMimeTypeGuesserTest +{ + protected function getGuesser(): MimeTypeGuesserInterface + { + return new MimeTypes(); + } + + public function testUnsupportedGuesser() + { + $guesser = $this->getGuesser(); + $guesser->registerGuesser(new class() implements MimeTypeGuesserInterface { + public function isGuesserSupported(): bool + { + return false; + } + + public function guessMimeType(string $mimeType): ?string + { + throw new RuntimeException('Should never be called.'); + } + }); + $this->assertEquals('image/gif', $guesser->guessMimeType(__DIR__.'/Fixtures/mimetypes/test')); + } + + public function testGetExtensions() + { + $mt = new MimeTypes(); + $this->assertSame(['mbox'], $mt->getExtensions('application/mbox')); + $this->assertSame(['ai', 'eps', 'ps'], $mt->getExtensions('application/postscript')); + $this->assertSame([], $mt->getExtensions('application/whatever-symfony')); + } + + public function testGetMimeTypes() + { + $mt = new MimeTypes(); + $this->assertSame(['application/mbox'], $mt->getMimeTypes('mbox')); + $this->assertContains('application/postscript', $mt->getMimeTypes('ai')); + $this->assertContains('application/postscript', $mt->getMimeTypes('ps')); + $this->assertSame([], $mt->getMimeTypes('symfony')); + } +} diff --git a/vendor/symfony/mime/Tests/NamedAddressTest.php b/vendor/symfony/mime/Tests/NamedAddressTest.php new file mode 100644 index 0000000000..72840191d5 --- /dev/null +++ b/vendor/symfony/mime/Tests/NamedAddressTest.php @@ -0,0 +1,27 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\NamedAddress; + +class NamedAddressTest extends TestCase +{ + public function testConstructor() + { + $a = new NamedAddress('fabien@symfonï.com', 'Fabien'); + $this->assertEquals('Fabien', $a->getName()); + $this->assertEquals('fabien@symfonï.com', $a->getAddress()); + $this->assertEquals('Fabien <fabien@xn--symfon-nwa.com>', $a->toString()); + $this->assertEquals('fabien@xn--symfon-nwa.com', $a->getEncodedAddress()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/DataPartTest.php b/vendor/symfony/mime/Tests/Part/DataPartTest.php new file mode 100644 index 0000000000..d8a08a2430 --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/DataPartTest.php @@ -0,0 +1,149 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\IdentificationHeader; +use Symfony\Component\Mime\Header\ParameterizedHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Part\DataPart; + +class DataPartTest extends TestCase +{ + public function testConstructor() + { + $p = new DataPart('content'); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals(base64_encode('content'), $p->bodyToString()); + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + // bodyToIterable() can be called several times + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('application', $p->getMediaType()); + $this->assertEquals('octet-stream', $p->getMediaSubType()); + + $p = new DataPart('content', null, 'text/html'); + $this->assertEquals('text', $p->getMediaType()); + $this->assertEquals('html', $p->getMediaSubType()); + } + + public function testConstructorWithResource() + { + $f = fopen('php://memory', 'r+', false); + fwrite($f, 'content'); + rewind($f); + $p = new DataPart($f); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals(base64_encode('content'), $p->bodyToString()); + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + fclose($f); + } + + public function testConstructorWithNonStringOrResource() + { + $this->expectException(\TypeError::class); + new DataPart(new \stdClass()); + } + + public function testHeaders() + { + $p = new DataPart('content'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'application/octet-stream'), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment') + ), $p->getPreparedHeaders()); + + $p = new DataPart('content', 'photo.jpg', 'text/html'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/html', ['name' => 'photo.jpg']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'photo.jpg', 'filename' => 'photo.jpg']) + ), $p->getPreparedHeaders()); + } + + public function testAsInline() + { + $p = new DataPart('content', 'photo.jpg', 'text/html'); + $p->asInline(); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/html', ['name' => 'photo.jpg']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'inline', ['name' => 'photo.jpg', 'filename' => 'photo.jpg']) + ), $p->getPreparedHeaders()); + } + + public function testAsInlineWithCID() + { + $p = new DataPart('content', 'photo.jpg', 'text/html'); + $p->asInline(); + $cid = $p->getContentId(); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/html', ['name' => 'photo.jpg']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'inline', ['name' => 'photo.jpg', 'filename' => 'photo.jpg']), + new IdentificationHeader('Content-ID', $cid) + ), $p->getPreparedHeaders()); + } + + public function testFromPath() + { + $p = DataPart::fromPath($file = __DIR__.'/../Fixtures/mimetypes/test.gif'); + $content = file_get_contents($file); + $this->assertEquals($content, $p->getBody()); + $this->assertEquals(base64_encode($content), $p->bodyToString()); + $this->assertEquals(base64_encode($content), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('image', $p->getMediaType()); + $this->assertEquals('gif', $p->getMediaSubType()); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'image/gif', ['name' => 'test.gif']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'test.gif', 'filename' => 'test.gif']) + ), $p->getPreparedHeaders()); + } + + public function testFromPathWithMeta() + { + $p = DataPart::fromPath($file = __DIR__.'/../Fixtures/mimetypes/test.gif', 'photo.gif', 'image/jpeg'); + $content = file_get_contents($file); + $this->assertEquals($content, $p->getBody()); + $this->assertEquals(base64_encode($content), $p->bodyToString()); + $this->assertEquals(base64_encode($content), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('image', $p->getMediaType()); + $this->assertEquals('jpeg', $p->getMediaSubType()); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'image/jpeg', ['name' => 'photo.gif']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'photo.gif', 'filename' => 'photo.gif']) + ), $p->getPreparedHeaders()); + } + + public function testHasContentId() + { + $p = new DataPart('content'); + $this->assertFalse($p->hasContentId()); + $p->getContentId(); + $this->assertTrue($p->hasContentId()); + } + + public function testSerialize() + { + $r = fopen('php://memory', 'r+', false); + fwrite($r, 'Text content'); + rewind($r); + + $p = new DataPart($r); + $p->getHeaders()->addTextHeader('foo', 'bar'); + $expected = clone $p; + $this->assertEquals($expected->toString(), unserialize(serialize($p))->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/MessagePartTest.php b/vendor/symfony/mime/Tests/Part/MessagePartTest.php new file mode 100644 index 0000000000..3855e085c4 --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/MessagePartTest.php @@ -0,0 +1,42 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Email; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\ParameterizedHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Part\MessagePart; + +class MessagePartTest extends TestCase +{ + public function testConstructor() + { + $p = new MessagePart((new Email())->from('fabien@symfony.com')->text('content')); + $this->assertContains('content', $p->getBody()); + $this->assertContains('content', $p->bodyToString()); + $this->assertContains('content', implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('message', $p->getMediaType()); + $this->assertEquals('rfc822', $p->getMediaSubType()); + } + + public function testHeaders() + { + $p = new MessagePart((new Email())->from('fabien@symfony.com')->text('content')->subject('Subject')); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'message/rfc822', ['name' => 'Subject.eml']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64'), + new ParameterizedHeader('Content-Disposition', 'attachment', ['name' => 'Subject.eml', 'filename' => 'Subject.eml']) + ), $p->getPreparedHeaders()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/Multipart/AlternativePartTest.php b/vendor/symfony/mime/Tests/Part/Multipart/AlternativePartTest.php new file mode 100644 index 0000000000..2dbc1315ef --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/Multipart/AlternativePartTest.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\Multipart\AlternativePart; + +class AlternativePartTest extends TestCase +{ + public function testConstructor() + { + $a = new AlternativePart(); + $this->assertEquals('multipart', $a->getMediaType()); + $this->assertEquals('alternative', $a->getMediaSubtype()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/Multipart/DigestPartTest.php b/vendor/symfony/mime/Tests/Part/Multipart/DigestPartTest.php new file mode 100644 index 0000000000..82738efbc5 --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/Multipart/DigestPartTest.php @@ -0,0 +1,28 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\Part\MessagePart; +use Symfony\Component\Mime\Part\Multipart\DigestPart; + +class DigestPartTest extends TestCase +{ + public function testConstructor() + { + $r = new DigestPart($a = new MessagePart(new Message()), $b = new MessagePart(new Message())); + $this->assertEquals('multipart', $r->getMediaType()); + $this->assertEquals('digest', $r->getMediaSubtype()); + $this->assertEquals([$a, $b], $r->getParts()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/Multipart/FormDataPartTest.php b/vendor/symfony/mime/Tests/Part/Multipart/FormDataPartTest.php new file mode 100644 index 0000000000..127fce000a --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/Multipart/FormDataPartTest.php @@ -0,0 +1,66 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\DataPart; +use Symfony\Component\Mime\Part\Multipart\FormDataPart; +use Symfony\Component\Mime\Part\TextPart; + +class FormDataPartTest extends TestCase +{ + public function testConstructor() + { + $r = new \ReflectionProperty(TextPart::class, 'encoding'); + $r->setAccessible(true); + + $b = new TextPart('content'); + $c = DataPart::fromPath($file = __DIR__.'/../../Fixtures/mimetypes/test.gif'); + $f = new FormDataPart([ + 'foo' => $content = 'very very long content that will not be cut even if the length i way more than 76 characters, ok?', + 'bar' => clone $b, + 'baz' => clone $c, + ]); + $this->assertEquals('multipart', $f->getMediaType()); + $this->assertEquals('form-data', $f->getMediaSubtype()); + $t = new TextPart($content, 'utf-8', 'plain', '8bit'); + $t->setDisposition('form-data'); + $t->setName('foo'); + $t->getHeaders()->setMaxLineLength(PHP_INT_MAX); + $b->setDisposition('form-data'); + $b->setName('bar'); + $b->getHeaders()->setMaxLineLength(PHP_INT_MAX); + $r->setValue($b, '8bit'); + $c->setDisposition('form-data'); + $c->setName('baz'); + $c->getHeaders()->setMaxLineLength(PHP_INT_MAX); + $r->setValue($c, '8bit'); + $this->assertEquals([$t, $b, $c], $f->getParts()); + } + + public function testToString() + { + $p = DataPart::fromPath($file = __DIR__.'/../../Fixtures/mimetypes/test.gif'); + $this->assertEquals(base64_encode(file_get_contents($file)), $p->bodyToString()); + } + + public function testContentLineLength() + { + $f = new FormDataPart([ + 'foo' => new DataPart($foo = str_repeat('foo', 1000), 'foo.txt', 'text/plain'), + 'bar' => $bar = str_repeat('bar', 1000), + ]); + $parts = $f->getParts(); + $this->assertEquals($foo, $parts[0]->bodyToString()); + $this->assertEquals($bar, $parts[1]->bodyToString()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/Multipart/MixedPartTest.php b/vendor/symfony/mime/Tests/Part/Multipart/MixedPartTest.php new file mode 100644 index 0000000000..3ff02ee6ca --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/Multipart/MixedPartTest.php @@ -0,0 +1,25 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\Multipart\MixedPart; + +class MixedPartTest extends TestCase +{ + public function testConstructor() + { + $a = new MixedPart(); + $this->assertEquals('multipart', $a->getMediaType()); + $this->assertEquals('mixed', $a->getMediaSubtype()); + } +} diff --git a/vendor/symfony/mime/Tests/Part/Multipart/RelatedPartTest.php b/vendor/symfony/mime/Tests/Part/Multipart/RelatedPartTest.php new file mode 100644 index 0000000000..2a5a7bed97 --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/Multipart/RelatedPartTest.php @@ -0,0 +1,30 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part\Multipart; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Part\Multipart\RelatedPart; +use Symfony\Component\Mime\Part\TextPart; + +class RelatedPartTest extends TestCase +{ + public function testConstructor() + { + $r = new RelatedPart($a = new TextPart('content'), $b = new TextPart('HTML content', 'utf-8', 'html'), $c = new TextPart('HTML content again', 'utf-8', 'html')); + $this->assertEquals('multipart', $r->getMediaType()); + $this->assertEquals('related', $r->getMediaSubtype()); + $this->assertEquals([$a, $b, $c], $r->getParts()); + $this->assertFalse($a->getHeaders()->has('Content-ID')); + $this->assertTrue($b->getHeaders()->has('Content-ID')); + $this->assertTrue($c->getHeaders()->has('Content-ID')); + } +} diff --git a/vendor/symfony/mime/Tests/Part/TextPartTest.php b/vendor/symfony/mime/Tests/Part/TextPartTest.php new file mode 100644 index 0000000000..c3818b883d --- /dev/null +++ b/vendor/symfony/mime/Tests/Part/TextPartTest.php @@ -0,0 +1,92 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests\Part; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\ParameterizedHeader; +use Symfony\Component\Mime\Header\UnstructuredHeader; +use Symfony\Component\Mime\Part\TextPart; + +class TextPartTest extends TestCase +{ + public function testConstructor() + { + $p = new TextPart('content'); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals('content', $p->bodyToString()); + $this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable()))); + // bodyToIterable() can be called several times + $this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals('text', $p->getMediaType()); + $this->assertEquals('plain', $p->getMediaSubType()); + + $p = new TextPart('content', null, 'html'); + $this->assertEquals('html', $p->getMediaSubType()); + } + + public function testConstructorWithResource() + { + $f = fopen('php://memory', 'r+', false); + fwrite($f, 'content'); + rewind($f); + $p = new TextPart($f); + $this->assertEquals('content', $p->getBody()); + $this->assertEquals('content', $p->bodyToString()); + $this->assertEquals('content', implode('', iterator_to_array($p->bodyToIterable()))); + fclose($f); + } + + public function testConstructorWithNonStringOrResource() + { + $this->expectException(\TypeError::class); + new TextPart(new \stdClass()); + } + + public function testHeaders() + { + $p = new TextPart('content'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']), + new UnstructuredHeader('Content-Transfer-Encoding', 'quoted-printable') + ), $p->getPreparedHeaders()); + + $p = new TextPart('content', 'iso-8859-1'); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'iso-8859-1']), + new UnstructuredHeader('Content-Transfer-Encoding', 'quoted-printable') + ), $p->getPreparedHeaders()); + } + + public function testEncoding() + { + $p = new TextPart('content', 'utf-8', 'plain', 'base64'); + $this->assertEquals(base64_encode('content'), $p->bodyToString()); + $this->assertEquals(base64_encode('content'), implode('', iterator_to_array($p->bodyToIterable()))); + $this->assertEquals(new Headers( + new ParameterizedHeader('Content-Type', 'text/plain', ['charset' => 'utf-8']), + new UnstructuredHeader('Content-Transfer-Encoding', 'base64') + ), $p->getPreparedHeaders()); + } + + public function testSerialize() + { + $r = fopen('php://memory', 'r+', false); + fwrite($r, 'Text content'); + rewind($r); + + $p = new TextPart($r); + $p->getHeaders()->addTextHeader('foo', 'bar'); + $expected = clone $p; + $this->assertEquals($expected->toString(), unserialize(serialize($p))->toString()); + } +} diff --git a/vendor/symfony/mime/Tests/RawMessageTest.php b/vendor/symfony/mime/Tests/RawMessageTest.php new file mode 100644 index 0000000000..5d1588bff0 --- /dev/null +++ b/vendor/symfony/mime/Tests/RawMessageTest.php @@ -0,0 +1,35 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Mime\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Mime\RawMessage; + +class RawMessageTest extends TestCase +{ + public function testToString() + { + $message = new RawMessage('string'); + $this->assertEquals('string', $message->toString()); + $this->assertEquals('string', implode('', iterator_to_array($message->toIterable()))); + // calling methods more than once work + $this->assertEquals('string', $message->toString()); + $this->assertEquals('string', implode('', iterator_to_array($message->toIterable()))); + + $message = new RawMessage(new \ArrayObject(['some', ' ', 'string'])); + $this->assertEquals('some string', $message->toString()); + $this->assertEquals('some string', implode('', iterator_to_array($message->toIterable()))); + // calling methods more than once work + $this->assertEquals('some string', $message->toString()); + $this->assertEquals('some string', implode('', iterator_to_array($message->toIterable()))); + } +} diff --git a/vendor/symfony/mime/composer.json b/vendor/symfony/mime/composer.json new file mode 100644 index 0000000000..f1d2f0975c --- /dev/null +++ b/vendor/symfony/mime/composer.json @@ -0,0 +1,39 @@ +{ + "name": "symfony/mime", + "type": "library", + "description": "A library to manipulate MIME messages", + "keywords": ["mime", "mime-type"], + "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", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "require-dev": { + "egulias/email-validator": "^2.0", + "symfony/dependency-injection": "~3.4|^4.1" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\Mime\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.3-dev" + } + } +} diff --git a/vendor/symfony/contracts/phpunit.xml.dist b/vendor/symfony/mime/phpunit.xml.dist index e222d9f5a7..a1c68d0e5f 100644 --- a/vendor/symfony/contracts/phpunit.xml.dist +++ b/vendor/symfony/mime/phpunit.xml.dist @@ -13,7 +13,7 @@ </php> <testsuites> - <testsuite name="Symfony Contracts Test Suite"> + <testsuite name="Symfony MIME Component Test Suite"> <directory>./Tests/</directory> </testsuite> </testsuites> @@ -22,10 +22,10 @@ <whitelist> <directory>./</directory> <exclude> + <directory>./Resources</directory> <directory>./Tests</directory> <directory>./vendor</directory> </exclude> </whitelist> </filter> - </phpunit> diff --git a/vendor/symfony/polyfill-php73/LICENSE b/vendor/symfony/polyfill-php73/LICENSE new file mode 100644 index 0000000000..3f853aaf35 --- /dev/null +++ b/vendor/symfony/polyfill-php73/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-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-php73/Php73.php b/vendor/symfony/polyfill-php73/Php73.php new file mode 100644 index 0000000000..aa3708f64f --- /dev/null +++ b/vendor/symfony/polyfill-php73/Php73.php @@ -0,0 +1,34 @@ +<?php + +namespace Symfony\Polyfill\Php73; + +/** + * @author Gabriel Caruso <carusogabriel34@gmail.com> + * @author Ion Bazan <ion.bazan@gmail.com> + * + * @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 array($s, (int) $ns); + } +} diff --git a/vendor/symfony/polyfill-php73/README.md b/vendor/symfony/polyfill-php73/README.md new file mode 100644 index 0000000000..b3ebbce511 --- /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/master/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 0000000000..673d100224 --- /dev/null +++ b/vendor/symfony/polyfill-php73/Resources/stubs/JsonException.php @@ -0,0 +1,14 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +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 0000000000..049b8bb8aa --- /dev/null +++ b/vendor/symfony/polyfill-php73/bootstrap.php @@ -0,0 +1,31 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * 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) { + if (!function_exists('is_countable')) { + function is_countable($var) { return is_array($var) || $var instanceof Countable || $var instanceof ResourceBundle || $var instanceof SimpleXmlElement; } + } + + if (!function_exists('hrtime')) { + p\Php73::$startAt = (int) microtime(true); + function hrtime($asNum = false) { return p\Php73::hrtime($asNum); } + } + + 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) { end($array); return key($array); } + } +} diff --git a/vendor/symfony/polyfill-php73/composer.json b/vendor/symfony/polyfill-php73/composer.json new file mode 100644 index 0000000000..e98167ed51 --- /dev/null +++ b/vendor/symfony/polyfill-php73/composer.json @@ -0,0 +1,32 @@ +{ + "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": ">=5.3.3" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php73\\": "" }, + "files": [ "bootstrap.php" ], + "classmap": [ "Resources/stubs" ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.11-dev" + } + } +} diff --git a/vendor/symfony/service-contracts/LICENSE b/vendor/symfony/service-contracts/LICENSE new file mode 100644 index 0000000000..3f853aaf35 --- /dev/null +++ b/vendor/symfony/service-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-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/service-contracts/README.md b/vendor/symfony/service-contracts/README.md new file mode 100644 index 0000000000..d033a439b9 --- /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/master/README.md for more information. diff --git a/vendor/symfony/contracts/Service/ResetInterface.php b/vendor/symfony/service-contracts/ResetInterface.php index 1af1075eee..1af1075eee 100644 --- a/vendor/symfony/contracts/Service/ResetInterface.php +++ b/vendor/symfony/service-contracts/ResetInterface.php diff --git a/vendor/symfony/contracts/Service/ServiceLocatorTrait.php b/vendor/symfony/service-contracts/ServiceLocatorTrait.php index 71b1b7460d..71b1b7460d 100644 --- a/vendor/symfony/contracts/Service/ServiceLocatorTrait.php +++ b/vendor/symfony/service-contracts/ServiceLocatorTrait.php diff --git a/vendor/symfony/contracts/Service/ServiceProviderInterface.php b/vendor/symfony/service-contracts/ServiceProviderInterface.php index c60ad0bd4b..c60ad0bd4b 100644 --- a/vendor/symfony/contracts/Service/ServiceProviderInterface.php +++ b/vendor/symfony/service-contracts/ServiceProviderInterface.php diff --git a/vendor/symfony/contracts/Service/ServiceSubscriberInterface.php b/vendor/symfony/service-contracts/ServiceSubscriberInterface.php index 8bb320f5b3..8bb320f5b3 100644 --- a/vendor/symfony/contracts/Service/ServiceSubscriberInterface.php +++ b/vendor/symfony/service-contracts/ServiceSubscriberInterface.php diff --git a/vendor/symfony/contracts/Service/ServiceSubscriberTrait.php b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php index ceaef6fa14..ceaef6fa14 100644 --- a/vendor/symfony/contracts/Service/ServiceSubscriberTrait.php +++ b/vendor/symfony/service-contracts/ServiceSubscriberTrait.php diff --git a/vendor/symfony/contracts/Tests/Service/ServiceLocatorTest.php b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php index 22487a8992..69594583f5 100644 --- a/vendor/symfony/contracts/Tests/Service/ServiceLocatorTest.php +++ b/vendor/symfony/service-contracts/Test/ServiceLocatorTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\Tests\Service; +namespace Symfony\Contracts\Service\Test; use PHPUnit\Framework\TestCase; use Psr\Container\ContainerInterface; diff --git a/vendor/symfony/service-contracts/composer.json b/vendor/symfony/service-contracts/composer.json new file mode 100644 index 0000000000..54341174ce --- /dev/null +++ b/vendor/symfony/service-contracts/composer.json @@ -0,0 +1,34 @@ +{ + "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.1.3" + }, + "suggest": { + "psr/container": "", + "symfony/service-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Service\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + } +} diff --git a/vendor/symfony/translation-contracts/LICENSE b/vendor/symfony/translation-contracts/LICENSE new file mode 100644 index 0000000000..3f853aaf35 --- /dev/null +++ b/vendor/symfony/translation-contracts/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2018-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/contracts/Translation/LocaleAwareInterface.php b/vendor/symfony/translation-contracts/LocaleAwareInterface.php index dbd8894fe7..dbd8894fe7 100644 --- a/vendor/symfony/contracts/Translation/LocaleAwareInterface.php +++ b/vendor/symfony/translation-contracts/LocaleAwareInterface.php diff --git a/vendor/symfony/translation-contracts/README.md b/vendor/symfony/translation-contracts/README.md new file mode 100644 index 0000000000..6c693ce0b3 --- /dev/null +++ b/vendor/symfony/translation-contracts/README.md @@ -0,0 +1,9 @@ +Symfony Translation 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/master/README.md for more information. diff --git a/vendor/symfony/contracts/Tests/Translation/TranslatorTest.php b/vendor/symfony/translation-contracts/Test/TranslatorTest.php index ac5f9c7aeb..48466300b5 100644 --- a/vendor/symfony/contracts/Tests/Translation/TranslatorTest.php +++ b/vendor/symfony/translation-contracts/Test/TranslatorTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Contracts\Tests\Translation; +namespace Symfony\Contracts\Translation\Test; use PHPUnit\Framework\TestCase; use Symfony\Contracts\Translation\TranslatorInterface; diff --git a/vendor/symfony/contracts/Translation/TranslatorInterface.php b/vendor/symfony/translation-contracts/TranslatorInterface.php index d867637370..d867637370 100644 --- a/vendor/symfony/contracts/Translation/TranslatorInterface.php +++ b/vendor/symfony/translation-contracts/TranslatorInterface.php diff --git a/vendor/symfony/contracts/Translation/TranslatorTrait.php b/vendor/symfony/translation-contracts/TranslatorTrait.php index c1021923c8..c1021923c8 100644 --- a/vendor/symfony/contracts/Translation/TranslatorTrait.php +++ b/vendor/symfony/translation-contracts/TranslatorTrait.php diff --git a/vendor/symfony/translation-contracts/composer.json b/vendor/symfony/translation-contracts/composer.json new file mode 100644 index 0000000000..09749d35f5 --- /dev/null +++ b/vendor/symfony/translation-contracts/composer.json @@ -0,0 +1,33 @@ +{ + "name": "symfony/translation-contracts", + "type": "library", + "description": "Generic abstractions related to translation", + "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": { + "symfony/translation-implementation": "" + }, + "autoload": { + "psr-4": { "Symfony\\Contracts\\Translation\\": "" } + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + } +} diff --git a/vendor/symfony/translation/CHANGELOG.md b/vendor/symfony/translation/CHANGELOG.md index 87eb2fa4a3..c80716838b 100644 --- a/vendor/symfony/translation/CHANGELOG.md +++ b/vendor/symfony/translation/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +4.3.0 +----- + + * Improved Xliff 1.2 loader to load the original file's metadata + * Added `TranslatorPathsPass` + 4.2.0 ----- diff --git a/vendor/symfony/translation/DataCollectorTranslator.php b/vendor/symfony/translation/DataCollectorTranslator.php index 68200a7f45..0284b77e9b 100644 --- a/vendor/symfony/translation/DataCollectorTranslator.php +++ b/vendor/symfony/translation/DataCollectorTranslator.php @@ -68,10 +68,10 @@ class DataCollectorTranslator implements LegacyTranslatorInterface, TranslatorIn { if ($this->translator instanceof TranslatorInterface) { $trans = $this->translator->trans($id, ['%count%' => $number] + $parameters, $domain, $locale); + } else { + $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale); } - $trans = $this->translator->transChoice($id, $number, $parameters, $domain, $locale); - $this->collectMessage($locale, $domain, $id, $trans, ['%count%' => $number] + $parameters); return $trans; diff --git a/vendor/symfony/translation/DependencyInjection/TranslatorPass.php b/vendor/symfony/translation/DependencyInjection/TranslatorPass.php index fc1c08fc32..ed4a840d86 100644 --- a/vendor/symfony/translation/DependencyInjection/TranslatorPass.php +++ b/vendor/symfony/translation/DependencyInjection/TranslatorPass.php @@ -68,12 +68,22 @@ class TranslatorPass implements CompilerPassInterface return; } + $paths = array_keys($container->getDefinition('twig.template_iterator')->getArgument(2)); if ($container->hasDefinition($this->debugCommandServiceId)) { - $container->getDefinition($this->debugCommandServiceId)->replaceArgument(4, $container->getParameter('twig.default_path')); - } + $definition = $container->getDefinition($this->debugCommandServiceId); + $definition->replaceArgument(4, $container->getParameter('twig.default_path')); + if (\count($definition->getArguments()) > 6) { + $definition->replaceArgument(6, $paths); + } + } if ($container->hasDefinition($this->updateCommandServiceId)) { - $container->getDefinition($this->updateCommandServiceId)->replaceArgument(5, $container->getParameter('twig.default_path')); + $definition = $container->getDefinition($this->updateCommandServiceId); + $definition->replaceArgument(5, $container->getParameter('twig.default_path')); + + if (\count($definition->getArguments()) > 7) { + $definition->replaceArgument(7, $paths); + } } } } diff --git a/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php b/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php new file mode 100644 index 0000000000..d9fc71911f --- /dev/null +++ b/vendor/symfony/translation/DependencyInjection/TranslatorPathsPass.php @@ -0,0 +1,144 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\AbstractRecursivePass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; + +/** + * @author Yonel Ceruto <yonelceruto@gmail.com> + */ +class TranslatorPathsPass extends AbstractRecursivePass +{ + private $translatorServiceId; + private $debugCommandServiceId; + private $updateCommandServiceId; + private $resolverServiceId; + private $level = 0; + private $paths = []; + private $definitions = []; + private $controllers = []; + + public function __construct(string $translatorServiceId = 'translator', string $debugCommandServiceId = 'console.command.translation_debug', string $updateCommandServiceId = 'console.command.translation_update', string $resolverServiceId = 'argument_resolver.service') + { + $this->translatorServiceId = $translatorServiceId; + $this->debugCommandServiceId = $debugCommandServiceId; + $this->updateCommandServiceId = $updateCommandServiceId; + $this->resolverServiceId = $resolverServiceId; + } + + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->translatorServiceId)) { + return; + } + + foreach ($this->findControllerArguments($container) as $controller => $argument) { + $id = \substr($controller, 0, \strpos($controller, ':') ?: \strlen($controller)); + if ($container->hasDefinition($id)) { + list($locatorRef) = $argument->getValues(); + $this->controllers[(string) $locatorRef][$container->getDefinition($id)->getClass()] = true; + } + } + + try { + parent::process($container); + + $paths = []; + foreach ($this->paths as $class => $_) { + if (($r = $container->getReflectionClass($class)) && !$r->isInterface()) { + $paths[] = $r->getFileName(); + } + } + if ($paths) { + if ($container->hasDefinition($this->debugCommandServiceId)) { + $definition = $container->getDefinition($this->debugCommandServiceId); + $definition->replaceArgument(6, array_merge($definition->getArgument(6), $paths)); + } + if ($container->hasDefinition($this->updateCommandServiceId)) { + $definition = $container->getDefinition($this->updateCommandServiceId); + $definition->replaceArgument(7, array_merge($definition->getArgument(7), $paths)); + } + } + } finally { + $this->level = 0; + $this->paths = []; + $this->definitions = []; + } + } + + protected function processValue($value, $isRoot = false) + { + if ($value instanceof Reference) { + if ((string) $value === $this->translatorServiceId) { + for ($i = $this->level - 1; $i >= 0; --$i) { + $class = $this->definitions[$i]->getClass(); + + if (ServiceLocator::class === $class) { + if (!isset($this->controllers[$this->currentId])) { + continue; + } + foreach ($this->controllers[$this->currentId] as $class => $_) { + $this->paths[$class] = true; + } + } else { + $this->paths[$class] = true; + } + + break; + } + } + + return $value; + } + + if ($value instanceof Definition) { + $this->definitions[$this->level++] = $value; + $value = parent::processValue($value, $isRoot); + unset($this->definitions[--$this->level]); + + return $value; + } + + return parent::processValue($value, $isRoot); + } + + private function findControllerArguments(ContainerBuilder $container): array + { + if ($container->hasDefinition($this->resolverServiceId)) { + $argument = $container->getDefinition($this->resolverServiceId)->getArgument(0); + if ($argument instanceof Reference) { + $argument = $container->getDefinition($argument); + } + + return $argument->getArgument(0); + } + + if ($container->hasDefinition('debug.'.$this->resolverServiceId)) { + $argument = $container->getDefinition('debug.'.$this->resolverServiceId)->getArgument(0); + if ($argument instanceof Reference) { + $argument = $container->getDefinition($argument); + } + $argument = $argument->getArgument(0); + if ($argument instanceof Reference) { + $argument = $container->getDefinition($argument); + } + + return $argument->getArgument(0); + } + + return []; + } +} diff --git a/vendor/symfony/translation/Dumper/PoFileDumper.php b/vendor/symfony/translation/Dumper/PoFileDumper.php index 0f7e6fa834..5f60086285 100644 --- a/vendor/symfony/translation/Dumper/PoFileDumper.php +++ b/vendor/symfony/translation/Dumper/PoFileDumper.php @@ -39,6 +39,18 @@ class PoFileDumper extends FileDumper } else { $newLine = true; } + $metadata = $messages->getMetadata($source, $domain); + + if (isset($metadata['comments'])) { + $output .= $this->formatComments($metadata['comments']); + } + if (isset($metadata['flags'])) { + $output .= $this->formatComments(implode(',', (array) $metadata['flags']), ','); + } + if (isset($metadata['sources'])) { + $output .= $this->formatComments(implode(' ', (array) $metadata['sources']), ':'); + } + $output .= sprintf('msgid "%s"'."\n", $this->escape($source)); $output .= sprintf('msgstr "%s"'."\n", $this->escape($target)); } @@ -58,4 +70,15 @@ class PoFileDumper extends FileDumper { return addcslashes($str, "\0..\37\42\134"); } + + private function formatComments($comments, string $prefix = ''): ?string + { + $output = null; + + foreach ((array) $comments as $comment) { + $output .= sprintf('#%s %s'."\n", $prefix, $comment); + } + + return $output; + } } diff --git a/vendor/symfony/translation/Dumper/QtFileDumper.php b/vendor/symfony/translation/Dumper/QtFileDumper.php index ec93f92e4a..79a64b2430 100644 --- a/vendor/symfony/translation/Dumper/QtFileDumper.php +++ b/vendor/symfony/translation/Dumper/QtFileDumper.php @@ -33,6 +33,17 @@ class QtFileDumper extends FileDumper foreach ($messages->all($domain) as $source => $target) { $message = $context->appendChild($dom->createElement('message')); + $metadata = $messages->getMetadata($source, $domain); + if (isset($metadata['sources'])) { + foreach ((array) $metadata['sources'] as $location) { + $loc = explode(':', $location, 2); + $location = $message->appendChild($dom->createElement('location')); + $location->setAttribute('filename', $loc[0]); + if (isset($loc[1])) { + $location->setAttribute('line', $loc[1]); + } + } + } $message->appendChild($dom->createElement('source', $source)); $message->appendChild($dom->createElement('translation', $target)); } diff --git a/vendor/symfony/translation/Extractor/PhpExtractor.php b/vendor/symfony/translation/Extractor/PhpExtractor.php index 55ebfa1623..84fd7400f8 100644 --- a/vendor/symfony/translation/Extractor/PhpExtractor.php +++ b/vendor/symfony/translation/Extractor/PhpExtractor.php @@ -81,9 +81,8 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface { $files = $this->extractFiles($resource); foreach ($files as $file) { - $this->parseTokens(token_get_all(file_get_contents($file)), $catalog); + $this->parseTokens(token_get_all(file_get_contents($file)), $catalog, $file); - // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 gc_mem_caches(); } } @@ -198,9 +197,15 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface * * @param array $tokens * @param MessageCatalogue $catalog + * @param string $filename */ - protected function parseTokens($tokens, MessageCatalogue $catalog) + protected function parseTokens($tokens, MessageCatalogue $catalog/*, string $filename*/) { + if (\func_num_args() < 3 && __CLASS__ !== \get_class($this) && __CLASS__ !== (new \ReflectionMethod($this, __FUNCTION__))->getDeclaringClass()->getName() && !$this instanceof \PHPUnit\Framework\MockObject\MockObject && !$this instanceof \Prophecy\Prophecy\ProphecySubjectInterface) { + @trigger_error(sprintf('The "%s()" method will have a new "string $filename" argument in version 5.0, not defining it is deprecated since Symfony 4.3.', __METHOD__), E_USER_DEPRECATED); + } + $filename = 2 < \func_num_args() ? \func_get_arg(2) : ''; + $tokenIterator = new \ArrayIterator($tokens); for ($key = 0; $key < $tokenIterator->count(); ++$key) { @@ -237,6 +242,10 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface if ($message) { $catalog->set($message, $this->prefix.$message, $domain); + $metadata = $catalog->getMetadata($message, $domain) ?? []; + $normalizedFilename = preg_replace('{[\\\\/]+}', '/', $filename); + $metadata['sources'][] = $normalizedFilename.':'.$tokens[$key][2]; + $catalog->setMetadata($message, $metadata, $domain); break; } } diff --git a/vendor/symfony/translation/Loader/XliffFileLoader.php b/vendor/symfony/translation/Loader/XliffFileLoader.php index ed97cae290..6e01a7119b 100644 --- a/vendor/symfony/translation/Loader/XliffFileLoader.php +++ b/vendor/symfony/translation/Loader/XliffFileLoader.php @@ -82,38 +82,51 @@ class XliffFileLoader implements LoaderInterface $xml = simplexml_import_dom($dom); $encoding = strtoupper($dom->encoding); - $xml->registerXPathNamespace('xliff', 'urn:oasis:names:tc:xliff:document:1.2'); - foreach ($xml->xpath('//xliff:trans-unit') as $translation) { - $attributes = $translation->attributes(); + $namespace = 'urn:oasis:names:tc:xliff:document:1.2'; + $xml->registerXPathNamespace('xliff', $namespace); - if (!(isset($attributes['resname']) || isset($translation->source))) { - continue; - } + foreach ($xml->xpath('//xliff:file') as $file) { + $fileAttributes = $file->attributes(); - $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; - // If the xlf file has another encoding specified, try to convert it because - // simple_xml will always return utf-8 encoded values - $target = $this->utf8ToCharset((string) (isset($translation->target) ? $translation->target : $translation->source), $encoding); + $file->registerXPathNamespace('xliff', $namespace); - $catalogue->set((string) $source, $target, $domain); + foreach ($file->xpath('.//xliff:trans-unit') as $translation) { + $attributes = $translation->attributes(); - $metadata = []; - if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { - $metadata['notes'] = $notes; - } + if (!(isset($attributes['resname']) || isset($translation->source))) { + continue; + } - if (isset($translation->target) && $translation->target->attributes()) { - $metadata['target-attributes'] = []; - foreach ($translation->target->attributes() as $key => $value) { - $metadata['target-attributes'][$key] = (string) $value; + $source = isset($attributes['resname']) && $attributes['resname'] ? $attributes['resname'] : $translation->source; + // If the xlf file has another encoding specified, try to convert it because + // simple_xml will always return utf-8 encoded values + $target = $this->utf8ToCharset((string) ($translation->target ?? $translation->source), $encoding); + + $catalogue->set((string) $source, $target, $domain); + + $metadata = [ + 'source' => (string) $translation->source, + 'file' => [ + 'original' => (string) $fileAttributes['original'], + ], + ]; + if ($notes = $this->parseNotesMetadata($translation->note, $encoding)) { + $metadata['notes'] = $notes; } - } - if (isset($attributes['id'])) { - $metadata['id'] = (string) $attributes['id']; - } + if (isset($translation->target) && $translation->target->attributes()) { + $metadata['target-attributes'] = []; + foreach ($translation->target->attributes() as $key => $value) { + $metadata['target-attributes'][$key] = (string) $value; + } + } - $catalogue->setMetadata((string) $source, $metadata, $domain); + if (isset($attributes['id'])) { + $metadata['id'] = (string) $attributes['id']; + } + + $catalogue->setMetadata((string) $source, $metadata, $domain); + } } } diff --git a/vendor/symfony/translation/LoggingTranslator.php b/vendor/symfony/translation/LoggingTranslator.php index d6b711d27e..3a84bf1170 100644 --- a/vendor/symfony/translation/LoggingTranslator.php +++ b/vendor/symfony/translation/LoggingTranslator.php @@ -82,7 +82,9 @@ class LoggingTranslator implements TranslatorInterface, LegacyTranslatorInterfac */ public function setLocale($locale) { + $prev = $this->translator->getLocale(); $this->translator->setLocale($locale); + $this->logger->debug(sprintf('The locale of the translator has changed from "%s" to "%s".', $prev, $locale)); } /** diff --git a/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php b/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php index e39ef39ec5..f82b18fdd7 100644 --- a/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php +++ b/vendor/symfony/translation/Tests/Catalogue/AbstractOperationTest.php @@ -41,7 +41,7 @@ abstract class AbstractOperationTest extends TestCase public function testGetMessagesFromUnknownDomain() { - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('InvalidArgumentException'); + $this->expectException('InvalidArgumentException'); $this->createOperation( new MessageCatalogue('en'), new MessageCatalogue('en') diff --git a/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php index 8b9c03d991..f62fc85ebc 100644 --- a/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php +++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPassTest.php @@ -54,4 +54,69 @@ class TranslationPassTest extends TestCase $expected = ['translation.xliff_loader' => new ServiceClosureArgument(new Reference('translation.xliff_loader'))]; $this->assertEquals($expected, $container->getDefinition((string) $translator->getArgument(0))->getArgument(0)); } + + public function testValidCommandsViewPathsArgument() + { + $container = new ContainerBuilder(); + $container->register('translator.default') + ->setArguments([null, null, null, null]) + ; + $debugCommand = $container->register('console.command.translation_debug') + ->setArguments([null, null, null, null, null, [], []]) + ; + $updateCommand = $container->register('console.command.translation_update') + ->setArguments([null, null, null, null, null, null, [], []]) + ; + $container->register('twig.template_iterator') + ->setArguments([null, null, ['other/templates' => null, 'tpl' => 'App']]) + ; + $container->setParameter('twig.default_path', 'templates'); + + $pass = new TranslatorPass('translator.default'); + $pass->process($container); + + $expectedViewPaths = ['other/templates', 'tpl']; + + $this->assertSame('templates', $debugCommand->getArgument(4)); + $this->assertSame('templates', $updateCommand->getArgument(5)); + $this->assertSame($expectedViewPaths, $debugCommand->getArgument(6)); + $this->assertSame($expectedViewPaths, $updateCommand->getArgument(7)); + } + + public function testCommandsViewPathsArgumentsAreIgnoredWithOldServiceDefinitions() + { + $container = new ContainerBuilder(); + $container->register('translator.default') + ->setArguments([null, null, null, null]) + ; + $debugCommand = $container->register('console.command.translation_debug') + ->setArguments([ + new Reference('translator'), + new Reference('translation.reader'), + new Reference('translation.extractor'), + '%translator.default_path%', + null, + ]) + ; + $updateCommand = $container->register('console.command.translation_update') + ->setArguments([ + new Reference('translation.writer'), + new Reference('translation.reader'), + new Reference('translation.extractor'), + '%kernel.default_locale%', + '%translator.default_path%', + null, + ]) + ; + $container->register('twig.template_iterator') + ->setArguments([null, null, ['other/templates' => null, 'tpl' => 'App']]) + ; + $container->setParameter('twig.default_path', 'templates'); + + $pass = new TranslatorPass('translator.default'); + $pass->process($container); + + $this->assertSame('templates', $debugCommand->getArgument(4)); + $this->assertSame('templates', $updateCommand->getArgument(5)); + } } diff --git a/vendor/symfony/translation/Tests/DependencyInjection/TranslationPathsPassTest.php b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPathsPassTest.php new file mode 100644 index 0000000000..42ab398dff --- /dev/null +++ b/vendor/symfony/translation/Tests/DependencyInjection/TranslationPathsPassTest.php @@ -0,0 +1,89 @@ +<?php + +/* + * This file is part of the Symfony package. + * + * (c) Fabien Potencier <fabien@symfony.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Translation\Tests\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\ServiceLocator; +use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ControllerArguments; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceArguments; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceMethodCalls; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceProperties; +use Symfony\Component\Translation\Tests\DependencyInjection\fixtures\ServiceSubscriber; + +class TranslationPathsPassTest extends TestCase +{ + public function testProcess() + { + $container = new ContainerBuilder(); + $container->register('translator'); + $debugCommand = $container->register('console.command.translation_debug') + ->setArguments([null, null, null, null, null, [], []]) + ; + $updateCommand = $container->register('console.command.translation_update') + ->setArguments([null, null, null, null, null, null, [], []]) + ; + $container->register(ControllerArguments::class, ControllerArguments::class) + ->setTags(['controller.service_arguments']) + ; + $container->register(ServiceArguments::class, ServiceArguments::class) + ->setArguments([new Reference('translator')]) + ; + $container->register(ServiceProperties::class, ServiceProperties::class) + ->setProperties([new Reference('translator')]) + ; + $container->register(ServiceMethodCalls::class, ServiceMethodCalls::class) + ->setMethodCalls([['setTranslator', [new Reference('translator')]]]) + ; + $container->register('service_rc') + ->setArguments([new Definition(), new Reference(ServiceMethodCalls::class)]) + ; + $serviceLocator1 = $container->register('.service_locator.foo', ServiceLocator::class) + ->setArguments([new ServiceClosureArgument(new Reference('translator'))]) + ; + $serviceLocator2 = (new Definition(ServiceLocator::class)) + ->setArguments([ServiceSubscriber::class, new Reference('service_container')]) + ->setFactory([$serviceLocator1, 'withContext']) + ; + $container->register('service_subscriber', ServiceSubscriber::class) + ->setArguments([$serviceLocator2]) + ; + $container->register('.service_locator.bar', ServiceLocator::class) + ->setArguments([[ + ControllerArguments::class.'::index' => new ServiceClosureArgument(new Reference('.service_locator.foo')), + ControllerArguments::class.'::__invoke' => new ServiceClosureArgument(new Reference('.service_locator.foo')), + ControllerArguments::class => new ServiceClosureArgument(new Reference('.service_locator.foo')), + ]]) + ; + $container->register('argument_resolver.service') + ->setArguments([new Reference('.service_locator.bar')]) + ; + + $pass = new TranslatorPathsPass('translator', 'console.command.translation_debug', 'console.command.translation_update', 'argument_resolver.service'); + $pass->process($container); + + $expectedPaths = [ + $container->getReflectionClass(ServiceArguments::class)->getFileName(), + $container->getReflectionClass(ServiceProperties::class)->getFileName(), + $container->getReflectionClass(ServiceMethodCalls::class)->getFileName(), + $container->getReflectionClass(ControllerArguments::class)->getFileName(), + $container->getReflectionClass(ServiceSubscriber::class)->getFileName(), + ]; + + $this->assertSame($expectedPaths, $debugCommand->getArgument(6)); + $this->assertSame($expectedPaths, $updateCommand->getArgument(7)); + } +} diff --git a/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ControllerArguments.php b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ControllerArguments.php new file mode 100644 index 0000000000..97a53fa76b --- /dev/null +++ b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ControllerArguments.php @@ -0,0 +1,16 @@ +<?php + +namespace Symfony\Component\Translation\Tests\DependencyInjection\fixtures; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class ControllerArguments +{ + public function __invoke(TranslatorInterface $translator) + { + } + + public function index(TranslatorInterface $translator) + { + } +} diff --git a/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceArguments.php b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceArguments.php new file mode 100644 index 0000000000..80c629d6e7 --- /dev/null +++ b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceArguments.php @@ -0,0 +1,12 @@ +<?php + +namespace Symfony\Component\Translation\Tests\DependencyInjection\fixtures; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class ServiceArguments +{ + public function __construct(TranslatorInterface $translator) + { + } +} diff --git a/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceMethodCalls.php b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceMethodCalls.php new file mode 100644 index 0000000000..8998d8909b --- /dev/null +++ b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceMethodCalls.php @@ -0,0 +1,12 @@ +<?php + +namespace Symfony\Component\Translation\Tests\DependencyInjection\fixtures; + +use Symfony\Contracts\Translation\TranslatorInterface; + +class ServiceMethodCalls +{ + public function setTranslator(TranslatorInterface $translator) + { + } +} diff --git a/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceProperties.php b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceProperties.php new file mode 100644 index 0000000000..f5098e907c --- /dev/null +++ b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceProperties.php @@ -0,0 +1,8 @@ +<?php + +namespace Symfony\Component\Translation\Tests\DependencyInjection\fixtures; + +class ServiceProperties +{ + public $translator; +} diff --git a/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceSubscriber.php b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceSubscriber.php new file mode 100644 index 0000000000..65b60d6fee --- /dev/null +++ b/vendor/symfony/translation/Tests/DependencyInjection/fixtures/ServiceSubscriber.php @@ -0,0 +1,19 @@ +<?php + +namespace Symfony\Component\Translation\Tests\DependencyInjection\fixtures; + +use Psr\Container\ContainerInterface; +use Symfony\Contracts\Service\ServiceSubscriberInterface; +use Symfony\Contracts\Translation\TranslatorInterface; + +class ServiceSubscriber implements ServiceSubscriberInterface +{ + public function __construct(ContainerInterface $container) + { + } + + public static function getSubscribedServices() + { + return ['translator' => TranslatorInterface::class]; + } +} diff --git a/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php index 960ec2df65..46df869f89 100644 --- a/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php +++ b/vendor/symfony/translation/Tests/Dumper/PoFileDumperTest.php @@ -20,7 +20,26 @@ class PoFileDumperTest extends TestCase public function testFormatCatalogue() { $catalogue = new MessageCatalogue('en'); - $catalogue->add(['foo' => 'bar', 'bar' => 'foo']); + $catalogue->add(['foo' => 'bar', 'bar' => 'foo', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo']); + $catalogue->setMetadata('foo_bar', [ + 'comments' => [ + 'Comment 1', + 'Comment 2', + ], + 'flags' => [ + 'fuzzy', + 'another', + ], + 'sources' => [ + 'src/file_1', + 'src/file_2:50', + ], + ]); + $catalogue->setMetadata('bar_foo', [ + 'comments' => 'Comment', + 'flags' => 'fuzzy', + 'sources' => 'src/file_1', + ]); $dumper = new PoFileDumper(); diff --git a/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php b/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php index edfad6005c..6c4b559278 100644 --- a/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php +++ b/vendor/symfony/translation/Tests/Dumper/QtFileDumperTest.php @@ -20,7 +20,26 @@ class QtFileDumperTest extends TestCase public function testFormatCatalogue() { $catalogue = new MessageCatalogue('en'); - $catalogue->add(['foo' => 'bar'], 'resources'); + $catalogue->add(['foo' => 'bar', 'foo_bar' => 'foobar', 'bar_foo' => 'barfoo'], 'resources'); + $catalogue->setMetadata('foo_bar', [ + 'comments' => [ + 'Comment 1', + 'Comment 2', + ], + 'flags' => [ + 'fuzzy', + 'another', + ], + 'sources' => [ + 'src/file_1', + 'src/file_2:50', + ], + ], 'resources'); + $catalogue->setMetadata('bar_foo', [ + 'comments' => 'Comment', + 'flags' => 'fuzzy', + 'sources' => 'src/file_1', + ], 'resources'); $dumper = new QtFileDumper(); diff --git a/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php b/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php index 7cde108080..a6d7c5001c 100644 --- a/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php +++ b/vendor/symfony/translation/Tests/Extractor/PhpExtractorTest.php @@ -69,6 +69,10 @@ EOF; $actualCatalogue = $catalogue->all(); $this->assertEquals($expectedCatalogue, $actualCatalogue); + + $filename = str_replace(\DIRECTORY_SEPARATOR, '/', __DIR__).'/../fixtures/extractor/translation.html.php'; + $this->assertEquals(['sources' => [$filename.':2']], $catalogue->getMetadata('single-quoted key')); + $this->assertEquals(['sources' => [$filename.':43']], $catalogue->getMetadata('other-domain-test-no-params-short-array', 'not_messages')); } public function resourcesProvider() diff --git a/vendor/symfony/translation/Tests/IdentityTranslatorTest.php b/vendor/symfony/translation/Tests/IdentityTranslatorTest.php index be0a548aa1..cf618d95a2 100644 --- a/vendor/symfony/translation/Tests/IdentityTranslatorTest.php +++ b/vendor/symfony/translation/Tests/IdentityTranslatorTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Translation\Tests; use Symfony\Component\Translation\IdentityTranslator; -use Symfony\Contracts\Tests\Translation\TranslatorTest; +use Symfony\Contracts\Translation\Test\TranslatorTest; class IdentityTranslatorTest extends TranslatorTest { diff --git a/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php index 08f55e9022..f149b8c715 100644 --- a/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php +++ b/vendor/symfony/translation/Tests/Loader/QtFileLoaderTest.php @@ -23,7 +23,11 @@ class QtFileLoaderTest extends TestCase $resource = __DIR__.'/../fixtures/resources.ts'; $catalogue = $loader->load($resource, 'en', 'resources'); - $this->assertEquals(['foo' => 'bar'], $catalogue->all('resources')); + $this->assertEquals([ + 'foo' => 'bar', + 'foo_bar' => 'foobar', + 'bar_foo' => 'barfoo', + ], $catalogue->all('resources')); $this->assertEquals('en', $catalogue->getLocale()); $this->assertEquals([new FileResource($resource)], $catalogue->getResources()); } diff --git a/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php b/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php index 7cb9f54fde..1ca8336d52 100644 --- a/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php +++ b/vendor/symfony/translation/Tests/Loader/XliffFileLoaderTest.php @@ -84,7 +84,17 @@ class XliffFileLoaderTest extends TestCase $this->assertEquals(utf8_decode('föö'), $catalogue->get('bar', 'domain1')); $this->assertEquals(utf8_decode('bär'), $catalogue->get('foo', 'domain1')); - $this->assertEquals(['notes' => [['content' => utf8_decode('bäz')]], 'id' => '1'], $catalogue->getMetadata('foo', 'domain1')); + $this->assertEquals( + [ + 'source' => 'foo', + 'notes' => [['content' => utf8_decode('bäz')]], + 'id' => '1', + 'file' => [ + 'original' => 'file.ext', + ], + ], + $catalogue->getMetadata('foo', 'domain1') + ); } public function testTargetAttributesAreStoredCorrectly() @@ -164,11 +174,44 @@ class XliffFileLoaderTest extends TestCase $loader = new XliffFileLoader(); $catalogue = $loader->load(__DIR__.'/../fixtures/withnote.xlf', 'en', 'domain1'); - $this->assertEquals(['notes' => [['priority' => 1, 'content' => 'foo']], 'id' => '1'], $catalogue->getMetadata('foo', 'domain1')); + $this->assertEquals( + [ + 'source' => 'foo', + 'notes' => [['priority' => 1, 'content' => 'foo']], + 'id' => '1', + 'file' => [ + 'original' => 'file.ext', + ], + ], + $catalogue->getMetadata('foo', 'domain1') + ); // message without target - $this->assertEquals(['notes' => [['content' => 'bar', 'from' => 'foo']], 'id' => '2'], $catalogue->getMetadata('extra', 'domain1')); + $this->assertEquals( + [ + 'source' => 'extrasource', + 'notes' => [['content' => 'bar', 'from' => 'foo']], + 'id' => '2', + 'file' => [ + 'original' => 'file.ext', + ], + ], + $catalogue->getMetadata('extra', 'domain1') + ); // message with empty target - $this->assertEquals(['notes' => [['content' => 'baz'], ['priority' => 2, 'from' => 'bar', 'content' => 'qux']], 'id' => '123'], $catalogue->getMetadata('key', 'domain1')); + $this->assertEquals( + [ + 'source' => 'key', + 'notes' => [ + ['content' => 'baz'], + ['priority' => 2, 'from' => 'bar', 'content' => 'qux'], + ], + 'id' => '123', + 'file' => [ + 'original' => 'file.ext', + ], + ], + $catalogue->getMetadata('key', 'domain1') + ); } public function testLoadVersion2() @@ -257,4 +300,32 @@ class XliffFileLoaderTest extends TestCase $this->assertSame('processed', $metadata['notes'][0]['category']); $this->assertSame('true', $metadata['notes'][0]['content']); } + + public function testLoadWithMultipleFileNodes() + { + $loader = new XliffFileLoader(); + $catalogue = $loader->load(__DIR__.'/../fixtures/resources-multi-files.xlf', 'en', 'domain1'); + + $this->assertEquals( + [ + 'source' => 'foo', + 'id' => '1', + 'file' => [ + 'original' => 'file.ext', + ], + ], + $catalogue->getMetadata('foo', 'domain1') + ); + $this->assertEquals( + [ + 'source' => 'test', + 'notes' => [['content' => 'note']], + 'id' => '4', + 'file' => [ + 'original' => 'otherfile.ext', + ], + ], + $catalogue->getMetadata('test', 'domain1') + ); + } } diff --git a/vendor/symfony/translation/Tests/fixtures/resources-multi-files.xlf b/vendor/symfony/translation/Tests/fixtures/resources-multi-files.xlf new file mode 100644 index 0000000000..5f451508bc --- /dev/null +++ b/vendor/symfony/translation/Tests/fixtures/resources-multi-files.xlf @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2"> + <file source-language="en" datatype="plaintext" original="file.ext"> + <body> + <trans-unit id="1"> + <source>foo</source> + <target>bar</target> + </trans-unit> + </body> + </file> + <file source-language="en" datatype="plaintext" original="otherfile.ext"> + <body> + <trans-unit id="2"> + <source>extra</source> + </trans-unit> + <trans-unit id="3"> + <source>key</source> + <target></target> + </trans-unit> + <trans-unit id="4"> + <source>test</source> + <target>with</target> + <note>note</note> + </trans-unit> + </body> + </file> +</xliff> diff --git a/vendor/symfony/translation/Tests/fixtures/resources.po b/vendor/symfony/translation/Tests/fixtures/resources.po index a20e619828..68e0f2d7e0 100644 --- a/vendor/symfony/translation/Tests/fixtures/resources.po +++ b/vendor/symfony/translation/Tests/fixtures/resources.po @@ -9,3 +9,16 @@ msgstr "bar" msgid "bar" msgstr "foo" + +# Comment 1 +# Comment 2 +#, fuzzy,another +#: src/file_1 src/file_2:50 +msgid "foo_bar" +msgstr "foobar" + +# Comment +#, fuzzy +#: src/file_1 +msgid "bar_foo" +msgstr "barfoo" diff --git a/vendor/symfony/translation/Tests/fixtures/resources.ts b/vendor/symfony/translation/Tests/fixtures/resources.ts index 40e18522c8..29e6a6fadf 100644 --- a/vendor/symfony/translation/Tests/fixtures/resources.ts +++ b/vendor/symfony/translation/Tests/fixtures/resources.ts @@ -6,5 +6,16 @@ <source>foo</source> <translation>bar</translation> </message> + <message> + <location filename="src/file_1"/> + <location filename="src/file_2" line="50"/> + <source>foo_bar</source> + <translation>foobar</translation> + </message> + <message> + <location filename="src/file_1"/> + <source>bar_foo</source> + <translation>barfoo</translation> + </message> </context> </TS> diff --git a/vendor/symfony/translation/Tests/fixtures/withnote.xlf b/vendor/symfony/translation/Tests/fixtures/withnote.xlf index c045e21e23..f98cf7f97b 100644 --- a/vendor/symfony/translation/Tests/fixtures/withnote.xlf +++ b/vendor/symfony/translation/Tests/fixtures/withnote.xlf @@ -7,8 +7,8 @@ <target>bar</target> <note priority="1">foo</note> </trans-unit> - <trans-unit id="2"> - <source>extra</source> + <trans-unit id="2" resname="extra"> + <source>extrasource</source> <note from="foo">bar</note> </trans-unit> <trans-unit id="123"> diff --git a/vendor/symfony/translation/Translator.php b/vendor/symfony/translation/Translator.php index 8a2b2dd9d0..f5ce39ef0d 100644 --- a/vendor/symfony/translation/Translator.php +++ b/vendor/symfony/translation/Translator.php @@ -395,7 +395,10 @@ EOF return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php'; } - private function doLoadCatalogue($locale): void + /** + * @internal + */ + protected function doLoadCatalogue($locale): void { $this->catalogues[$locale] = new MessageCatalogue($locale); diff --git a/vendor/symfony/translation/composer.json b/vendor/symfony/translation/composer.json index 809625b5ad..fd25a4cf04 100644 --- a/vendor/symfony/translation/composer.json +++ b/vendor/symfony/translation/composer.json @@ -17,8 +17,8 @@ ], "require": { "php": "^7.1.3", - "symfony/contracts": "^1.0.2", - "symfony/polyfill-mbstring": "~1.0" + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^1.1.2" }, "require-dev": { "symfony/config": "~3.4|~4.0", @@ -26,6 +26,7 @@ "symfony/dependency-injection": "~3.4|~4.0", "symfony/http-kernel": "~3.4|~4.0", "symfony/intl": "~3.4|~4.0", + "symfony/service-contracts": "^1.1.2", "symfony/var-dumper": "~3.4|~4.0", "symfony/yaml": "~3.4|~4.0", "symfony/finder": "~2.8|~3.0|~4.0", @@ -37,7 +38,7 @@ "symfony/yaml": "<3.4" }, "provide": { - "symfony/translation-contracts-implementation": "1.0" + "symfony/translation-implementation": "1.0" }, "suggest": { "symfony/config": "", @@ -53,7 +54,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } diff --git a/vendor/symfony/var-exporter/composer.json b/vendor/symfony/var-exporter/composer.json index b982d3bfd7..3d543df671 100644 --- a/vendor/symfony/var-exporter/composer.json +++ b/vendor/symfony/var-exporter/composer.json @@ -30,7 +30,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "4.2-dev" + "dev-master": "4.3-dev" } } } |
