diff options
Diffstat (limited to 'vendor')
500 files changed, 11211 insertions, 7994 deletions
diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index cc01970429..2b89e59e2e 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -6,15 +6,9 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - 'ArithmeticError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', - 'AssertionError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', 'Datamatrix' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', - 'DivisionByZeroError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', - 'Error' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/Error.php', 'PDF417' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', - 'ParseError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', 'QRcode' => $vendorDir . '/tecnickcom/tcpdf/include/barcodes/qrcode.php', - 'SessionUpdateTimestampHandlerInterface' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', 'TCPDF' => $vendorDir . '/tecnickcom/tcpdf/tcpdf.php', 'TCPDF2DBarcode' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_barcodes_2d.php', 'TCPDFBarcode' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_barcodes_1d.php', @@ -26,5 +20,4 @@ return array( 'TCPDF_IMPORT' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_import.php', 'TCPDF_PARSER' => $vendorDir . '/tecnickcom/tcpdf/tcpdf_parser.php', 'TCPDF_STATIC' => $vendorDir . '/tecnickcom/tcpdf/include/tcpdf_static.php', - 'TypeError' => $vendorDir . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', ); diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index 4975c4ba9d..090bf9ecda 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,10 +6,8 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( - '32dcc8afd4335739640db7d200c1971d' => $vendorDir . '/symfony/polyfill-apcu/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php', - '023d27dca8066ef29e6739335ea73bad' => $vendorDir . '/symfony/polyfill-php70/bootstrap.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => $vendorDir . '/guzzlehttp/psr7/src/functions_include.php', 'c964ee0ededf28c96ebd9db5099ef910' => $vendorDir . '/guzzlehttp/promises/src/functions_include.php', 'b3134b0e457069f7362d2c9cf91628c7' => $vendorDir . '/fisharebest/ext-calendar/src/shims.php', diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 205030bfb5..cf61d87541 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -10,10 +10,10 @@ return array( 'Webuni\\CommonMark\\TableExtension\\' => array($vendorDir . '/webuni/commonmark-table-extension/src'), 'Symfony\\Polyfill\\Php72\\' => array($vendorDir . '/symfony/polyfill-php72'), 'Symfony\\Polyfill\\Php71\\' => array($vendorDir . '/symfony/polyfill-php71'), - 'Symfony\\Polyfill\\Php70\\' => array($vendorDir . '/symfony/polyfill-php70'), 'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'), 'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'), - 'Symfony\\Polyfill\\Apcu\\' => array($vendorDir . '/symfony/polyfill-apcu'), + 'Symfony\\Contracts\\' => array($vendorDir . '/symfony/contracts'), + 'Symfony\\Component\\VarExporter\\' => array($vendorDir . '/symfony/var-exporter'), '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 ecf1c8ccd9..bf7753fbda 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -7,10 +7,8 @@ namespace Composer\Autoload; class ComposerStaticInit3da29173c262c589b273f6106eae3544 { public static $files = array ( - '32dcc8afd4335739640db7d200c1971d' => __DIR__ . '/..' . '/symfony/polyfill-apcu/bootstrap.php', '320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php', '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php', - '023d27dca8066ef29e6739335ea73bad' => __DIR__ . '/..' . '/symfony/polyfill-php70/bootstrap.php', 'a0edc8309cc5e1d60e3047b5df6b7052' => __DIR__ . '/..' . '/guzzlehttp/psr7/src/functions_include.php', 'c964ee0ededf28c96ebd9db5099ef910' => __DIR__ . '/..' . '/guzzlehttp/promises/src/functions_include.php', 'b3134b0e457069f7362d2c9cf91628c7' => __DIR__ . '/..' . '/fisharebest/ext-calendar/src/shims.php', @@ -31,10 +29,10 @@ class ComposerStaticInit3da29173c262c589b273f6106eae3544 array ( 'Symfony\\Polyfill\\Php72\\' => 23, 'Symfony\\Polyfill\\Php71\\' => 23, - 'Symfony\\Polyfill\\Php70\\' => 23, 'Symfony\\Polyfill\\Mbstring\\' => 26, 'Symfony\\Polyfill\\Ctype\\' => 23, - 'Symfony\\Polyfill\\Apcu\\' => 22, + 'Symfony\\Contracts\\' => 18, + 'Symfony\\Component\\VarExporter\\' => 30, 'Symfony\\Component\\HttpKernel\\' => 29, 'Symfony\\Component\\HttpFoundation\\' => 33, 'Symfony\\Component\\ExpressionLanguage\\' => 37, @@ -96,10 +94,6 @@ class ComposerStaticInit3da29173c262c589b273f6106eae3544 array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-php71', ), - 'Symfony\\Polyfill\\Php70\\' => - array ( - 0 => __DIR__ . '/..' . '/symfony/polyfill-php70', - ), 'Symfony\\Polyfill\\Mbstring\\' => array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring', @@ -108,9 +102,13 @@ class ComposerStaticInit3da29173c262c589b273f6106eae3544 array ( 0 => __DIR__ . '/..' . '/symfony/polyfill-ctype', ), - 'Symfony\\Polyfill\\Apcu\\' => + 'Symfony\\Contracts\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/contracts', + ), + 'Symfony\\Component\\VarExporter\\' => array ( - 0 => __DIR__ . '/..' . '/symfony/polyfill-apcu', + 0 => __DIR__ . '/..' . '/symfony/var-exporter', ), 'Symfony\\Component\\HttpKernel\\' => array ( @@ -207,15 +205,9 @@ class ComposerStaticInit3da29173c262c589b273f6106eae3544 ); public static $classMap = array ( - 'ArithmeticError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php', - 'AssertionError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/AssertionError.php', 'Datamatrix' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/datamatrix.php', - 'DivisionByZeroError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php', - 'Error' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/Error.php', 'PDF417' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/pdf417.php', - 'ParseError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/ParseError.php', 'QRcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/barcodes/qrcode.php', - 'SessionUpdateTimestampHandlerInterface' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php', 'TCPDF' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf.php', 'TCPDF2DBarcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_barcodes_2d.php', 'TCPDFBarcode' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_barcodes_1d.php', @@ -227,7 +219,6 @@ class ComposerStaticInit3da29173c262c589b273f6106eae3544 'TCPDF_IMPORT' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_import.php', 'TCPDF_PARSER' => __DIR__ . '/..' . '/tecnickcom/tcpdf/tcpdf_parser.php', 'TCPDF_STATIC' => __DIR__ . '/..' . '/tecnickcom/tcpdf/include/tcpdf_static.php', - 'TypeError' => __DIR__ . '/..' . '/symfony/polyfill-php70/Resources/stubs/TypeError.php', ); public static function getInitializer(ClassLoader $loader) diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index c8bdac6ff8..ed5342a1eb 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -492,17 +492,17 @@ }, { "name": "league/commonmark", - "version": "0.17.5", - "version_normalized": "0.17.5.0", + "version": "0.18.0", + "version_normalized": "0.18.0.0", "source": { "type": "git", "url": "https://github.com/thephpleague/commonmark.git", - "reference": "82d7ab62d7f68391cb9d323f3ccce50be24a5369" + "reference": "006af077d4b1b7eb1d9760964f9f984ba188632c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/82d7ab62d7f68391cb9d323f3ccce50be24a5369", - "reference": "82d7ab62d7f68391cb9d323f3ccce50be24a5369", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/006af077d4b1b7eb1d9760964f9f984ba188632c", + "reference": "006af077d4b1b7eb1d9760964f9f984ba188632c", "shasum": "" }, "require": { @@ -525,14 +525,14 @@ "suggest": { "league/commonmark-extras": "Library of useful extensions including smart punctuation" }, - "time": "2018-03-29T14:35:19+00:00", + "time": "2018-09-18T13:13:55+00:00", "bin": [ "bin/commonmark" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "0.18-dev" + "dev-master": "0.19-dev" } }, "installation-source": "dist", @@ -563,17 +563,17 @@ }, { "name": "league/flysystem", - "version": "1.0.48", - "version_normalized": "1.0.48.0", + "version": "1.0.49", + "version_normalized": "1.0.49.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "a6ded5b2f6055e2db97b4b859fdfca2b952b78aa" + "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a6ded5b2f6055e2db97b4b859fdfca2b952b78aa", - "reference": "a6ded5b2f6055e2db97b4b859fdfca2b952b78aa", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/a63cc83d8a931b271be45148fa39ba7156782ffd", + "reference": "a63cc83d8a931b271be45148fa39ba7156782ffd", "shasum": "" }, "require": { @@ -603,7 +603,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": "2018-10-15T13:53:10+00:00", + "time": "2018-11-23T23:41:29+00:00", "type": "library", "extra": { "branch-alias": { @@ -1147,44 +1147,51 @@ }, { "name": "symfony/cache", - "version": "v3.4.18", - "version_normalized": "3.4.18.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "4f29972d3fae5febec5c18db70e7dd2957e74ad6" + "reference": "dbe98af4943a9c246e4538868e0fa55bc8b5e0f3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/4f29972d3fae5febec5c18db70e7dd2957e74ad6", - "reference": "4f29972d3fae5febec5c18db70e7dd2957e74ad6", + "url": "https://api.github.com/repos/symfony/cache/zipball/dbe98af4943a9c246e4538868e0fa55bc8b5e0f3", + "reference": "dbe98af4943a9c246e4538868e0fa55bc8b5e0f3", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", "psr/simple-cache": "^1.0", - "symfony/polyfill-apcu": "~1.1" + "symfony/contracts": "^1.0", + "symfony/var-exporter": "^4.2" }, "conflict": { - "symfony/var-dumper": "<3.3" + "doctrine/dbal": "<2.5", + "symfony/dependency-injection": "<3.4", + "symfony/var-dumper": "<3.4" }, "provide": { "psr/cache-implementation": "1.0", - "psr/simple-cache-implementation": "1.0" + "psr/simple-cache-implementation": "1.0", + "symfony/cache-contracts-implementation": "1.0" }, "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "~1.6", - "doctrine/dbal": "~2.4", - "predis/predis": "~1.0" + "doctrine/dbal": "~2.5", + "predis/predis": "~1.1", + "symfony/config": "~4.2", + "symfony/dependency-injection": "~3.4|~4.1", + "symfony/var-dumper": "^4.1.1" }, - "time": "2018-09-25T07:13:51+00:00", + "time": "2018-11-26T18:33:39+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", @@ -1218,35 +1225,105 @@ ] }, { + "name": "symfony/contracts", + "version": "v1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/contracts.git", + "reference": "4a33574d5771f4b04334cd4f7d43de96a92efb62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/contracts/zipball/4a33574d5771f4b04334cd4f7d43de96a92efb62", + "reference": "4a33574d5771f4b04334cd4f7d43de96a92efb62", + "shasum": "" + }, + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "psr/cache": "^1.0", + "psr/container": "^1.0" + }, + "suggest": { + "psr/cache": "When using the Cache contracts", + "psr/container": "When using the Service contracts", + "symfony/cache-contracts-implementation": "", + "symfony/service-contracts-implementation": "", + "symfony/translation-contracts-implementation": "" + }, + "time": "2018-10-31T08:00:32+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Contracts\\": "" + }, + "exclude-from-classmap": [ + "**/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A set of abstractions extracted out of the Symfony components", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ] + }, + { "name": "symfony/debug", - "version": "v3.4.18", - "version_normalized": "3.4.18.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/debug.git", - "reference": "fe9793af008b651c5441bdeab21ede8172dab097" + "reference": "e0a2b92ee0b5b934f973d90c2f58e18af109d276" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug/zipball/fe9793af008b651c5441bdeab21ede8172dab097", - "reference": "fe9793af008b651c5441bdeab21ede8172dab097", + "url": "https://api.github.com/repos/symfony/debug/zipball/e0a2b92ee0b5b934f973d90c2f58e18af109d276", + "reference": "e0a2b92ee0b5b934f973d90c2f58e18af109d276", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/log": "~1.0" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "symfony/http-kernel": "~3.4|~4.0" }, - "time": "2018-10-31T09:06:03+00:00", + "time": "2018-11-28T18:24:18+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", @@ -1277,41 +1354,42 @@ }, { "name": "symfony/event-dispatcher", - "version": "v3.4.18", - "version_normalized": "3.4.18.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14" + "reference": "9b788b5f7cd6be22918f3d18ee3ff0a78e060137" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", - "reference": "db9e829c8f34c3d35cf37fcd4cdb4293bc4a2f14", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9b788b5f7cd6be22918f3d18ee3ff0a78e060137", + "reference": "9b788b5f7cd6be22918f3d18ee3ff0a78e060137", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3", + "symfony/contracts": "^1.0" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4" }, "require-dev": { "psr/log": "~1.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" + "symfony/config": "~3.4|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0" }, "suggest": { "symfony/dependency-injection": "", "symfony/http-kernel": "" }, - "time": "2018-10-30T16:50:50+00:00", + "time": "2018-11-26T10:55:26+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", @@ -1342,28 +1420,29 @@ }, { "name": "symfony/expression-language", - "version": "v3.4.18", - "version_normalized": "3.4.18.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "d60e37ab9838338d959f2cc177a66cf498293788" + "reference": "2d2741ecba77e1cb27b726f12a6d43cfc2f199af" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/d60e37ab9838338d959f2cc177a66cf498293788", - "reference": "d60e37ab9838338d959f2cc177a66cf498293788", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/2d2741ecba77e1cb27b726f12a6d43cfc2f199af", + "reference": "2d2741ecba77e1cb27b726f12a6d43cfc2f199af", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/cache": "~3.1|~4.0" + "php": "^7.1.3", + "symfony/cache": "~3.4|~4.0", + "symfony/contracts": "^1.0" }, - "time": "2018-07-26T09:06:28+00:00", + "time": "2018-11-11T19:52:12+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", @@ -1394,32 +1473,32 @@ }, { "name": "symfony/http-foundation", - "version": "v3.4.18", - "version_normalized": "3.4.18.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0" + "reference": "1b31f3017fadd8cb05cf2c8aebdbf3b12a943851" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", - "reference": "5aea7a86ca3203dd7a257e765b4b9c9cfd01c6c0", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/1b31f3017fadd8cb05cf2c8aebdbf3b12a943851", + "reference": "1b31f3017fadd8cb05cf2c8aebdbf3b12a943851", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "predis/predis": "~1.0", + "symfony/expression-language": "~3.4|~4.0" }, - "time": "2018-10-31T08:57:11+00:00", + "time": "2018-11-26T10:55:26+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", @@ -1450,31 +1529,33 @@ }, { "name": "symfony/http-kernel", - "version": "v3.4.18", - "version_normalized": "3.4.18.0", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "4bf0be7c7fe63eff6a5eae2f21c83e77e31a56fb" + "reference": "500409e5d8a31fc92450a0ec2ea4e4c35af40117" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/4bf0be7c7fe63eff6a5eae2f21c83e77e31a56fb", - "reference": "4bf0be7c7fe63eff6a5eae2f21c83e77e31a56fb", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/500409e5d8a31fc92450a0ec2ea4e4c35af40117", + "reference": "500409e5d8a31fc92450a0ec2ea4e4c35af40117", "shasum": "" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/log": "~1.0", - "symfony/debug": "~2.8|~3.0|~4.0", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", + "symfony/contracts": "^1.0", + "symfony/debug": "~3.4|~4.0", + "symfony/event-dispatcher": "~4.1", + "symfony/http-foundation": "^4.1.1", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", + "symfony/config": "<3.4", + "symfony/dependency-injection": "<4.2", + "symfony/translation": "<4.2", + "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, "provide": { @@ -1482,35 +1563,33 @@ }, "require-dev": { "psr/cache": "~1.0", - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", + "symfony/browser-kit": "~3.4|~4.0", + "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/dom-crawler": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0", "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0" + "symfony/stopwatch": "~3.4|~4.0", + "symfony/templating": "~3.4|~4.0", + "symfony/translation": "~4.2", + "symfony/var-dumper": "^4.1.1" }, "suggest": { "symfony/browser-kit": "", "symfony/config": "", "symfony/console": "", "symfony/dependency-injection": "", - "symfony/finder": "", "symfony/var-dumper": "" }, - "time": "2018-11-03T10:03:02+00:00", + "time": "2018-11-30T09:16:14+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", @@ -1540,64 +1619,6 @@ "homepage": "https://symfony.com" }, { - "name": "symfony/polyfill-apcu", - "version": "v1.10.0", - "version_normalized": "1.10.0.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-apcu.git", - "reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/19e1b73bf255265ad0b568f81766ae2a3266d8d2", - "reference": "19e1b73bf255265ad0b568f81766ae2a3266d8d2", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "time": "2018-08-06T14:22:27+00:00", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Apcu\\": "" - }, - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "apcu", - "compatibility", - "polyfill", - "portable", - "shim" - ] - }, - { "name": "symfony/polyfill-ctype", "version": "v1.10.0", "version_normalized": "1.10.0.0", @@ -1719,25 +1740,24 @@ ] }, { - "name": "symfony/polyfill-php70", + "name": "symfony/polyfill-php71", "version": "v1.10.0", "version_normalized": "1.10.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224" + "url": "https://github.com/symfony/polyfill-php71.git", + "reference": "1766834a22738196eb45486c4ca23c5739513bf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/6b88000cdd431cd2e940caa2cb569201f3f84224", - "reference": "6b88000cdd431cd2e940caa2cb569201f3f84224", + "url": "https://api.github.com/repos/symfony/polyfill-php71/zipball/1766834a22738196eb45486c4ca23c5739513bf4", + "reference": "1766834a22738196eb45486c4ca23c5739513bf4", "shasum": "" }, "require": { - "paragonie/random_compat": "~1.0|~2.0|~9.99", "php": ">=5.3.3" }, - "time": "2018-09-21T06:26:08+00:00", + "time": "2018-08-06T14:22:27+00:00", "type": "library", "extra": { "branch-alias": { @@ -1747,13 +1767,10 @@ "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php70\\": "" + "Symfony\\Polyfill\\Php71\\": "" }, "files": [ "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1770,7 +1787,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.1+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1780,24 +1797,24 @@ ] }, { - "name": "symfony/polyfill-php71", + "name": "symfony/polyfill-php72", "version": "v1.10.0", "version_normalized": "1.10.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php71.git", - "reference": "1766834a22738196eb45486c4ca23c5739513bf4" + "url": "https://github.com/symfony/polyfill-php72.git", + "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php71/zipball/1766834a22738196eb45486c4ca23c5739513bf4", - "reference": "1766834a22738196eb45486c4ca23c5739513bf4", + "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", + "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "time": "2018-08-06T14:22:27+00:00", + "time": "2018-09-21T13:07:52+00:00", "type": "library", "extra": { "branch-alias": { @@ -1807,7 +1824,7 @@ "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php71\\": "" + "Symfony\\Polyfill\\Php72\\": "" }, "files": [ "bootstrap.php" @@ -1827,7 +1844,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.1+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -1837,37 +1854,40 @@ ] }, { - "name": "symfony/polyfill-php72", - "version": "v1.10.0", - "version_normalized": "1.10.0.0", + "name": "symfony/var-exporter", + "version": "v4.2.0", + "version_normalized": "4.2.0.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php72.git", - "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631" + "url": "https://github.com/symfony/var-exporter.git", + "reference": "08250457428e06289d21ed52397b0ae336abf54b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", - "reference": "9050816e2ca34a8e916c3a0ae8b9c2fccf68b631", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/08250457428e06289d21ed52397b0ae336abf54b", + "reference": "08250457428e06289d21ed52397b0ae336abf54b", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^7.1.3" }, - "time": "2018-09-21T13:07:52+00:00", + "require-dev": { + "symfony/var-dumper": "^4.1.1" + }, + "time": "2018-11-14T10:32:16+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "1.9-dev" + "dev-master": "4.2-dev" } }, "installation-source": "dist", "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php72\\": "" + "Symfony\\Component\\VarExporter\\": "" }, - "files": [ - "bootstrap.php" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1884,13 +1904,15 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions", + "description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "serialize" ] }, { @@ -1959,21 +1981,21 @@ }, { "name": "webuni/commonmark-table-extension", - "version": "0.8.0", - "version_normalized": "0.8.0.0", + "version": "0.9.0", + "version_normalized": "0.9.0.0", "source": { "type": "git", "url": "https://github.com/webuni/commonmark-table-extension.git", - "reference": "4304b1f56b26e5213a4a781b654f62ef5ed8fbe3" + "reference": "94bc98d802d0b706e748716854e5fa0bd3644df3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webuni/commonmark-table-extension/zipball/4304b1f56b26e5213a4a781b654f62ef5ed8fbe3", - "reference": "4304b1f56b26e5213a4a781b654f62ef5ed8fbe3", + "url": "https://api.github.com/repos/webuni/commonmark-table-extension/zipball/94bc98d802d0b706e748716854e5fa0bd3644df3", + "reference": "94bc98d802d0b706e748716854e5fa0bd3644df3", "shasum": "" }, "require": { - "league/commonmark": "^0.16|^0.17", + "league/commonmark": "^0.16|^0.17|^0.18", "php": "^5.6|^7.0" }, "require-dev": { @@ -1982,11 +2004,11 @@ "symfony/var-dumper": "^3.0|^4.0", "vimeo/psalm": "~0.3" }, - "time": "2018-01-24T12:30:02+00:00", + "time": "2018-11-28T11:29:11+00:00", "type": "library", "extra": { "branch-alias": { - "dev-master": "0.8-dev" + "dev-master": "0.9-dev" } }, "installation-source": "dist", diff --git a/vendor/league/commonmark/CHANGELOG.md b/vendor/league/commonmark/CHANGELOG.md index 237b15d87c..f59c5abd14 100644 --- a/vendor/league/commonmark/CHANGELOG.md +++ b/vendor/league/commonmark/CHANGELOG.md @@ -4,6 +4,18 @@ Updates should follow the [Keep a CHANGELOG](http://keepachangelog.com/) princip ## [Unreleased][unreleased] +## [0.18.0] - 2018-09-18 + +### Added + + - Added `ConverterInterface` to `Converter` and `CommonMarkConverter` (#330) + - Added `ListItem::getListData()` method (#329) + +### Changed + + - Links with `target="_blank"` will also get `rel="noopener noreferrer"` by default (#331) + - Implemented several performance optimizations (#324) + ## [0.17.5] - 2018-03-29 ### Fixed @@ -645,7 +657,8 @@ An unused constant and static method were deprecated and will be removed in a fu ### Added - Initial commit (compatible with jgm/stmd:spec.txt @ 0275f34) -[unreleased]: https://github.com/thephpleague/commonmark/compare/0.17.5...HEAD +[unreleased]: https://github.com/thephpleague/commonmark/compare/0.18.0...HEAD +[0.18.0]: https://github.com/thephpleague/commonmark/compare/0.17.5...0.18.0 [0.17.5]: https://github.com/thephpleague/commonmark/compare/0.17.4...0.17.5 [0.17.4]: https://github.com/thephpleague/commonmark/compare/0.17.3...0.17.4 [0.17.3]: https://github.com/thephpleague/commonmark/compare/0.17.2...0.17.3 diff --git a/vendor/league/commonmark/README.md b/vendor/league/commonmark/README.md index 0c08a9bd69..d58423646f 100644 --- a/vendor/league/commonmark/README.md +++ b/vendor/league/commonmark/README.md @@ -102,8 +102,10 @@ Documentation can be found at [commonmark.thephpleague.com][docs]. - [Drupal 7 & 8](https://www.drupal.org/project/markdown) - [Laravel 4 & 5](https://github.com/GrahamCampbell/Laravel-Markdown) - [Sculpin](https://github.com/bcremer/sculpin-commonmark-bundle) -- [Symfony](https://github.com/webuni/commonmark-bundle) -- [Twig](https://github.com/webuni/commonmark-twig-renderer) +- [Symfony 2 & 3](https://github.com/webuni/commonmark-bundle) +- [Symfony 4](https://github.com/avensome/commonmark-bundle) +- [Twig-based renderer](https://github.com/webuni/commonmark-twig-renderer) +- [Twig filter and tag](https://github.com/aptoma/twig-markdown) ### CommonMark Extras @@ -118,6 +120,7 @@ Custom parsers/renderers can be bundled into extensions which extend CommonMark. - [CommonMark Attributes Extension](https://github.com/webuni/commonmark-attributes-extension) - Adds a syntax to define attributes on the various HTML elements. - [Alt Three Emoji](https://github.com/AltThree/Emoji) An emoji parser for CommonMark. - [uafrica/commonmark-ext](https://github.com/uafrica/commonmark-ext) - Adds strikethrough support. + - [Sup Sub extensions](https://github.com/OWS/commonmark-sup-sub-extensions) - Adds support of superscript and subscript (`<sup>` and `<sub>` HTML tags) If you build your own, feel free to submit a PR to add it to this list! @@ -151,17 +154,17 @@ $ ./tests/benchmark/benchmark.php ## Versioning -[SemVer](http://semver.org/) will be followed closely. 0.x.0 versions will introduce breaking changes to the codebase, so be careful which version constraints you use. **It's highly recommended that you use [Composer's caret operator](https://getcomposer.org/doc/articles/versions.md#caret) to ensure compatibility**; for example: `^0.16`. This is equivalent to `>=0.16.0 <0.17.0`. +[SemVer](http://semver.org/) will be followed closely. 0.x.0 versions will introduce breaking changes to the codebase, so be careful which version constraints you use. **It's highly recommended that you use [Composer's caret operator](https://getcomposer.org/doc/articles/versions.md#caret) to ensure compatibility**; for example: `^0.18`. This is equivalent to `>=0.18.0 <0.19.0`. 0.x.y releases should not introduce breaking changes to the codebase; however, they might change the resulting AST or HTML output of parsed Markdown (due to bug fixes, minor spec changes, etc.) As a result, you might get slightly different HTML, but any custom code built onto this library will still function correctly. -If you're only using the `CommonMarkConverter` class to convert Markdown (no other class references, custom parsers, etc.), then it should be safe to use a broader constraint like `~0.16`, `>0.16`, etc. I personally promise to never break this specific class in any future 0.x release. +If you're only using the `CommonMarkConverter` class or `ConverterInterface` to convert Markdown (no other class references, custom parsers, etc.), then it should be safe to use a broader constraint like `~0.18`, `>0.18`, etc. I personally promise to never break this specific class in any future 0.x release. ## Stability While this package does work well, the underlying code should not be considered "stable" yet. The original spec and JS parser may undergo changes in the near future which will result in corresponding changes to this code. Any methods tagged with `@api` are not expected to change, but other methods/classes might. -Major release 1.0.0 will be reserved for when both CommonMark and this project are considered stable (see [outstanding CommonMark spec issues](http://talk.commonmark.org/t/issues-to-resolve-before-1-0-release/1287)). 0.x.y will be used until that happens. +Major release 1.0.0 will be reserved for when either the CommonMark spec or this project are considered stable (see [outstanding CommonMark spec issues](http://talk.commonmark.org/t/issues-to-resolve-before-1-0-release/1287)). 0.x.y will be used until that happens. ## Contributing diff --git a/vendor/league/commonmark/UPGRADE.md b/vendor/league/commonmark/UPGRADE.md index 15bace7226..cfe5cc4c6f 100644 --- a/vendor/league/commonmark/UPGRADE.md +++ b/vendor/league/commonmark/UPGRADE.md @@ -1,5 +1,9 @@ # Upgrade Instructions +## 0.18.0 + +No breaking changes were introduced, but we did add a new interface: `ConverterInface`. Consider depending on this interface in your code instead of the concrete implementation. (See #330) + ## 0.17.0 ## Minimum PHP version diff --git a/vendor/league/commonmark/composer.json b/vendor/league/commonmark/composer.json index 9ae47e3c2c..b41e8e7509 100644 --- a/vendor/league/commonmark/composer.json +++ b/vendor/league/commonmark/composer.json @@ -60,7 +60,7 @@ "bin": ["bin/commonmark"], "extra": { "branch-alias": { - "dev-master": "0.18-dev" + "dev-master": "0.19-dev" } } } diff --git a/vendor/league/commonmark/src/Block/Element/AbstractBlock.php b/vendor/league/commonmark/src/Block/Element/AbstractBlock.php index cf764f5c33..15da520d45 100644 --- a/vendor/league/commonmark/src/Block/Element/AbstractBlock.php +++ b/vendor/league/commonmark/src/Block/Element/AbstractBlock.php @@ -94,7 +94,7 @@ abstract class AbstractBlock extends Node */ public function hasChildren() { - return !is_null($this->firstChild); + return $this->firstChild !== null; } /** diff --git a/vendor/league/commonmark/src/Block/Element/ListItem.php b/vendor/league/commonmark/src/Block/Element/ListItem.php index 2da2c7d81e..a455a8a444 100644 --- a/vendor/league/commonmark/src/Block/Element/ListItem.php +++ b/vendor/league/commonmark/src/Block/Element/ListItem.php @@ -31,6 +31,14 @@ class ListItem extends AbstractBlock } /** + * @return ListData + */ + public function getListData() + { + return $this->listData; + } + + /** * Returns true if this block can contain the given block as a child node * * @param AbstractBlock $block diff --git a/vendor/league/commonmark/src/Block/Parser/FencedCodeParser.php b/vendor/league/commonmark/src/Block/Parser/FencedCodeParser.php index d27abb2b8a..b35cf81025 100644 --- a/vendor/league/commonmark/src/Block/Parser/FencedCodeParser.php +++ b/vendor/league/commonmark/src/Block/Parser/FencedCodeParser.php @@ -34,7 +34,7 @@ class FencedCodeParser extends AbstractBlockParser $indent = $cursor->getIndent(); $fence = $cursor->match('/^[ \t]*(?:`{3,}(?!.*`)|^~{3,}(?!.*~))/'); - if (is_null($fence)) { + if ($fence === null) { return false; } diff --git a/vendor/league/commonmark/src/CommonMarkConverter.php b/vendor/league/commonmark/src/CommonMarkConverter.php index bd626f8243..0341446aa7 100644 --- a/vendor/league/commonmark/src/CommonMarkConverter.php +++ b/vendor/league/commonmark/src/CommonMarkConverter.php @@ -24,7 +24,7 @@ class CommonMarkConverter extends Converter * * This might be a typical `x.y.z` version, or `x.y-dev`. */ - const VERSION = '0.17.5'; + const VERSION = '0.18.0'; /** * Create a new commonmark converter instance. diff --git a/vendor/league/commonmark/src/Context.php b/vendor/league/commonmark/src/Context.php index e99cf9ef9e..67d542bedc 100644 --- a/vendor/league/commonmark/src/Context.php +++ b/vendor/league/commonmark/src/Context.php @@ -62,6 +62,8 @@ class Context implements ContextInterface */ protected $blocksParsed = false; + protected $encoding = 'UTF-8'; + protected $referenceParser; public function __construct(Document $document, Environment $environment) @@ -222,4 +224,24 @@ class Context implements ContextInterface { return $this->referenceParser; } + + /** + * @return string + */ + public function getEncoding() + { + return $this->encoding; + } + + /** + * @param string $encoding + * + * @return $this + */ + public function setEncoding($encoding) + { + $this->encoding = $encoding; + + return $this; + } } diff --git a/vendor/league/commonmark/src/ContextInterface.php b/vendor/league/commonmark/src/ContextInterface.php index 12846c6ec3..351b280a63 100644 --- a/vendor/league/commonmark/src/ContextInterface.php +++ b/vendor/league/commonmark/src/ContextInterface.php @@ -95,4 +95,9 @@ interface ContextInterface * @return ReferenceParser */ public function getReferenceParser(); + + /** + * @return string + */ + public function getEncoding(); } diff --git a/vendor/league/commonmark/src/Converter.php b/vendor/league/commonmark/src/Converter.php index 9f49bcc666..babe0afbab 100644 --- a/vendor/league/commonmark/src/Converter.php +++ b/vendor/league/commonmark/src/Converter.php @@ -17,7 +17,7 @@ namespace League\CommonMark; /** * Converts CommonMark-compatible Markdown to HTML. */ -class Converter +class Converter implements ConverterInterface { /** * The document parser instance. diff --git a/vendor/league/commonmark/src/ConverterInterface.php b/vendor/league/commonmark/src/ConverterInterface.php new file mode 100644 index 0000000000..3d47a275d1 --- /dev/null +++ b/vendor/league/commonmark/src/ConverterInterface.php @@ -0,0 +1,29 @@ +<?php + +/* + * This file is part of the league/commonmark package. + * + * (c) Colin O'Dell <colinodell@gmail.com> + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace League\CommonMark; + +/** + * Interface for a service which converts CommonMark to HTML. + */ +interface ConverterInterface +{ + /** + * Converts CommonMark to HTML. + * + * @param string $commonMark + * + * @return string HTML + * + * @api + */ + public function convertToHtml($commonMark); +} diff --git a/vendor/league/commonmark/src/Cursor.php b/vendor/league/commonmark/src/Cursor.php index 7de36dfab3..91af05d6f1 100644 --- a/vendor/league/commonmark/src/Cursor.php +++ b/vendor/league/commonmark/src/Cursor.php @@ -74,12 +74,17 @@ class Cursor private $isMultibyte; /** + * @var int + */ + private $charCache = []; + + /** * @param string $line */ - public function __construct($line) + public function __construct($line, $encoding = 'UTF-8') { $this->line = $line; - $this->encoding = mb_detect_encoding($line, 'ASCII,UTF-8', true) ?: 'ISO-8859-1'; + $this->encoding = $encoding; $this->length = mb_strlen($line, $this->encoding); $this->isMultibyte = $this->length !== strlen($line); $this->lineContainsTabs = preg_match('/\t/', $line) > 0; @@ -134,7 +139,9 @@ class Cursor */ public function getIndent() { - $this->getNextNonSpacePosition(); + if ($this->nextNonSpaceCache === null) { + $this->getNextNonSpacePosition(); + } return $this->indent; } @@ -146,9 +153,7 @@ class Cursor */ public function isIndented() { - $this->getNextNonSpacePosition(); - - return $this->indent >= self::INDENT_LEVEL; + return $this->getIndent() >= self::INDENT_LEVEL; } /** @@ -162,12 +167,16 @@ class Cursor $index = $this->currentPosition; } + if (isset($this->charCache[$index])) { + return $this->charCache[$index]; + } + // Index out-of-bounds, or we're at the end if ($index < 0 || $index >= $this->length) { return; } - return mb_substr($this->line, $index, 1, $this->encoding); + return $this->charCache[$index] = mb_substr($this->line, $index, 1, $this->encoding); } /** @@ -189,7 +198,7 @@ class Cursor */ public function isBlank() { - return $this->getNextNonSpacePosition() === $this->length; + return $this->nextNonSpaceCache === $this->length || $this->getNextNonSpacePosition() === $this->length; } /** @@ -217,10 +226,8 @@ class Cursor $this->previousPosition = $this->currentPosition; $this->nextNonSpaceCache = null; - $nextFewChars = mb_substr($this->line, $this->currentPosition, $characters, $this->encoding); - // Optimization to avoid tab handling logic if we have no tabs - if (!$this->lineContainsTabs || preg_match('/\t/', $nextFewChars) === 0) { + if (!$this->lineContainsTabs || preg_match('/\t/', $nextFewChars = mb_substr($this->line, $this->currentPosition, $characters, $this->encoding)) === 0) { $length = min($characters, $this->length - $this->currentPosition); $this->partiallyConsumedTab = false; $this->currentPosition += $length; @@ -394,13 +401,15 @@ class Cursor if ($this->isMultibyte) { // PREG_OFFSET_CAPTURE always returns the byte offset, not the char offset, which is annoying $offset = mb_strlen(mb_strcut($subject, 0, $matches[0][1], $this->encoding), $this->encoding); + $matchLength = mb_strlen($matches[0][0], $this->encoding); } else { $offset = $matches[0][1]; + $matchLength = strlen($matches[0][0]); } // [0][0] contains the matched text // [0][1] contains the index of that match - $this->advanceBy($offset + mb_strlen($matches[0][0], $this->encoding)); + $this->advanceBy($offset + $matchLength); return $matches[0][0]; } diff --git a/vendor/league/commonmark/src/DocParser.php b/vendor/league/commonmark/src/DocParser.php index d0e0c3d7ed..9caaf69d60 100644 --- a/vendor/league/commonmark/src/DocParser.php +++ b/vendor/league/commonmark/src/DocParser.php @@ -82,6 +82,7 @@ class DocParser public function parse($input) { $context = new Context(new Document(), $this->getEnvironment()); + $context->setEncoding(mb_detect_encoding($input, 'ASCII,UTF-8', true) ?: 'ISO-8859-1'); $lines = $this->preProcessInput($input); foreach ($lines as $line) { @@ -89,8 +90,9 @@ class DocParser $this->incorporateLine($context); } + $lineCount = count($lines); while ($tip = $context->getTip()) { - $tip->finalize($context, count($lines)); + $tip->finalize($context, $lineCount); } $this->processInlines($context, $context->getDocument()->walker()); @@ -102,11 +104,11 @@ class DocParser private function incorporateLine(ContextInterface $context) { - $cursor = new Cursor($context->getLine()); $context->getBlockCloser()->resetTip(); - $context->setBlocksParsed(false); + $cursor = new Cursor($context->getLine(), $context->getEncoding()); + $this->resetContainer($context, $cursor); $context->getBlockCloser()->setLastMatchedContainer($context->getContainer()); @@ -170,8 +172,7 @@ class DocParser { $container = $context->getDocument(); - while ($container->hasChildren()) { - $lastChild = $container->lastChild(); + while ($lastChild = $container->lastChild()) { if (!$lastChild->isOpen()) { break; } @@ -218,9 +219,9 @@ class DocParser */ private function isLazyParagraphContinuation(ContextInterface $context, Cursor $cursor) { - return !$context->getBlockCloser()->areAllClosed() && + return $context->getTip() instanceof Paragraph && + !$context->getBlockCloser()->areAllClosed() && !$cursor->isBlank() && - $context->getTip() instanceof Paragraph && count($context->getTip()->getStrings()) > 0; } diff --git a/vendor/league/commonmark/src/Inline/Element/AbstractInline.php b/vendor/league/commonmark/src/Inline/Element/AbstractInline.php index ae75500314..6d6b43410e 100644 --- a/vendor/league/commonmark/src/Inline/Element/AbstractInline.php +++ b/vendor/league/commonmark/src/Inline/Element/AbstractInline.php @@ -41,6 +41,6 @@ abstract class AbstractInline extends Node */ public function getData($key, $default = null) { - return array_key_exists($key, $this->data) ? $this->data[$key] : $default; + return isset($this->data[$key]) ? $this->data[$key] : $default; } } diff --git a/vendor/league/commonmark/src/Inline/Parser/CloseBracketParser.php b/vendor/league/commonmark/src/Inline/Parser/CloseBracketParser.php index 2fa3ba1aef..70388d6e54 100644 --- a/vendor/league/commonmark/src/Inline/Parser/CloseBracketParser.php +++ b/vendor/league/commonmark/src/Inline/Parser/CloseBracketParser.php @@ -50,11 +50,6 @@ class CloseBracketParser extends AbstractInlineParser implements EnvironmentAwar */ public function parse(InlineParserContext $inlineContext) { - $cursor = $inlineContext->getCursor(); - - $startPos = $cursor->getPosition(); - $previousState = $cursor->saveState(); - // Look through stack of delimiters for a [ or ! $opener = $inlineContext->getDelimiterStack()->searchByCharacter(['[', '!']); if ($opener === null) { @@ -68,7 +63,10 @@ class CloseBracketParser extends AbstractInlineParser implements EnvironmentAwar return false; } - $isImage = $opener->getChar() === '!'; + $cursor = $inlineContext->getCursor(); + + $startPos = $cursor->getPosition(); + $previousState = $cursor->saveState(); $cursor->advance(); @@ -81,6 +79,8 @@ class CloseBracketParser extends AbstractInlineParser implements EnvironmentAwar return false; } + $isImage = $opener->getChar() === '!'; + $inline = $this->createInline($link['url'], $link['title'], $isImage); $opener->getInlineNode()->replaceWith($inline); while (($label = $inline->next()) !== null) { diff --git a/vendor/league/commonmark/src/Inline/Renderer/LinkRenderer.php b/vendor/league/commonmark/src/Inline/Renderer/LinkRenderer.php index 293710b4d3..8402a049ab 100644 --- a/vendor/league/commonmark/src/Inline/Renderer/LinkRenderer.php +++ b/vendor/league/commonmark/src/Inline/Renderer/LinkRenderer.php @@ -56,6 +56,10 @@ class LinkRenderer implements InlineRendererInterface, ConfigurationAwareInterfa $attrs['title'] = Xml::escape($inline->data['title'], true); } + if (isset($attrs['target']) && $attrs['target'] === '_blank' && !isset($attrs['rel'])) { + $attrs['rel'] = 'noopener noreferrer'; + } + return new HtmlElement('a', $attrs, $htmlRenderer->renderInlines($inline->children())); } diff --git a/vendor/league/commonmark/src/UnmatchedBlockCloser.php b/vendor/league/commonmark/src/UnmatchedBlockCloser.php index 00ab1c8606..0dcd791842 100644 --- a/vendor/league/commonmark/src/UnmatchedBlockCloser.php +++ b/vendor/league/commonmark/src/UnmatchedBlockCloser.php @@ -53,9 +53,11 @@ class UnmatchedBlockCloser public function closeUnmatchedBlocks() { + $endLine = $this->context->getLineNumber() - 1; + while ($this->oldTip !== $this->lastMatchedContainer) { $oldTip = $this->oldTip->parent(); - $this->oldTip->finalize($this->context, $this->context->getLineNumber() - 1); + $this->oldTip->finalize($this->context, $endLine); $this->oldTip = $oldTip; } } diff --git a/vendor/league/commonmark/src/Util/LinkParserHelper.php b/vendor/league/commonmark/src/Util/LinkParserHelper.php index 36f9a6bea1..8f0e5e1a3c 100644 --- a/vendor/league/commonmark/src/Util/LinkParserHelper.php +++ b/vendor/league/commonmark/src/Util/LinkParserHelper.php @@ -76,9 +76,13 @@ final class LinkParserHelper public static function parseLinkLabel(Cursor $cursor) { $match = $cursor->match('/^\[(?:[^\\\\\[\]]|' . RegexHelper::PARTIAL_ESCAPED_CHAR . '|\\\\)*\]/'); + if ($match === null || preg_match('/[^\\\\]\\\\\]$/', $match)) { + return 0; + } + $length = mb_strlen($match, 'utf-8'); - if ($match === null || $length > 1001 || preg_match('/[^\\\\]\\\\\]$/', $match)) { + if ($length > 1001) { return 0; } diff --git a/vendor/league/commonmark/src/Util/RegexHelper.php b/vendor/league/commonmark/src/Util/RegexHelper.php index 43e2a738a7..e06d8b6df0 100644 --- a/vendor/league/commonmark/src/Util/RegexHelper.php +++ b/vendor/league/commonmark/src/Util/RegexHelper.php @@ -316,7 +316,6 @@ final class RegexHelper */ public static function matchAll($pattern, $subject, $offset = 0) { - $matches = []; $subject = substr($subject, $offset); preg_match_all($pattern, $subject, $matches, PREG_PATTERN_ORDER); diff --git a/vendor/league/flysystem/src/Adapter/Local.php b/vendor/league/flysystem/src/Adapter/Local.php index 238d91fea7..1bdf51d81f 100644 --- a/vendor/league/flysystem/src/Adapter/Local.php +++ b/vendor/league/flysystem/src/Adapter/Local.php @@ -33,13 +33,13 @@ class Local extends AbstractAdapter */ protected static $permissions = [ 'file' => [ - 'public' => 0644, + 'public' => 0644, 'private' => 0600, ], - 'dir' => [ - 'public' => 0755, + 'dir' => [ + 'public' => 0755, 'private' => 0700, - ] + ], ]; /** @@ -56,6 +56,7 @@ class Local extends AbstractAdapter * @var int */ protected $writeFlags; + /** * @var int */ @@ -99,11 +100,16 @@ class Local extends AbstractAdapter { if ( ! is_dir($root)) { $umask = umask(0); - @mkdir($root, $this->permissionMap['dir']['public'], true); + + if ( ! @mkdir($root, $this->permissionMap['dir']['public'], true)) { + $mkdirError = error_get_last(); + } + umask($umask); if ( ! is_dir($root)) { - throw new Exception(sprintf('Impossible to create the root directory "%s".', $root)); + $errorMessage = isset($mkdirError['message']) ? $mkdirError['message'] : ''; + throw new Exception(sprintf('Impossible to create the root directory "%s". %s', $root, $errorMessage)); } } } diff --git a/vendor/league/flysystem/src/Util/MimeType.php b/vendor/league/flysystem/src/Util/MimeType.php index 58622a2ee6..254bc2a141 100644 --- a/vendor/league/flysystem/src/Util/MimeType.php +++ b/vendor/league/flysystem/src/Util/MimeType.php @@ -58,6 +58,7 @@ class MimeType 'z' => 'application/x-compress', 'xhtml' => 'application/xhtml+xml', 'xht' => 'application/xhtml+xml', + 'rdf' => 'application/rdf+xml', 'zip' => 'application/x-zip', 'rar' => 'application/x-rar', 'mid' => 'audio/midi', diff --git a/vendor/symfony/cache/Adapter/AbstractAdapter.php b/vendor/symfony/cache/Adapter/AbstractAdapter.php index 7b7336f278..571eb1468a 100644 --- a/vendor/symfony/cache/Adapter/AbstractAdapter.php +++ b/vendor/symfony/cache/Adapter/AbstractAdapter.php @@ -19,13 +19,16 @@ 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\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Nicolas Grekas <p@tchwork.com> */ -abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface +abstract class AbstractAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { use AbstractTrait; + use ContractsTrait; private static $apcuSupported; private static $phpFilesSupported; @@ -33,11 +36,7 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface private $createCacheItem; private $mergeByLifetime; - /** - * @param string $namespace - * @param int $defaultLifetime - */ - protected function __construct($namespace = '', $defaultLifetime = 0) + protected function __construct(string $namespace = '', int $defaultLifetime = 0) { $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { @@ -47,30 +46,44 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface function ($key, $value, $isHit) use ($defaultLifetime) { $item = new CacheItem(); $item->key = $key; - $item->value = $value; + $item->value = $v = $value; $item->isHit = $isHit; $item->defaultLifetime = $defaultLifetime; + // Detect wrapped values that encode for their expiry and creation duration + // For compactness, these values are packed in the key of an array using + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = \key($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + $item->value = $v[$k]; + $v = \unpack('Ve/Nc', \substr($k, 1, -1)); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } return $item; }, null, CacheItem::class ); - $getId = function ($key) { return $this->getId((string) $key); }; + $getId = \Closure::fromCallable(array($this, 'getId')); $this->mergeByLifetime = \Closure::bind( function ($deferred, $namespace, &$expiredIds) use ($getId) { $byLifetime = array(); - $now = time(); + $now = microtime(true); $expiredIds = array(); foreach ($deferred as $key => $item) { + $key = (string) $key; if (null === $item->expiry) { - $byLifetime[0 < $item->defaultLifetime ? $item->defaultLifetime : 0][$getId($key)] = $item->value; - } elseif ($item->expiry > $now) { - $byLifetime[$item->expiry - $now][$getId($key)] = $item->value; - } else { + $ttl = 0 < $item->defaultLifetime ? $item->defaultLifetime : 0; + } elseif (0 >= $ttl = (int) ($item->expiry - $now)) { $expiredIds[] = $getId($key); + continue; + } + if (isset(($metadata = $item->newMetadata)[CacheItem::METADATA_TAGS])) { + unset($metadata[CacheItem::METADATA_TAGS]); } + // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators + $byLifetime[$ttl][$getId($key)] = $metadata ? array("\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $item->value) : $item->value; } return $byLifetime; @@ -81,6 +94,10 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface } /** + * Returns an ApcuAdapter if supported, a PhpFilesAdapter otherwise. + * + * Using ApcuAdapter makes system caches compatible with read-only filesystems. + * * @param string $namespace * @param int $defaultLifetime * @param string $version @@ -95,12 +112,8 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface self::$apcuSupported = ApcuAdapter::isSupported(); } - if (!self::$apcuSupported && null === self::$phpFilesSupported) { - self::$phpFilesSupported = PhpFilesAdapter::isSupported(); - } - - if (self::$phpFilesSupported) { - $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory); + if (!self::$apcuSupported) { + $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true); if (null !== $logger) { $opcache->setLogger($logger); } @@ -108,22 +121,14 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface return $opcache; } - $fs = new FilesystemAdapter($namespace, $defaultLifetime, $directory); - if (null !== $logger) { - $fs->setLogger($logger); - } - if (!self::$apcuSupported) { - return $fs; - } - $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version); - if ('cli' === \PHP_SAPI && !ini_get('apc.enable_cli')) { + if ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN)) { $apcu->setLogger(new NullLogger()); } elseif (null !== $logger) { $apcu->setLogger($logger); } - return new ChainAdapter(array($apcu, $fs)); + return $apcu; } public static function createConnection($dsn, array $options = array()) @@ -131,10 +136,10 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface 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:')) { return RedisAdapter::createConnection($dsn, $options); } - if (0 === strpos($dsn, 'memcached://')) { + if (0 === strpos($dsn, 'memcached:')) { return MemcachedAdapter::createConnection($dsn, $options); } diff --git a/vendor/symfony/cache/Adapter/ApcuAdapter.php b/vendor/symfony/cache/Adapter/ApcuAdapter.php index 50554ed688..7db3956588 100644 --- a/vendor/symfony/cache/Adapter/ApcuAdapter.php +++ b/vendor/symfony/cache/Adapter/ApcuAdapter.php @@ -18,13 +18,9 @@ class ApcuAdapter extends AbstractAdapter use ApcuTrait; /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $version - * * @throws CacheException if APCu is not enabled */ - public function __construct($namespace = '', $defaultLifetime = 0, $version = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null) { $this->init($namespace, $defaultLifetime, $version); } diff --git a/vendor/symfony/cache/Adapter/ArrayAdapter.php b/vendor/symfony/cache/Adapter/ArrayAdapter.php index 9c4332058c..47db1271b2 100644 --- a/vendor/symfony/cache/Adapter/ArrayAdapter.php +++ b/vendor/symfony/cache/Adapter/ArrayAdapter.php @@ -16,11 +16,12 @@ use Psr\Log\LoggerAwareInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\ResettableInterface; use Symfony\Component\Cache\Traits\ArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Nicolas Grekas <p@tchwork.com> */ -class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, ResettableInterface +class ArrayAdapter implements AdapterInterface, CacheInterface, LoggerAwareInterface, ResettableInterface { use ArrayTrait; @@ -30,7 +31,7 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable * @param int $defaultLifetime * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise */ - public function __construct($defaultLifetime = 0, $storeSerialized = true) + public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true) { $this->storeSerialized = $storeSerialized; $this->createCacheItem = \Closure::bind( @@ -51,24 +52,28 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable /** * {@inheritdoc} */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + $item = $this->getItem($key); + $metadata = $item->getMetadata(); + + // ArrayAdapter works in memory, we don't care about stampede protection + if (INF === $beta || !$item->isHit()) { + $this->save($item->set($callback($item))); + } + + return $item->get(); + } + + /** + * {@inheritdoc} + */ public function getItem($key) { - $isHit = $this->hasItem($key); - try { - if (!$isHit) { - $this->values[$key] = $value = null; - } elseif (!$this->storeSerialized) { - $value = $this->values[$key]; - } elseif ('b:0;' === $value = $this->values[$key]) { - $value = false; - } elseif (false === $value = unserialize($value)) { - $this->values[$key] = $value = null; - $isHit = false; - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e)); + if (!$isHit = $this->hasItem($key)) { $this->values[$key] = $value = null; - $isHit = false; + } else { + $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key]; } $f = $this->createCacheItem; @@ -81,10 +86,12 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable public function getItems(array $keys = array()) { foreach ($keys as $key) { - CacheItem::validateKey($key); + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } } - return $this->generateItems($keys, time(), $this->createCacheItem); + return $this->generateItems($keys, microtime(true), $this->createCacheItem); } /** @@ -112,23 +119,16 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable $value = $item["\0*\0value"]; $expiry = $item["\0*\0expiry"]; - if (null !== $expiry && $expiry <= time()) { + if (null !== $expiry && $expiry <= microtime(true)) { $this->deleteItem($key); return true; } - if ($this->storeSerialized) { - try { - $value = serialize($value); - } catch (\Exception $e) { - $type = \is_object($value) ? \get_class($value) : \gettype($value); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); - - return false; - } + if ($this->storeSerialized && null === $value = $this->freeze($value)) { + return false; } if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) { - $expiry = time() + $item["\0*\0defaultLifetime"]; + $expiry = microtime(true) + $item["\0*\0defaultLifetime"]; } $this->values[$key] = $value; @@ -152,4 +152,12 @@ class ArrayAdapter implements AdapterInterface, LoggerAwareInterface, Resettable { return true; } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); + } } diff --git a/vendor/symfony/cache/Adapter/ChainAdapter.php b/vendor/symfony/cache/Adapter/ChainAdapter.php index 72ff4c19fb..0417a22cd1 100644 --- a/vendor/symfony/cache/Adapter/ChainAdapter.php +++ b/vendor/symfony/cache/Adapter/ChainAdapter.php @@ -17,6 +17,9 @@ 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\ContractsTrait; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; /** * Chains several adapters together. @@ -26,8 +29,10 @@ use Symfony\Component\Cache\ResettableInterface; * * @author Kévin Dunglas <dunglas@gmail.com> */ -class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class ChainAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { + use ContractsTrait; + private $adapters = array(); private $adapterCount; private $syncItem; @@ -36,7 +41,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn * @param CacheItemPoolInterface[] $adapters The ordered list of adapters used to fetch cached items * @param int $defaultLifetime The default lifetime of items propagated from lower adapters to upper ones */ - public function __construct(array $adapters, $defaultLifetime = 0) + public function __construct(array $adapters, int $defaultLifetime = 0) { if (!$adapters) { throw new InvalidArgumentException('At least one adapter must be specified.'); @@ -60,6 +65,10 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn $item->value = $sourceItem->value; $item->expiry = $sourceItem->expiry; $item->isHit = $sourceItem->isHit; + $item->metadata = $sourceItem->metadata; + + $sourceItem->isTaggable = false; + unset($sourceItem->metadata[CacheItem::METADATA_TAGS]); if (0 < $sourceItem->defaultLifetime && $sourceItem->defaultLifetime < $defaultLifetime) { $defaultLifetime = $sourceItem->defaultLifetime; @@ -78,6 +87,34 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn /** * {@inheritdoc} */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + $lastItem = null; + $i = 0; + $wrap = function (CacheItem $item = null) use ($key, $callback, $beta, &$wrap, &$i, &$lastItem, &$metadata) { + $adapter = $this->adapters[$i]; + if (isset($this->adapters[++$i])) { + $callback = $wrap; + $beta = INF === $beta ? INF : 0; + } + if ($adapter instanceof CacheInterface) { + $value = $adapter->get($key, $callback, $beta, $metadata); + } else { + $value = $this->doGet($adapter, $key, $callback, $beta, $metadata); + } + if (null !== $item) { + ($this->syncItem)($lastItem = $lastItem ?? $item, $item); + } + + return $value; + }; + + return $wrap(); + } + + /** + * {@inheritdoc} + */ public function getItem($key) { $syncItem = $this->syncItem; @@ -265,7 +302,7 @@ class ChainAdapter implements AdapterInterface, PruneableInterface, ResettableIn public function reset() { foreach ($this->adapters as $adapter) { - if ($adapter instanceof ResettableInterface) { + if ($adapter instanceof ResetInterface) { $adapter->reset(); } } diff --git a/vendor/symfony/cache/Adapter/DoctrineAdapter.php b/vendor/symfony/cache/Adapter/DoctrineAdapter.php index 972d2b4154..75ae4cb701 100644 --- a/vendor/symfony/cache/Adapter/DoctrineAdapter.php +++ b/vendor/symfony/cache/Adapter/DoctrineAdapter.php @@ -18,12 +18,7 @@ class DoctrineAdapter extends AbstractAdapter { use DoctrineTrait; - /** - * @param CacheProvider $provider - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0) { parent::__construct('', $defaultLifetime); $this->provider = $provider; diff --git a/vendor/symfony/cache/Adapter/FilesystemAdapter.php b/vendor/symfony/cache/Adapter/FilesystemAdapter.php index d071964ec2..7185dd4877 100644 --- a/vendor/symfony/cache/Adapter/FilesystemAdapter.php +++ b/vendor/symfony/cache/Adapter/FilesystemAdapter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\FilesystemTrait; @@ -18,13 +20,9 @@ class FilesystemAdapter extends AbstractAdapter implements PruneableInterface { use FilesystemTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory - */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); } diff --git a/vendor/symfony/cache/Adapter/MemcachedAdapter.php b/vendor/symfony/cache/Adapter/MemcachedAdapter.php index 5637141a77..b678bb5d88 100644 --- a/vendor/symfony/cache/Adapter/MemcachedAdapter.php +++ b/vendor/symfony/cache/Adapter/MemcachedAdapter.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\MemcachedTrait; class MemcachedAdapter extends AbstractAdapter @@ -29,8 +30,8 @@ class MemcachedAdapter extends AbstractAdapter * * Using a MemcachedAdapter as a pure items store is fine. */ - public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) + public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($client, $namespace, $defaultLifetime); + $this->init($client, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Adapter/NullAdapter.php b/vendor/symfony/cache/Adapter/NullAdapter.php index f58f81e5b8..3c88a6902a 100644 --- a/vendor/symfony/cache/Adapter/NullAdapter.php +++ b/vendor/symfony/cache/Adapter/NullAdapter.php @@ -13,11 +13,12 @@ namespace Symfony\Component\Cache\Adapter; use Psr\Cache\CacheItemInterface; use Symfony\Component\Cache\CacheItem; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Titouan Galopin <galopintitouan@gmail.com> */ -class NullAdapter implements AdapterInterface +class NullAdapter implements AdapterInterface, CacheInterface { private $createCacheItem; @@ -39,6 +40,14 @@ class NullAdapter implements AdapterInterface /** * {@inheritdoc} */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + return $callback(($this->createCacheItem)()); + } + + /** + * {@inheritdoc} + */ public function getItem($key) { $f = $this->createCacheItem; @@ -110,6 +119,14 @@ class NullAdapter implements AdapterInterface return false; } + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); + } + private function generateItems(array $keys) { $f = $this->createCacheItem; diff --git a/vendor/symfony/cache/Adapter/PdoAdapter.php b/vendor/symfony/cache/Adapter/PdoAdapter.php index c3fc45b672..eb35fb38a9 100644 --- a/vendor/symfony/cache/Adapter/PdoAdapter.php +++ b/vendor/symfony/cache/Adapter/PdoAdapter.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Adapter; use Doctrine\DBAL\Connection; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PdoTrait; @@ -27,6 +28,9 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface * a Doctrine DBAL Connection or a DSN string that will be used to * lazy-connect to the database when the cache is actually used. * + * When a Doctrine DBAL Connection is passed, the cache table is created + * automatically when possible. Otherwise, use the createTable() method. + * * List of available options: * * db_table: The name of the table [default: cache_items] * * db_id_col: The column where to store the cache id [default: item_id] @@ -37,17 +41,14 @@ class PdoAdapter extends AbstractAdapter implements PruneableInterface * * db_password: The password when lazy-connect [default: ''] * * db_connection_options: An array of driver-specific connection options [default: array()] * - * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null - * @param string $namespace - * @param int $defaultLifetime - * @param array $options An associative array of options + * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null * * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION * @throws InvalidArgumentException When namespace contains invalid characters */ - public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = array()) + public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = array(), MarshallerInterface $marshaller = null) { - $this->init($connOrDsn, $namespace, $defaultLifetime, $options); + $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller); } } diff --git a/vendor/symfony/cache/Adapter/PhpArrayAdapter.php b/vendor/symfony/cache/Adapter/PhpArrayAdapter.php index 87c8090b91..a145a361d1 100644 --- a/vendor/symfony/cache/Adapter/PhpArrayAdapter.php +++ b/vendor/symfony/cache/Adapter/PhpArrayAdapter.php @@ -17,7 +17,9 @@ 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\ContractsTrait; use Symfony\Component\Cache\Traits\PhpArrayTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * Caches items at warm up time using a PHP array that is stored in shared memory by OPCache since PHP 7.0. @@ -26,9 +28,10 @@ use Symfony\Component\Cache\Traits\PhpArrayTrait; * @author Titouan Galopin <galopintitouan@gmail.com> * @author Nicolas Grekas <p@tchwork.com> */ -class PhpArrayAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { use PhpArrayTrait; + use ContractsTrait; private $createCacheItem; @@ -36,11 +39,10 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl * @param string $file The PHP file were values are cached * @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit */ - public function __construct($file, AdapterInterface $fallbackPool) + public function __construct(string $file, AdapterInterface $fallbackPool) { $this->file = $file; $this->pool = $fallbackPool; - $this->zendDetectUnicode = ini_get('zend.detect_unicode'); $this->createCacheItem = \Closure::bind( function ($key, $value, $isHit) { $item = new CacheItem(); @@ -56,19 +58,17 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl } /** - * This adapter should only be used on PHP 7.0+ to take advantage of how PHP - * stores arrays in its latest versions. This factory method decorates the given - * fallback pool with this adapter only if the current PHP version is supported. + * This adapter takes advantage of how PHP stores arrays in its latest versions. * * @param string $file The PHP file were values are cached - * @param CacheItemPoolInterface $fallbackPool Fallback for old PHP versions or opcache disabled + * @param CacheItemPoolInterface $fallbackPool Fallback when opcache is disabled * * @return CacheItemPoolInterface */ public static function create($file, CacheItemPoolInterface $fallbackPool) { - // Shared memory is available in PHP 7.0+ with OPCache enabled and in HHVM - if ((\PHP_VERSION_ID >= 70000 && ini_get('opcache.enable')) || \defined('HHVM_VERSION')) { + // Shared memory is available in PHP 7.0+ with OPCache enabled + if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { if (!$fallbackPool instanceof AdapterInterface) { $fallbackPool = new ProxyAdapter($fallbackPool); } @@ -82,6 +82,39 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl /** * {@inheritdoc} */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + if (null === $this->values) { + $this->initialize(); + } + if (!isset($this->keys[$key])) { + get_from_pool: + if ($this->pool instanceof CacheInterface) { + return $this->pool->get($key, $callback, $beta, $metadata); + } + + return $this->doGet($this->pool, $key, $callback, $beta, $metadata); + } + $value = $this->values[$this->keys[$key]]; + + if ('N;' === $value) { + return null; + } + try { + if ($value instanceof \Closure) { + return $value(); + } + } catch (\Throwable $e) { + unset($this->keys[$key]); + goto get_from_pool; + } + + return $value; + } + + /** + * {@inheritdoc} + */ public function getItem($key) { if (!\is_string($key)) { @@ -90,23 +123,19 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl if (null === $this->values) { $this->initialize(); } - if (!isset($this->values[$key])) { + if (!isset($this->keys[$key])) { return $this->pool->getItem($key); } - $value = $this->values[$key]; + $value = $this->values[$this->keys[$key]]; $isHit = true; if ('N;' === $value) { $value = null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + } elseif ($value instanceof \Closure) { try { - $e = null; - $value = unserialize($value); - } catch (\Error $e) { - } catch (\Exception $e) { - } - if (null !== $e) { + $value = $value(); + } catch (\Throwable $e) { $value = null; $isHit = false; } @@ -146,7 +175,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl $this->initialize(); } - return isset($this->values[$key]) || $this->pool->hasItem($key); + return isset($this->keys[$key]) || $this->pool->hasItem($key); } /** @@ -161,7 +190,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl $this->initialize(); } - return !isset($this->values[$key]) && $this->pool->deleteItem($key); + return !isset($this->keys[$key]) && $this->pool->deleteItem($key); } /** @@ -177,7 +206,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); } - if (isset($this->values[$key])) { + if (isset($this->keys[$key])) { $deleted = false; } else { $fallbackKeys[] = $key; @@ -203,7 +232,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl $this->initialize(); } - return !isset($this->values[$item->getKey()]) && $this->pool->save($item); + return !isset($this->keys[$item->getKey()]) && $this->pool->save($item); } /** @@ -215,7 +244,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl $this->initialize(); } - return !isset($this->values[$item->getKey()]) && $this->pool->saveDeferred($item); + return !isset($this->keys[$item->getKey()]) && $this->pool->saveDeferred($item); } /** @@ -226,26 +255,21 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl return $this->pool->commit(); } - /** - * @return \Generator - */ - private function generateItems(array $keys) + private function generateItems(array $keys): \Generator { $f = $this->createCacheItem; $fallbackKeys = array(); foreach ($keys as $key) { - if (isset($this->values[$key])) { - $value = $this->values[$key]; + if (isset($this->keys[$key])) { + $value = $this->values[$this->keys[$key]]; if ('N;' === $value) { yield $key => $f($key, null, true); - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + } elseif ($value instanceof \Closure) { try { - yield $key => $f($key, unserialize($value), true); - } catch (\Error $e) { - yield $key => $f($key, null, false); - } catch (\Exception $e) { + yield $key => $f($key, $value(), true); + } catch (\Throwable $e) { yield $key => $f($key, null, false); } } else { @@ -257,9 +281,7 @@ class PhpArrayAdapter implements AdapterInterface, PruneableInterface, Resettabl } if ($fallbackKeys) { - foreach ($this->pool->getItems($fallbackKeys) as $key => $item) { - yield $key => $item; - } + yield from $this->pool->getItems($fallbackKeys); } } diff --git a/vendor/symfony/cache/Adapter/PhpFilesAdapter.php b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php index 528d9c01fb..1f4e05e176 100644 --- a/vendor/symfony/cache/Adapter/PhpFilesAdapter.php +++ b/vendor/symfony/cache/Adapter/PhpFilesAdapter.php @@ -20,22 +20,19 @@ class PhpFilesAdapter extends AbstractAdapter implements PruneableInterface use PhpFilesTrait; /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory + * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire. + * Doing so is encouraged because it fits perfectly OPcache's memory model. * * @throws CacheException if OPcache is not enabled */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false) { - if (!static::isSupported()) { - throw new CacheException('OPcache is not enabled'); - } + $this->appendOnly = $appendOnly; + self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); $e = new \Exception(); $this->includeHandler = function () use ($e) { throw $e; }; - $this->zendDetectUnicode = ini_get('zend.detect_unicode'); } } diff --git a/vendor/symfony/cache/Adapter/ProxyAdapter.php b/vendor/symfony/cache/Adapter/ProxyAdapter.php index 7682c72474..d6b888788d 100644 --- a/vendor/symfony/cache/Adapter/ProxyAdapter.php +++ b/vendor/symfony/cache/Adapter/ProxyAdapter.php @@ -16,26 +16,25 @@ use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Contracts\Cache\CacheInterface; /** * @author Nicolas Grekas <p@tchwork.com> */ -class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class ProxyAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { use ProxyTrait; + use ContractsTrait; private $namespace; private $namespaceLen; private $createCacheItem; + private $setInnerItem; private $poolHash; - /** - * @param CacheItemPoolInterface $pool - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(CacheItemPoolInterface $pool, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheItemPoolInterface $pool, string $namespace = '', int $defaultLifetime = 0) { $this->pool = $pool; $this->poolHash = $poolHash = spl_object_hash($pool); @@ -45,11 +44,22 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn function ($key, $innerItem) use ($defaultLifetime, $poolHash) { $item = new CacheItem(); $item->key = $key; - $item->value = $innerItem->get(); + $item->value = $v = $innerItem->get(); $item->isHit = $innerItem->isHit(); $item->defaultLifetime = $defaultLifetime; $item->innerItem = $innerItem; $item->poolHash = $poolHash; + // Detect wrapped values that encode for their expiry and creation duration + // For compactness, these values are packed in the key of an array using + // magic numbers in the form 9D-..-..-..-..-00-..-..-..-5F + if (\is_array($v) && 1 === \count($v) && 10 === \strlen($k = \key($v)) && "\x9D" === $k[0] && "\0" === $k[5] && "\x5F" === $k[9]) { + $item->value = $v[$k]; + $v = \unpack('Ve/Nc', \substr($k, 1, -1)); + $item->metadata[CacheItem::METADATA_EXPIRY] = $v['e'] + CacheItem::METADATA_EXPIRY_OFFSET; + $item->metadata[CacheItem::METADATA_CTIME] = $v['c']; + } elseif ($innerItem instanceof CacheItem) { + $item->metadata = $innerItem->metadata; + } $innerItem->set(null); return $item; @@ -57,6 +67,43 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn null, CacheItem::class ); + $this->setInnerItem = \Closure::bind( + /** + * @param array $item A CacheItem cast to (array); accessing protected properties requires adding the "\0*\0" PHP prefix + */ + function (CacheItemInterface $innerItem, array $item) { + // Tags are stored separately, no need to account for them when considering this item's newly set metadata + if (isset(($metadata = $item["\0*\0newMetadata"])[CacheItem::METADATA_TAGS])) { + unset($metadata[CacheItem::METADATA_TAGS]); + } + if ($metadata) { + // For compactness, expiry and creation duration are packed in the key of an array, using magic numbers as separators + $item["\0*\0value"] = array("\x9D".pack('VN', (int) $metadata[CacheItem::METADATA_EXPIRY] - CacheItem::METADATA_EXPIRY_OFFSET, $metadata[CacheItem::METADATA_CTIME])."\x5F" => $item["\0*\0value"]); + } + $innerItem->set($item["\0*\0value"]); + $innerItem->expiresAt(null !== $item["\0*\0expiry"] ? \DateTime::createFromFormat('U.u', sprintf('%.6f', $item["\0*\0expiry"])) : null); + }, + null, + CacheItem::class + ); + } + + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + if (!$this->pool instanceof CacheInterface) { + return $this->doGet($this, $key, $callback, $beta, $metadata); + } + + return $this->pool->get($this->getId($key), function ($innerItem) use ($key, $callback) { + $item = ($this->createCacheItem)($key, $innerItem); + $item->set($value = $callback($item)); + ($this->setInnerItem)($innerItem, (array) $item); + + return $value; + }, $beta, $metadata); } /** @@ -152,13 +199,11 @@ class ProxyAdapter implements AdapterInterface, PruneableInterface, ResettableIn return false; } $item = (array) $item; - $expiry = $item["\0*\0expiry"]; - if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) { - $expiry = time() + $item["\0*\0defaultLifetime"]; + if (null === $item["\0*\0expiry"] && 0 < $item["\0*\0defaultLifetime"]) { + $item["\0*\0expiry"] = microtime(true) + $item["\0*\0defaultLifetime"]; } $innerItem = $item["\0*\0poolHash"] === $this->poolHash ? $item["\0*\0innerItem"] : $this->pool->getItem($this->namespace.$item["\0*\0key"]); - $innerItem->set($item["\0*\0value"]); - $innerItem->expiresAt(null !== $expiry ? \DateTime::createFromFormat('U', $expiry) : null); + ($this->setInnerItem)($innerItem, $item); return $this->pool->$method($innerItem); } diff --git a/vendor/symfony/cache/Adapter/RedisAdapter.php b/vendor/symfony/cache/Adapter/RedisAdapter.php index c1e17997fb..9d3931d1f4 100644 --- a/vendor/symfony/cache/Adapter/RedisAdapter.php +++ b/vendor/symfony/cache/Adapter/RedisAdapter.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\RedisTrait; class RedisAdapter extends AbstractAdapter @@ -22,8 +23,8 @@ class RedisAdapter extends AbstractAdapter * @param string $namespace The default namespace * @param int $defaultLifetime The default lifetime */ - public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) + public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($redisClient, $namespace, $defaultLifetime); + $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php index 24db5d504a..2e6d03a1f0 100644 --- a/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php +++ b/vendor/symfony/cache/Adapter/SimpleCacheAdapter.php @@ -25,7 +25,7 @@ class SimpleCacheAdapter extends AbstractAdapter implements PruneableInterface, private $miss; - public function __construct(CacheInterface $pool, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheInterface $pool, string $namespace = '', int $defaultLifetime = 0) { parent::__construct($namespace, $defaultLifetime); diff --git a/vendor/symfony/cache/Adapter/TagAwareAdapter.php b/vendor/symfony/cache/Adapter/TagAwareAdapter.php index 62f815e017..4144ffea74 100644 --- a/vendor/symfony/cache/Adapter/TagAwareAdapter.php +++ b/vendor/symfony/cache/Adapter/TagAwareAdapter.php @@ -16,16 +16,19 @@ use Psr\Cache\InvalidArgumentException; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Component\Cache\Traits\ContractsTrait; use Symfony\Component\Cache\Traits\ProxyTrait; +use Symfony\Contracts\Cache\TagAwareCacheInterface; /** * @author Nicolas Grekas <p@tchwork.com> */ -class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, ResettableInterface +class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface { const TAGS_PREFIX = "\0tags\0"; use ProxyTrait; + use ContractsTrait; private $deferred = array(); private $createCacheItem; @@ -36,7 +39,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R private $knownTagVersions = array(); private $knownTagVersionsTtl; - public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, $knownTagVersionsTtl = 0.15) + public function __construct(AdapterInterface $itemsPool, AdapterInterface $tagsPool = null, float $knownTagVersionsTtl = 0.15) { $this->pool = $itemsPool; $this->tags = $tagsPool ?: $itemsPool; @@ -58,12 +61,13 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R ); $this->setCacheItemTags = \Closure::bind( function (CacheItem $item, $key, array &$itemTags) { + $item->isTaggable = true; if (!$item->isHit) { return $item; } if (isset($itemTags[$key])) { foreach ($itemTags[$key] as $tag => $version) { - $item->prevTags[$tag] = $tag; + $item->metadata[CacheItem::METADATA_TAGS][$tag] = $tag; } unset($itemTags[$key]); } else { @@ -80,7 +84,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface, PruneableInterface, R function ($deferred) { $tagsByKey = array(); foreach ($deferred as $key => $item) { - $tagsByKey[$key] = $item->tags; + $tagsByKey[$key] = $item->newMetadata[CacheItem::METADATA_TAGS] ?? array(); } return $tagsByKey; diff --git a/vendor/symfony/cache/Adapter/TraceableAdapter.php b/vendor/symfony/cache/Adapter/TraceableAdapter.php index 98d0e52693..e1d96bb4ef 100644 --- a/vendor/symfony/cache/Adapter/TraceableAdapter.php +++ b/vendor/symfony/cache/Adapter/TraceableAdapter.php @@ -12,8 +12,11 @@ namespace Symfony\Component\Cache\Adapter; use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Service\ResetInterface; /** * An adapter that collects data about all cache calls. @@ -22,7 +25,7 @@ use Symfony\Component\Cache\ResettableInterface; * @author Tobias Nyholm <tobias.nyholm@gmail.com> * @author Nicolas Grekas <p@tchwork.com> */ -class TraceableAdapter implements AdapterInterface, PruneableInterface, ResettableInterface +class TraceableAdapter implements AdapterInterface, CacheInterface, PruneableInterface, ResettableInterface { protected $pool; private $calls = array(); @@ -35,6 +38,38 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab /** * {@inheritdoc} */ + public function get(string $key, callable $callback, float $beta = null, array &$metadata = null) + { + if (!$this->pool instanceof CacheInterface) { + throw new \BadMethodCallException(sprintf('Cannot call "%s::get()": this class doesn\'t implement "%s".', \get_class($this->pool), CacheInterface::class)); + } + + $isHit = true; + $callback = function (CacheItem $item) use ($callback, &$isHit) { + $isHit = $item->isHit(); + + return $callback($item); + }; + + $event = $this->start(__FUNCTION__); + try { + $value = $this->pool->get($key, $callback, $beta, $metadata); + $event->result[$key] = \is_object($value) ? \get_class($value) : \gettype($value); + } finally { + $event->end = microtime(true); + } + if ($isHit) { + ++$event->hits; + } else { + ++$event->misses; + } + + return $value; + } + + /** + * {@inheritdoc} + */ public function getItem($key) { $event = $this->start(__FUNCTION__); @@ -191,7 +226,7 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab */ public function reset() { - if (!$this->pool instanceof ResettableInterface) { + if (!$this->pool instanceof ResetInterface) { return; } $event = $this->start(__FUNCTION__); @@ -202,6 +237,19 @@ class TraceableAdapter implements AdapterInterface, PruneableInterface, Resettab } } + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + $event = $this->start(__FUNCTION__); + try { + return $event->result[$key] = $this->pool->deleteItem($key); + } finally { + $event->end = microtime(true); + } + } + public function getCalls() { return $this->calls; diff --git a/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php index de68955d8e..69461b8b6b 100644 --- a/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php +++ b/vendor/symfony/cache/Adapter/TraceableTagAwareAdapter.php @@ -11,10 +11,12 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Contracts\Cache\TagAwareCacheInterface; + /** * @author Robin Chalas <robin.chalas@gmail.com> */ -class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface +class TraceableTagAwareAdapter extends TraceableAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface { public function __construct(TagAwareAdapterInterface $pool) { diff --git a/vendor/symfony/cache/CHANGELOG.md b/vendor/symfony/cache/CHANGELOG.md index 11c1b9364e..9016bc5dbf 100644 --- a/vendor/symfony/cache/CHANGELOG.md +++ b/vendor/symfony/cache/CHANGELOG.md @@ -1,6 +1,24 @@ CHANGELOG ========= +4.2.0 +----- + + * added support for connecting to Redis clusters via DSN + * added support for configuring multiple Memcached servers via DSN + * added `MarshallerInterface` and `DefaultMarshaller` to allow changing the serializer and provide one that automatically uses igbinary when available + * implemented `CacheInterface`, which provides stampede protection via probabilistic early expiration and should become the preferred way to use a cache + * added sub-second expiry accuracy for backends that support it + * added support for phpredis 4 `compression` and `tcp_keepalive` options + * added automatic table creation when using Doctrine DBAL with PDO-based backends + * throw `LogicException` when `CacheItem::tag()` is called on an item coming from a non tag-aware pool + * deprecated `CacheItem::getPreviousTags()`, use `CacheItem::getMetadata()` instead + * deprecated the `AbstractAdapter::unserialize()` and `AbstractCache::unserialize()` methods + * added `CacheCollectorPass` (originally in `FrameworkBundle`) + * added `CachePoolClearerPass` (originally in `FrameworkBundle`) + * added `CachePoolPass` (originally in `FrameworkBundle`) + * added `CachePoolPrunerPass` (originally in `FrameworkBundle`) + 3.4.0 ----- @@ -13,7 +31,7 @@ CHANGELOG 3.3.0 ----- - * [EXPERIMENTAL] added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any + * added CacheItem::getPreviousTags() to get bound tags coming from the pool storage if any * added PSR-16 "Simple Cache" implementations for all existing PSR-6 adapters * added Psr6Cache and SimpleCacheAdapter for bidirectional interoperability between PSR-6 and PSR-16 * added MemcachedAdapter (PSR-6) and MemcachedCache (PSR-16) diff --git a/vendor/symfony/cache/CacheItem.php b/vendor/symfony/cache/CacheItem.php index 58ecad82d2..e0500756a4 100644 --- a/vendor/symfony/cache/CacheItem.php +++ b/vendor/symfony/cache/CacheItem.php @@ -11,24 +11,28 @@ namespace Symfony\Component\Cache; -use Psr\Cache\CacheItemInterface; use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Exception\LogicException; +use Symfony\Contracts\Cache\ItemInterface; /** * @author Nicolas Grekas <p@tchwork.com> */ -final class CacheItem implements CacheItemInterface +final class CacheItem implements ItemInterface { + private const METADATA_EXPIRY_OFFSET = 1527506807; + protected $key; protected $value; protected $isHit = false; protected $expiry; protected $defaultLifetime; - protected $tags = array(); - protected $prevTags = array(); + protected $metadata = array(); + protected $newMetadata = array(); protected $innerItem; protected $poolHash; + protected $isTaggable = false; /** * {@inheritdoc} @@ -70,9 +74,9 @@ final class CacheItem implements CacheItemInterface public function expiresAt($expiration) { if (null === $expiration) { - $this->expiry = $this->defaultLifetime > 0 ? time() + $this->defaultLifetime : null; + $this->expiry = $this->defaultLifetime > 0 ? microtime(true) + $this->defaultLifetime : null; } elseif ($expiration instanceof \DateTimeInterface) { - $this->expiry = (int) $expiration->format('U'); + $this->expiry = (float) $expiration->format('U.u'); } else { throw new InvalidArgumentException(sprintf('Expiration date must implement DateTimeInterface or be null, "%s" given', \is_object($expiration) ? \get_class($expiration) : \gettype($expiration))); } @@ -86,11 +90,11 @@ final class CacheItem implements CacheItemInterface public function expiresAfter($time) { if (null === $time) { - $this->expiry = $this->defaultLifetime > 0 ? time() + $this->defaultLifetime : null; + $this->expiry = $this->defaultLifetime > 0 ? microtime(true) + $this->defaultLifetime : null; } elseif ($time instanceof \DateInterval) { - $this->expiry = (int) \DateTime::createFromFormat('U', time())->add($time)->format('U'); + $this->expiry = microtime(true) + \DateTime::createFromFormat('U', 0)->add($time)->format('U.u'); } elseif (\is_int($time)) { - $this->expiry = $time + time(); + $this->expiry = $time + microtime(true); } else { throw new InvalidArgumentException(sprintf('Expiration date must be an integer, a DateInterval or null, "%s" given', \is_object($time) ? \get_class($time) : \gettype($time))); } @@ -99,24 +103,21 @@ final class CacheItem implements CacheItemInterface } /** - * Adds a tag to a cache item. - * - * @param string|string[] $tags A tag or array of tags - * - * @return static - * - * @throws InvalidArgumentException When $tag is not valid + * {@inheritdoc} */ - public function tag($tags) + public function tag($tags): ItemInterface { - if (!\is_array($tags)) { + if (!$this->isTaggable) { + throw new LogicException(sprintf('Cache item "%s" comes from a non tag-aware pool: you cannot tag it.', $this->key)); + } + if (!\is_iterable($tags)) { $tags = array($tags); } foreach ($tags as $tag) { if (!\is_string($tag)) { throw new InvalidArgumentException(sprintf('Cache tag must be string, "%s" given', \is_object($tag) ? \get_class($tag) : \gettype($tag))); } - if (isset($this->tags[$tag])) { + if (isset($this->newMetadata[self::METADATA_TAGS][$tag])) { continue; } if ('' === $tag) { @@ -125,20 +126,32 @@ final class CacheItem implements CacheItemInterface if (false !== strpbrk($tag, '{}()/\@:')) { throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:', $tag)); } - $this->tags[$tag] = $tag; + $this->newMetadata[self::METADATA_TAGS][$tag] = $tag; } return $this; } /** + * {@inheritdoc} + */ + public function getMetadata(): array + { + return $this->metadata; + } + + /** * Returns the list of tags bound to the value coming from the pool storage if any. * * @return array + * + * @deprecated since Symfony 4.2, use the "getMetadata()" method instead. */ public function getPreviousTags() { - return $this->prevTags; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the "getMetadata()" method instead.', __METHOD__), E_USER_DEPRECATED); + + return $this->metadata[self::METADATA_TAGS] ?? array(); } /** diff --git a/vendor/symfony/cache/DataCollector/CacheDataCollector.php b/vendor/symfony/cache/DataCollector/CacheDataCollector.php index ac5c36d2fd..5f29bfe5f2 100644 --- a/vendor/symfony/cache/DataCollector/CacheDataCollector.php +++ b/vendor/symfony/cache/DataCollector/CacheDataCollector.php @@ -104,10 +104,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter return $this->data['instances']['calls']; } - /** - * @return array - */ - private function calculateStatistics() + private function calculateStatistics(): array { $statistics = array(); foreach ($this->data['instances']['calls'] as $name => $calls) { @@ -124,7 +121,15 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter foreach ($calls as $call) { ++$statistics[$name]['calls']; $statistics[$name]['time'] += $call->end - $call->start; - if ('getItem' === $call->name) { + if ('get' === $call->name) { + ++$statistics[$name]['reads']; + if ($call->hits) { + ++$statistics[$name]['hits']; + } else { + ++$statistics[$name]['misses']; + ++$statistics[$name]['writes']; + } + } elseif ('getItem' === $call->name) { ++$statistics[$name]['reads']; if ($call->hits) { ++$statistics[$name]['hits']; @@ -158,10 +163,7 @@ class CacheDataCollector extends DataCollector implements LateDataCollectorInter return $statistics; } - /** - * @return array - */ - private function calculateTotalStatistics() + private function calculateTotalStatistics(): array { $statistics = $this->getStatistics(); $totals = array( diff --git a/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php new file mode 100644 index 0000000000..f93f97b88e --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CacheCollectorPass.php @@ -0,0 +1,72 @@ +<?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\DependencyInjection; + +use Symfony\Component\Cache\Adapter\TagAwareAdapterInterface; +use Symfony\Component\Cache\Adapter\TraceableAdapter; +use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Inject a data collector to all the cache services to be able to get detailed statistics. + * + * @author Tobias Nyholm <tobias.nyholm@gmail.com> + */ +class CacheCollectorPass implements CompilerPassInterface +{ + private $dataCollectorCacheId; + private $cachePoolTag; + private $cachePoolRecorderInnerSuffix; + + public function __construct(string $dataCollectorCacheId = 'data_collector.cache', string $cachePoolTag = 'cache.pool', string $cachePoolRecorderInnerSuffix = '.recorder_inner') + { + $this->dataCollectorCacheId = $dataCollectorCacheId; + $this->cachePoolTag = $cachePoolTag; + $this->cachePoolRecorderInnerSuffix = $cachePoolRecorderInnerSuffix; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->dataCollectorCacheId)) { + return; + } + + $collectorDefinition = $container->getDefinition($this->dataCollectorCacheId); + foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $attributes) { + $definition = $container->getDefinition($id); + if ($definition->isAbstract()) { + continue; + } + + $recorder = new Definition(is_subclass_of($definition->getClass(), TagAwareAdapterInterface::class) ? TraceableTagAwareAdapter::class : TraceableAdapter::class); + $recorder->setTags($definition->getTags()); + $recorder->setPublic($definition->isPublic()); + $recorder->setArguments(array(new Reference($innerId = $id.$this->cachePoolRecorderInnerSuffix))); + + $definition->setTags(array()); + $definition->setPublic(false); + + $container->setDefinition($innerId, $definition); + $container->setDefinition($id, $recorder); + + // Tell the collector to add the new instance + $collectorDefinition->addMethodCall('addInstance', array($id, new Reference($id))); + $collectorDefinition->setPublic(false); + } + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.php new file mode 100644 index 0000000000..be315b636d --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolClearerPass.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\Cache\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas <p@tchwork.com> + */ +class CachePoolClearerPass implements CompilerPassInterface +{ + private $cachePoolClearerTag; + + public function __construct(string $cachePoolClearerTag = 'cache.pool.clearer') + { + $this->cachePoolClearerTag = $cachePoolClearerTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $container->getParameterBag()->remove('cache.prefix.seed'); + + foreach ($container->findTaggedServiceIds($this->cachePoolClearerTag) as $id => $attr) { + $clearer = $container->getDefinition($id); + $pools = array(); + foreach ($clearer->getArgument(0) as $name => $ref) { + if ($container->hasDefinition($ref)) { + $pools[$name] = new Reference($ref); + } + } + $clearer->replaceArgument(0, $pools); + } + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php new file mode 100644 index 0000000000..92e2017e6f --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPass.php @@ -0,0 +1,167 @@ +<?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\DependencyInjection; + +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Nicolas Grekas <p@tchwork.com> + */ +class CachePoolPass implements CompilerPassInterface +{ + private $cachePoolTag; + private $kernelResetTag; + private $cacheClearerId; + private $cachePoolClearerTag; + private $cacheSystemClearerId; + private $cacheSystemClearerTag; + + public function __construct(string $cachePoolTag = 'cache.pool', string $kernelResetTag = 'kernel.reset', string $cacheClearerId = 'cache.global_clearer', string $cachePoolClearerTag = 'cache.pool.clearer', string $cacheSystemClearerId = 'cache.system_clearer', string $cacheSystemClearerTag = 'kernel.cache_clearer') + { + $this->cachePoolTag = $cachePoolTag; + $this->kernelResetTag = $kernelResetTag; + $this->cacheClearerId = $cacheClearerId; + $this->cachePoolClearerTag = $cachePoolClearerTag; + $this->cacheSystemClearerId = $cacheSystemClearerId; + $this->cacheSystemClearerTag = $cacheSystemClearerTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if ($container->hasParameter('cache.prefix.seed')) { + $seed = '.'.$container->getParameterBag()->resolveValue($container->getParameter('cache.prefix.seed')); + } else { + $seed = '_'.$container->getParameter('kernel.project_dir'); + } + $seed .= '.'.$container->getParameter('kernel.container_class'); + + $pools = array(); + $clearers = array(); + $attributes = array( + 'provider', + 'name', + 'namespace', + 'default_lifetime', + 'reset', + ); + foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) { + $adapter = $pool = $container->getDefinition($id); + if ($pool->isAbstract()) { + continue; + } + while ($adapter instanceof ChildDefinition) { + $adapter = $container->findDefinition($adapter->getParent()); + if ($t = $adapter->getTag($this->cachePoolTag)) { + $tags[0] += $t[0]; + } + } + $name = $tags[0]['name'] ?? $id; + if (!isset($tags[0]['namespace'])) { + $tags[0]['namespace'] = $this->getNamespace($seed, $name); + } + if (isset($tags[0]['clearer'])) { + $clearer = $tags[0]['clearer']; + while ($container->hasAlias($clearer)) { + $clearer = (string) $container->getAlias($clearer); + } + } else { + $clearer = null; + } + unset($tags[0]['clearer'], $tags[0]['name']); + + if (isset($tags[0]['provider'])) { + $tags[0]['provider'] = new Reference(static::getServiceProvider($container, $tags[0]['provider'])); + } + $i = 0; + foreach ($attributes as $attr) { + if (!isset($tags[0][$attr])) { + // no-op + } elseif ('reset' === $attr) { + if ($tags[0][$attr]) { + $pool->addTag($this->kernelResetTag, array('method' => $tags[0][$attr])); + } + } elseif ('namespace' !== $attr || ArrayAdapter::class !== $adapter->getClass()) { + $pool->replaceArgument($i++, $tags[0][$attr]); + } + unset($tags[0][$attr]); + } + if (!empty($tags[0])) { + throw new InvalidArgumentException(sprintf('Invalid "%s" tag for service "%s": accepted attributes are "clearer", "provider", "name", "namespace", "default_lifetime" and "reset", found "%s".', $this->cachePoolTag, $id, implode('", "', array_keys($tags[0])))); + } + + if (null !== $clearer) { + $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + + $pools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + } + + $notAliasedCacheClearerId = $this->cacheClearerId; + while ($container->hasAlias($this->cacheClearerId)) { + $this->cacheClearerId = (string) $container->getAlias($this->cacheClearerId); + } + if ($container->hasDefinition($this->cacheClearerId)) { + $clearers[$notAliasedCacheClearerId] = $pools; + } + + foreach ($clearers as $id => $pools) { + $clearer = $container->getDefinition($id); + if ($clearer instanceof ChildDefinition) { + $clearer->replaceArgument(0, $pools); + } else { + $clearer->setArgument(0, $pools); + } + $clearer->addTag($this->cachePoolClearerTag); + + if ($this->cacheSystemClearerId === $id) { + $clearer->addTag($this->cacheSystemClearerTag); + } + } + } + + private function getNamespace($seed, $id) + { + return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$seed, true))), 0, 10); + } + + /** + * @internal + */ + public static function getServiceProvider(ContainerBuilder $container, $name) + { + $container->resolveEnvPlaceholders($name, null, $usedEnvs); + + if ($usedEnvs || preg_match('#^[a-z]++:#', $name)) { + $dsn = $name; + + if (!$container->hasDefinition($name = '.cache_connection.'.ContainerBuilder::hash($dsn))) { + $definition = new Definition(AbstractAdapter::class); + $definition->setPublic(false); + $definition->setFactory(array(AbstractAdapter::class, 'createConnection')); + $definition->setArguments(array($dsn, array('lazy' => true))); + $container->setDefinition($name, $definition); + } + } + + return $name; + } +} diff --git a/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php new file mode 100644 index 0000000000..21266a871e --- /dev/null +++ b/vendor/symfony/cache/DependencyInjection/CachePoolPrunerPass.php @@ -0,0 +1,60 @@ +<?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\DependencyInjection; + +use Symfony\Component\Cache\PruneableInterface; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @author Rob Frawley 2nd <rmf@src.run> + */ +class CachePoolPrunerPass implements CompilerPassInterface +{ + private $cacheCommandServiceId; + private $cachePoolTag; + + public function __construct(string $cacheCommandServiceId = 'console.command.cache_pool_prune', string $cachePoolTag = 'cache.pool') + { + $this->cacheCommandServiceId = $cacheCommandServiceId; + $this->cachePoolTag = $cachePoolTag; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition($this->cacheCommandServiceId)) { + return; + } + + $services = array(); + + foreach ($container->findTaggedServiceIds($this->cachePoolTag) as $id => $tags) { + $class = $container->getParameterBag()->resolveValue($container->getDefinition($id)->getClass()); + + if (!$reflection = $container->getReflectionClass($class)) { + throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + + if ($reflection->implementsInterface(PruneableInterface::class)) { + $services[$id] = new Reference($id); + } + } + + $container->getDefinition($this->cacheCommandServiceId)->replaceArgument(0, new IteratorArgument($services)); + } +} diff --git a/vendor/symfony/cache/DoctrineProvider.php b/vendor/symfony/cache/DoctrineProvider.php index cebe95fbc7..3cc186962e 100644 --- a/vendor/symfony/cache/DoctrineProvider.php +++ b/vendor/symfony/cache/DoctrineProvider.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache; use Doctrine\Common\Cache\CacheProvider; use Psr\Cache\CacheItemPoolInterface; +use Symfony\Contracts\Service\ResetInterface; /** * @author Nicolas Grekas <p@tchwork.com> @@ -39,7 +40,7 @@ class DoctrineProvider extends CacheProvider implements PruneableInterface, Rese */ public function reset() { - if ($this->pool instanceof ResettableInterface) { + if ($this->pool instanceof ResetInterface) { $this->pool->reset(); } $this->setNamespace($this->getNamespace()); diff --git a/vendor/symfony/cache/Exception/LogicException.php b/vendor/symfony/cache/Exception/LogicException.php new file mode 100644 index 0000000000..d299673eb2 --- /dev/null +++ b/vendor/symfony/cache/Exception/LogicException.php @@ -0,0 +1,19 @@ +<?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\Exception; + +use Psr\Cache\CacheException as Psr6CacheInterface; +use Psr\SimpleCache\CacheException as SimpleCacheInterface; + +class LogicException extends \LogicException implements Psr6CacheInterface, SimpleCacheInterface +{ +} diff --git a/vendor/symfony/cache/LockRegistry.php b/vendor/symfony/cache/LockRegistry.php new file mode 100644 index 0000000000..0aadf33d61 --- /dev/null +++ b/vendor/symfony/cache/LockRegistry.php @@ -0,0 +1,130 @@ +<?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 Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * LockRegistry is used internally by existing adapters to protect against cache stampede. + * + * It does so by wrapping the computation of items in a pool of locks. + * Foreach each apps, there can be at most 20 concurrent processes that + * compute items at the same time and only one per cache-key. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +class LockRegistry +{ + private static $openedFiles = array(); + private static $lockedFiles = array(); + + /** + * The number of items in this list controls the max number of concurrent processes. + */ + private static $files = array( + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'AbstractAdapter.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.'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.'RedisAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'SimpleCacheAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TagAwareAdapterInterface.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableAdapter.php', + __DIR__.\DIRECTORY_SEPARATOR.'Adapter'.\DIRECTORY_SEPARATOR.'TraceableTagAwareAdapter.php', + ); + + /** + * Defines a set of existing files that will be used as keys to acquire locks. + * + * @return array The previously defined set of files + */ + public static function setFiles(array $files): array + { + $previousFiles = self::$files; + self::$files = $files; + + foreach (self::$openedFiles as $file) { + if ($file) { + flock($file, LOCK_UN); + fclose($file); + } + } + self::$openedFiles = self::$lockedFiles = array(); + + return $previousFiles; + } + + public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool) + { + $key = self::$files ? crc32($item->getKey()) % \count(self::$files) : -1; + + if ($key < 0 || (self::$lockedFiles[$key] ?? false) || !$lock = self::open($key)) { + return $callback($item, $save); + } + + while (true) { + try { + // race to get the lock in non-blocking mode + if (flock($lock, LOCK_EX | LOCK_NB)) { + self::$lockedFiles[$key] = true; + + return $callback($item, $save); + } + // if we failed the race, retry locking in blocking mode to wait for the winner + flock($lock, LOCK_SH); + } finally { + flock($lock, LOCK_UN); + unset(self::$lockedFiles[$key]); + } + static $signalingException, $signalingCallback; + $signalingException = $signalingException ?? unserialize("O:9:\"Exception\":1:{s:16:\"\0Exception\0trace\";a:0:{}}"); + $signalingCallback = $signalingCallback ?? function () use ($signalingException) { throw $signalingException; }; + + try { + $value = $pool->get($item->getKey(), $signalingCallback, 0); + $save = false; + + return $value; + } catch (\Exception $e) { + if ($signalingException !== $e) { + throw $e; + } + } + } + } + + private static function open(int $key) + { + if (null !== $h = self::$openedFiles[$key] ?? null) { + return $h; + } + set_error_handler(function () {}); + try { + $h = fopen(self::$files[$key], 'r+'); + } finally { + restore_error_handler(); + } + + self::$openedFiles[$key] = $h ?: @fopen(self::$files[$key], 'r'); + } +} diff --git a/vendor/symfony/cache/Marshaller/DefaultMarshaller.php b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php new file mode 100644 index 0000000000..16c02bb08f --- /dev/null +++ b/vendor/symfony/cache/Marshaller/DefaultMarshaller.php @@ -0,0 +1,99 @@ +<?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\Marshaller; + +use Symfony\Component\Cache\Exception\CacheException; + +/** + * Serializes/unserializes values using igbinary_serialize() if available, serialize() otherwise. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +class DefaultMarshaller implements MarshallerInterface +{ + private $useIgbinarySerialize = true; + + public function __construct(bool $useIgbinarySerialize = null) + { + if (null === $useIgbinarySerialize) { + $useIgbinarySerialize = \extension_loaded('igbinary'); + } elseif ($useIgbinarySerialize && !\extension_loaded('igbinary')) { + throw new CacheException('The "igbinary" PHP extension is not loaded.'); + } + $this->useIgbinarySerialize = $useIgbinarySerialize; + } + + /** + * {@inheritdoc} + */ + public function marshall(array $values, ?array &$failed): array + { + $serialized = $failed = array(); + + foreach ($values as $id => $value) { + try { + if ($this->useIgbinarySerialize) { + $serialized[$id] = igbinary_serialize($value); + } else { + $serialized[$id] = serialize($value); + } + } catch (\Exception $e) { + $failed[] = $id; + } + } + + return $serialized; + } + + /** + * {@inheritdoc} + */ + public function unmarshall(string $value) + { + if ('b:0;' === $value) { + return false; + } + if ('N;' === $value) { + return null; + } + static $igbinaryNull; + if ($value === ($igbinaryNull ?? $igbinaryNull = \extension_loaded('igbinary') ? igbinary_serialize(null) : false)) { + return null; + } + $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); + try { + if (':' === ($value[1] ?? ':')) { + if (false !== $value = unserialize($value)) { + return $value; + } + } elseif (false === $igbinaryNull) { + throw new \RuntimeException('Failed to unserialize values, did you forget to install the "igbinary" extension?'); + } elseif (null !== $value = igbinary_unserialize($value)) { + return $value; + } + + throw new \DomainException(error_get_last() ? error_get_last()['message'] : 'Failed to unserialize values.'); + } catch (\Error $e) { + throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine()); + } finally { + ini_set('unserialize_callback_func', $unserializeCallbackHandler); + } + } + + /** + * @internal + */ + public static function handleUnserializeCallback($class) + { + throw new \DomainException('Class not found: '.$class); + } +} diff --git a/vendor/symfony/cache/Marshaller/MarshallerInterface.php b/vendor/symfony/cache/Marshaller/MarshallerInterface.php new file mode 100644 index 0000000000..cdd6c4022c --- /dev/null +++ b/vendor/symfony/cache/Marshaller/MarshallerInterface.php @@ -0,0 +1,40 @@ +<?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\Marshaller; + +/** + * Serializes/unserializes PHP values. + * + * Implementations of this interface MUST deal with errors carefully. They MUST + * also deal with forward and backward compatibility at the storage format level. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +interface MarshallerInterface +{ + /** + * Serializes a list of values. + * + * When serialization fails for a specific value, no exception should be + * thrown. Instead, its key should be listed in $failed. + */ + public function marshall(array $values, ?array &$failed): array; + + /** + * Unserializes a single value and throws an exception if anything goes wrong. + * + * @return mixed + * + * @throws \Exception Whenever unserialization fails + */ + public function unmarshall(string $value); +} diff --git a/vendor/symfony/cache/ResettableInterface.php b/vendor/symfony/cache/ResettableInterface.php index 6be72861e7..7b0a853f23 100644 --- a/vendor/symfony/cache/ResettableInterface.php +++ b/vendor/symfony/cache/ResettableInterface.php @@ -11,10 +11,11 @@ namespace Symfony\Component\Cache; +use Symfony\Contracts\Service\ResetInterface; + /** * Resets a pool's local state. */ -interface ResettableInterface +interface ResettableInterface extends ResetInterface { - public function reset(); } diff --git a/vendor/symfony/cache/Simple/AbstractCache.php b/vendor/symfony/cache/Simple/AbstractCache.php index f29eb69c9b..08456f588f 100644 --- a/vendor/symfony/cache/Simple/AbstractCache.php +++ b/vendor/symfony/cache/Simple/AbstractCache.php @@ -31,13 +31,9 @@ abstract class AbstractCache implements CacheInterface, LoggerAwareInterface, Re private $defaultLifetime; - /** - * @param string $namespace - * @param int $defaultLifetime - */ - protected function __construct($namespace = '', $defaultLifetime = 0) + protected function __construct(string $namespace = '', int $defaultLifetime = 0) { - $this->defaultLifetime = max(0, (int) $defaultLifetime); + $this->defaultLifetime = max(0, $defaultLifetime); $this->namespace = '' === $namespace ? '' : CacheItem::validateKey($namespace).':'; if (null !== $this->maxIdLength && \strlen($namespace) > $this->maxIdLength - 24) { throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, \strlen($namespace), $namespace)); diff --git a/vendor/symfony/cache/Simple/ApcuCache.php b/vendor/symfony/cache/Simple/ApcuCache.php index e583b44341..0877c394bb 100644 --- a/vendor/symfony/cache/Simple/ApcuCache.php +++ b/vendor/symfony/cache/Simple/ApcuCache.php @@ -17,12 +17,7 @@ class ApcuCache extends AbstractCache { use ApcuTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $version - */ - public function __construct($namespace = '', $defaultLifetime = 0, $version = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $version = null) { $this->init($namespace, $defaultLifetime, $version); } diff --git a/vendor/symfony/cache/Simple/ArrayCache.php b/vendor/symfony/cache/Simple/ArrayCache.php index ca45c93a55..9185e5fa55 100644 --- a/vendor/symfony/cache/Simple/ArrayCache.php +++ b/vendor/symfony/cache/Simple/ArrayCache.php @@ -34,9 +34,9 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte * @param int $defaultLifetime * @param bool $storeSerialized Disabling serialization can lead to cache corruptions when storing mutable values but increases performance otherwise */ - public function __construct($defaultLifetime = 0, $storeSerialized = true) + public function __construct(int $defaultLifetime = 0, bool $storeSerialized = true) { - $this->defaultLifetime = (int) $defaultLifetime; + $this->defaultLifetime = $defaultLifetime; $this->storeSerialized = $storeSerialized; } @@ -45,9 +45,20 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte */ public function get($key, $default = null) { - foreach ($this->getMultiple(array($key), $default) as $v) { - return $v; + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } + if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > microtime(true) || !$this->delete($key))) { + $this->values[$key] = null; + + return $default; + } + if (!$this->storeSerialized) { + return $this->values[$key]; } + $value = $this->unfreeze($key, $isHit); + + return $isHit ? $value : $default; } /** @@ -61,10 +72,12 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', \is_object($keys) ? \get_class($keys) : \gettype($keys))); } foreach ($keys as $key) { - CacheItem::validateKey($key); + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } } - return $this->generateItems($keys, time(), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; }); + return $this->generateItems($keys, microtime(true), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; }); } /** @@ -87,7 +100,9 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte */ public function set($key, $value, $ttl = null) { - CacheItem::validateKey($key); + if (!\is_string($key)) { + CacheItem::validateKey($key); + } return $this->setMultiple(array($key => $value), $ttl); } @@ -103,27 +118,20 @@ class ArrayCache implements CacheInterface, LoggerAwareInterface, ResettableInte $valuesArray = array(); foreach ($values as $key => $value) { - \is_int($key) || CacheItem::validateKey($key); + if (!\is_int($key) && !(\is_string($key) && isset($this->expiries[$key]))) { + CacheItem::validateKey($key); + } $valuesArray[$key] = $value; } if (false === $ttl = $this->normalizeTtl($ttl)) { return $this->deleteMultiple(array_keys($valuesArray)); } - if ($this->storeSerialized) { - foreach ($valuesArray as $key => $value) { - try { - $valuesArray[$key] = serialize($value); - } catch (\Exception $e) { - $type = \is_object($value) ? \get_class($value) : \gettype($value); - CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); - - return false; - } - } - } - $expiry = 0 < $ttl ? time() + $ttl : PHP_INT_MAX; + $expiry = 0 < $ttl ? microtime(true) + $ttl : PHP_INT_MAX; foreach ($valuesArray as $key => $value) { + if ($this->storeSerialized && null === $value = $this->freeze($value)) { + return false; + } $this->values[$key] = $value; $this->expiries[$key] = $expiry; } diff --git a/vendor/symfony/cache/Simple/ChainCache.php b/vendor/symfony/cache/Simple/ChainCache.php index 47ac9c62c3..922d0fff31 100644 --- a/vendor/symfony/cache/Simple/ChainCache.php +++ b/vendor/symfony/cache/Simple/ChainCache.php @@ -15,6 +15,7 @@ use Psr\SimpleCache\CacheInterface; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Service\ResetInterface; /** * Chains several caches together. @@ -35,7 +36,7 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf * @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 */ - public function __construct(array $caches, $defaultLifetime = 0) + public function __construct(array $caches, int $defaultLifetime = 0) { if (!$caches) { throw new InvalidArgumentException('At least one cache must be specified.'); @@ -50,7 +51,7 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf $this->miss = new \stdClass(); $this->caches = array_values($caches); $this->cacheCount = \count($this->caches); - $this->defaultLifetime = 0 < $defaultLifetime ? (int) $defaultLifetime : null; + $this->defaultLifetime = 0 < $defaultLifetime ? $defaultLifetime : null; } /** @@ -244,7 +245,7 @@ class ChainCache implements CacheInterface, PruneableInterface, ResettableInterf public function reset() { foreach ($this->caches as $cache) { - if ($cache instanceof ResettableInterface) { + if ($cache instanceof ResetInterface) { $cache->reset(); } } diff --git a/vendor/symfony/cache/Simple/DoctrineCache.php b/vendor/symfony/cache/Simple/DoctrineCache.php index 00f0b9c6fc..0ba701d7cd 100644 --- a/vendor/symfony/cache/Simple/DoctrineCache.php +++ b/vendor/symfony/cache/Simple/DoctrineCache.php @@ -18,12 +18,7 @@ class DoctrineCache extends AbstractCache { use DoctrineTrait; - /** - * @param CacheProvider $provider - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(CacheProvider $provider, $namespace = '', $defaultLifetime = 0) + public function __construct(CacheProvider $provider, string $namespace = '', int $defaultLifetime = 0) { parent::__construct('', $defaultLifetime); $this->provider = $provider; diff --git a/vendor/symfony/cache/Simple/FilesystemCache.php b/vendor/symfony/cache/Simple/FilesystemCache.php index ccd5795342..8e04d53355 100644 --- a/vendor/symfony/cache/Simple/FilesystemCache.php +++ b/vendor/symfony/cache/Simple/FilesystemCache.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\FilesystemTrait; @@ -18,13 +20,9 @@ class FilesystemCache extends AbstractCache implements PruneableInterface { use FilesystemTrait; - /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory - */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null) { + $this->marshaller = $marshaller ?? new DefaultMarshaller(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); } diff --git a/vendor/symfony/cache/Simple/MemcachedCache.php b/vendor/symfony/cache/Simple/MemcachedCache.php index 7717740622..8e418b071e 100644 --- a/vendor/symfony/cache/Simple/MemcachedCache.php +++ b/vendor/symfony/cache/Simple/MemcachedCache.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\MemcachedTrait; class MemcachedCache extends AbstractCache @@ -19,13 +20,8 @@ class MemcachedCache extends AbstractCache protected $maxIdLength = 250; - /** - * @param \Memcached $client - * @param string $namespace - * @param int $defaultLifetime - */ - public function __construct(\Memcached $client, $namespace = '', $defaultLifetime = 0) + public function __construct(\Memcached $client, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($client, $namespace, $defaultLifetime); + $this->init($client, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Simple/PdoCache.php b/vendor/symfony/cache/Simple/PdoCache.php index 931a3b1ff7..076370c97e 100644 --- a/vendor/symfony/cache/Simple/PdoCache.php +++ b/vendor/symfony/cache/Simple/PdoCache.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\Traits\PdoTrait; @@ -25,6 +26,9 @@ class PdoCache extends AbstractCache implements PruneableInterface * a Doctrine DBAL Connection or a DSN string that will be used to * lazy-connect to the database when the cache is actually used. * + * When a Doctrine DBAL Connection is passed, the cache table is created + * automatically when possible. Otherwise, use the createTable() method. + * * List of available options: * * db_table: The name of the table [default: cache_items] * * db_id_col: The column where to store the cache id [default: item_id] @@ -35,17 +39,14 @@ class PdoCache extends AbstractCache implements PruneableInterface * * db_password: The password when lazy-connect [default: ''] * * db_connection_options: An array of driver-specific connection options [default: array()] * - * @param \PDO|Connection|string $connOrDsn A \PDO or Connection instance or DSN string or null - * @param string $namespace - * @param int $defaultLifetime - * @param array $options An associative array of options + * @param \PDO|Connection|string $connOrDsn a \PDO or Connection instance or DSN string or null * * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION * @throws InvalidArgumentException When namespace contains invalid characters */ - public function __construct($connOrDsn, $namespace = '', $defaultLifetime = 0, array $options = array()) + public function __construct($connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = array(), MarshallerInterface $marshaller = null) { - $this->init($connOrDsn, $namespace, $defaultLifetime, $options); + $this->init($connOrDsn, $namespace, $defaultLifetime, $options, $marshaller); } } diff --git a/vendor/symfony/cache/Simple/PhpArrayCache.php b/vendor/symfony/cache/Simple/PhpArrayCache.php index d7d87c019b..b913aee2b7 100644 --- a/vendor/symfony/cache/Simple/PhpArrayCache.php +++ b/vendor/symfony/cache/Simple/PhpArrayCache.php @@ -32,17 +32,14 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt * @param string $file The PHP file were values are cached * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit */ - public function __construct($file, CacheInterface $fallbackPool) + public function __construct(string $file, CacheInterface $fallbackPool) { $this->file = $file; $this->pool = $fallbackPool; - $this->zendDetectUnicode = ini_get('zend.detect_unicode'); } /** - * This adapter should only be used on PHP 7.0+ to take advantage of how PHP - * stores arrays in its latest versions. This factory method decorates the given - * fallback pool with this adapter only if the current PHP version is supported. + * This adapter takes advantage of how PHP stores arrays in its latest versions. * * @param string $file The PHP file were values are cached * @@ -50,8 +47,8 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt */ public static function create($file, CacheInterface $fallbackPool) { - // Shared memory is available in PHP 7.0+ with OPCache enabled and in HHVM - if ((\PHP_VERSION_ID >= 70000 && ini_get('opcache.enable')) || \defined('HHVM_VERSION')) { + // Shared memory is available in PHP 7.0+ with OPCache enabled + if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { return new static($file, $fallbackPool); } @@ -69,22 +66,18 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt if (null === $this->values) { $this->initialize(); } - if (!isset($this->values[$key])) { + if (!isset($this->keys[$key])) { return $this->pool->get($key, $default); } - - $value = $this->values[$key]; + $value = $this->values[$this->keys[$key]]; if ('N;' === $value) { - $value = null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + return null; + } + if ($value instanceof \Closure) { try { - $e = null; - $value = unserialize($value); - } catch (\Error $e) { - } catch (\Exception $e) { - } - if (null !== $e) { + return $value(); + } catch (\Throwable $e) { return $default; } } @@ -126,7 +119,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt $this->initialize(); } - return isset($this->values[$key]) || $this->pool->has($key); + return isset($this->keys[$key]) || $this->pool->has($key); } /** @@ -141,7 +134,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt $this->initialize(); } - return !isset($this->values[$key]) && $this->pool->delete($key); + return !isset($this->keys[$key]) && $this->pool->delete($key); } /** @@ -161,7 +154,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); } - if (isset($this->values[$key])) { + if (isset($this->keys[$key])) { $deleted = false; } else { $fallbackKeys[] = $key; @@ -190,7 +183,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt $this->initialize(); } - return !isset($this->values[$key]) && $this->pool->set($key, $value, $ttl); + return !isset($this->keys[$key]) && $this->pool->set($key, $value, $ttl); } /** @@ -210,7 +203,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt throw new InvalidArgumentException(sprintf('Cache key must be string, "%s" given.', \is_object($key) ? \get_class($key) : \gettype($key))); } - if (isset($this->values[$key])) { + if (isset($this->keys[$key])) { $saved = false; } else { $fallbackValues[$key] = $value; @@ -229,17 +222,15 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt $fallbackKeys = array(); foreach ($keys as $key) { - if (isset($this->values[$key])) { - $value = $this->values[$key]; + if (isset($this->keys[$key])) { + $value = $this->values[$this->keys[$key]]; if ('N;' === $value) { yield $key => null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + } elseif ($value instanceof \Closure) { try { - yield $key => unserialize($value); - } catch (\Error $e) { - yield $key => $default; - } catch (\Exception $e) { + yield $key => $value(); + } catch (\Throwable $e) { yield $key => $default; } } else { @@ -251,9 +242,7 @@ class PhpArrayCache implements CacheInterface, PruneableInterface, ResettableInt } if ($fallbackKeys) { - foreach ($this->pool->getMultiple($fallbackKeys, $default) as $key => $item) { - yield $key => $item; - } + yield from $this->pool->getMultiple($fallbackKeys, $default); } } } diff --git a/vendor/symfony/cache/Simple/PhpFilesCache.php b/vendor/symfony/cache/Simple/PhpFilesCache.php index 9231c8cd39..19ac8b4152 100644 --- a/vendor/symfony/cache/Simple/PhpFilesCache.php +++ b/vendor/symfony/cache/Simple/PhpFilesCache.php @@ -20,22 +20,19 @@ class PhpFilesCache extends AbstractCache implements PruneableInterface use PhpFilesTrait; /** - * @param string $namespace - * @param int $defaultLifetime - * @param string|null $directory + * @param $appendOnly Set to `true` to gain extra performance when the items stored in this pool never expire. + * Doing so is encouraged because it fits perfectly OPcache's memory model. * * @throws CacheException if OPcache is not enabled */ - public function __construct($namespace = '', $defaultLifetime = 0, $directory = null) + public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, bool $appendOnly = false) { - if (!static::isSupported()) { - throw new CacheException('OPcache is not enabled'); - } + $this->appendOnly = $appendOnly; + self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time(); parent::__construct('', $defaultLifetime); $this->init($namespace, $directory); $e = new \Exception(); $this->includeHandler = function () use ($e) { throw $e; }; - $this->zendDetectUnicode = ini_get('zend.detect_unicode'); } } diff --git a/vendor/symfony/cache/Simple/Psr6Cache.php b/vendor/symfony/cache/Simple/Psr6Cache.php index 482aa13710..853d46e26b 100644 --- a/vendor/symfony/cache/Simple/Psr6Cache.php +++ b/vendor/symfony/cache/Simple/Psr6Cache.php @@ -15,7 +15,7 @@ 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\AbstractAdapter; +use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; use Symfony\Component\Cache\PruneableInterface; @@ -30,27 +30,36 @@ class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterfa use ProxyTrait; private $createCacheItem; + private $cacheItemPrototype; public function __construct(CacheItemPoolInterface $pool) { $this->pool = $pool; - if ($pool instanceof AbstractAdapter) { - $this->createCacheItem = \Closure::bind( - function ($key, $value, $allowInt = false) { - if ($allowInt && \is_int($key)) { - $key = (string) $key; - } else { - CacheItem::validateKey($key); - } - $f = $this->createCacheItem; - - return $f($key, $value, false); - }, - $pool, - AbstractAdapter::class - ); + 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, $value, $allowInt); + }; } /** @@ -65,6 +74,10 @@ class Psr6Cache implements CacheInterface, PruneableInterface, ResettableInterfa } 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; } diff --git a/vendor/symfony/cache/Simple/RedisCache.php b/vendor/symfony/cache/Simple/RedisCache.php index e82c0627e2..df2a96e86b 100644 --- a/vendor/symfony/cache/Simple/RedisCache.php +++ b/vendor/symfony/cache/Simple/RedisCache.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Cache\Simple; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; use Symfony\Component\Cache\Traits\RedisTrait; class RedisCache extends AbstractCache @@ -22,8 +23,8 @@ class RedisCache extends AbstractCache * @param string $namespace * @param int $defaultLifetime */ - public function __construct($redisClient, $namespace = '', $defaultLifetime = 0) + public function __construct($redisClient, string $namespace = '', int $defaultLifetime = 0, MarshallerInterface $marshaller = null) { - $this->init($redisClient, $namespace, $defaultLifetime); + $this->init($redisClient, $namespace, $defaultLifetime, $marshaller); } } diff --git a/vendor/symfony/cache/Simple/TraceableCache.php b/vendor/symfony/cache/Simple/TraceableCache.php index 181934eff5..d6ed40f443 100644 --- a/vendor/symfony/cache/Simple/TraceableCache.php +++ b/vendor/symfony/cache/Simple/TraceableCache.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Cache\Simple; use Psr\SimpleCache\CacheInterface; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Service\ResetInterface; /** * An adapter that collects data about all cache calls. @@ -200,7 +201,7 @@ class TraceableCache implements CacheInterface, PruneableInterface, ResettableIn */ public function reset() { - if (!$this->pool instanceof ResettableInterface) { + if (!$this->pool instanceof ResetInterface) { return; } $event = $this->start(__FUNCTION__); diff --git a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php index d3175adc77..72d143e3c0 100644 --- a/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php +++ b/vendor/symfony/cache/Tests/Adapter/AdapterTestCase.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Cache\IntegrationTests\CachePoolTest; use Psr\Cache\CacheItemPoolInterface; +use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; abstract class AdapterTestCase extends CachePoolTest @@ -21,15 +22,67 @@ abstract class AdapterTestCase extends CachePoolTest { parent::setUp(); - if (!array_key_exists('testDeferredSaveWithoutCommit', $this->skippedTests) && \defined('HHVM_VERSION')) { - $this->skippedTests['testDeferredSaveWithoutCommit'] = 'Destructors are called late on HHVM.'; - } - if (!array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) { $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; } } + public function testGet() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(); + + $value = mt_rand(); + + $this->assertSame($value, $cache->get('foo', function (CacheItem $item) use ($value) { + $this->assertSame('foo', $item->getKey()); + + return $value; + })); + + $item = $cache->getItem('foo'); + $this->assertSame($value, $item->get()); + + $isHit = true; + $this->assertSame($value, $cache->get('foo', function (CacheItem $item) use (&$isHit) { $isHit = false; }, 0)); + $this->assertTrue($isHit); + + $this->assertNull($cache->get('foo', function (CacheItem $item) use (&$isHit, $value) { + $isHit = false; + $this->assertTrue($item->isHit()); + $this->assertSame($value, $item->get()); + }, INF)); + $this->assertFalse($isHit); + } + + public function testGetMetadata() + { + if (isset($this->skippedTests[__FUNCTION__])) { + $this->markTestSkipped($this->skippedTests[__FUNCTION__]); + } + + $cache = $this->createCachePool(0, __FUNCTION__); + + $cache->deleteItem('foo'); + $cache->get('foo', function ($item) { + $item->expiresAfter(10); + sleep(1); + + return 'bar'; + }); + + $item = $cache->getItem('foo'); + + $expected = array( + CacheItem::METADATA_EXPIRY => 9.5 + time(), + CacheItem::METADATA_CTIME => 1000, + ); + $this->assertEquals($expected, $item->getMetadata(), 'Item metadata should embed expiry and ctime.', .6); + } + public function testDefaultLifeTime() { if (isset($this->skippedTests[__FUNCTION__])) { diff --git a/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php index 2b3c6b4432..a17b42bce4 100644 --- a/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/ApcuAdapterTest.php @@ -24,10 +24,10 @@ class ApcuAdapterTest extends AdapterTestCase public function createCachePool($defaultLifetime = 0) { - if (!\function_exists('apcu_fetch') || !ini_get('apc.enabled')) { + if (!\function_exists('apcu_fetch') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN)) { $this->markTestSkipped('APCu extension is required.'); } - if ('cli' === \PHP_SAPI && !ini_get('apc.enable_cli')) { + if ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN)) { if ('testWithCliSapi' !== $this->getName()) { $this->markTestSkipped('apc.enable_cli=1 is required.'); } diff --git a/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php index 725d790150..7b65061cd1 100644 --- a/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/ArrayAdapterTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter; class ArrayAdapterTest extends AdapterTestCase { protected $skippedTests = array( + 'testGetMetadata' => 'ArrayAdapter does not keep metadata.', 'testDeferredSaveWithoutCommit' => 'Assumes a shared cache which ArrayAdapter is not.', 'testSaveWithoutExpire' => 'Assumes a shared cache which ArrayAdapter is not.', ); @@ -35,12 +36,12 @@ class ArrayAdapterTest extends AdapterTestCase // Hit $item = $cache->getItem('foo'); - $item->set('4711'); + $item->set('::4711'); $cache->save($item); $fooItem = $cache->getItem('foo'); $this->assertTrue($fooItem->isHit()); - $this->assertEquals('4711', $fooItem->get()); + $this->assertEquals('::4711', $fooItem->get()); // Miss (should be present as NULL in $values) $cache->getItem('bar'); @@ -49,7 +50,7 @@ class ArrayAdapterTest extends AdapterTestCase $this->assertCount(2, $values); $this->assertArrayHasKey('foo', $values); - $this->assertSame(serialize('4711'), $values['foo']); + $this->assertSame(serialize('::4711'), $values['foo']); $this->assertArrayHasKey('bar', $values); $this->assertNull($values['bar']); } diff --git a/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php index a47058f513..09ba6e444c 100644 --- a/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/ChainAdapterTest.php @@ -24,8 +24,12 @@ use Symfony\Component\Cache\Tests\Fixtures\ExternalAdapter; */ class ChainAdapterTest extends AdapterTestCase { - public function createCachePool($defaultLifetime = 0) + public function createCachePool($defaultLifetime = 0, $testMethod = null) { + if ('testGetMetadata' === $testMethod) { + return new ChainAdapter(array(new FilesystemAdapter('', $defaultLifetime)), $defaultLifetime); + } + return new ChainAdapter(array(new ArrayAdapter($defaultLifetime), new ExternalAdapter(), new FilesystemAdapter('', $defaultLifetime)), $defaultLifetime); } diff --git a/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php index 5e301f2509..7613afa7f9 100644 --- a/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/MaxIdLengthAdapterTest.php @@ -26,7 +26,7 @@ class MaxIdLengthAdapterTest extends TestCase $cache->expects($this->exactly(2)) ->method('doHave') ->withConsecutive( - array($this->equalTo('----------:0GTYWa9n4ed8vqNlOT2iEr:')), + array($this->equalTo('----------:nWfzGiCgLczv3SSUzXL3kg:')), array($this->equalTo('----------:---------------------------------------')) ); @@ -56,7 +56,7 @@ class MaxIdLengthAdapterTest extends TestCase $reflectionProperty->setValue($cache, true); // Versioning enabled - $this->assertEquals('--------------------------:1:------------', $reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12)))); + $this->assertEquals('--------------------------:1/------------', $reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12)))); $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12))))); $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 23))))); $this->assertLessThanOrEqual(50, \strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 40))))); diff --git a/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php index d1f8790340..85292994fe 100644 --- a/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/MemcachedAdapterTest.php @@ -137,7 +137,7 @@ class MemcachedAdapterTest extends AdapterTestCase 'localhost', 11222, ); - if (ini_get('memcached.use_sasl')) { + if (filter_var(ini_get('memcached.use_sasl'), FILTER_VALIDATE_BOOLEAN)) { yield array( 'memcached://user:password@127.0.0.1?weight=50', '127.0.0.1', @@ -154,7 +154,7 @@ class MemcachedAdapterTest extends AdapterTestCase '/var/local/run/memcached.socket', 0, ); - if (ini_get('memcached.use_sasl')) { + if (filter_var(ini_get('memcached.use_sasl'), FILTER_VALIDATE_BOOLEAN)) { yield array( 'memcached://user:password@/var/local/run/memcached.socket?weight=25', '/var/local/run/memcached.socket', @@ -192,4 +192,46 @@ class MemcachedAdapterTest extends AdapterTestCase array(\Memcached::OPT_SOCKET_RECV_SIZE => 1, \Memcached::OPT_SOCKET_SEND_SIZE => 2, \Memcached::OPT_RETRY_TIMEOUT => 8), ); } + + public function testMultiServerDsn() + { + $dsn = 'memcached:?host[localhost]&host[localhost:12345]&host[/some/memcached.sock:]=3'; + $client = MemcachedAdapter::createConnection($dsn); + + $expected = array( + 0 => array( + 'host' => 'localhost', + 'port' => 11211, + 'type' => 'TCP', + ), + 1 => array( + 'host' => 'localhost', + 'port' => 12345, + 'type' => 'TCP', + ), + 2 => array( + 'host' => '/some/memcached.sock', + 'port' => 0, + 'type' => 'SOCKET', + ), + ); + $this->assertSame($expected, $client->getServerList()); + + $dsn = 'memcached://localhost?host[foo.bar]=3'; + $client = MemcachedAdapter::createConnection($dsn); + + $expected = array( + 0 => array( + 'host' => 'localhost', + 'port' => 11211, + 'type' => 'TCP', + ), + 1 => array( + 'host' => 'foo.bar', + 'port' => 11211, + 'type' => 'TCP', + ), + ); + $this->assertSame($expected, $client->getServerList()); + } } diff --git a/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php index c271403338..f1ffcbb823 100644 --- a/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/NamespacedProxyAdapterTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\ProxyAdapter; /** @@ -19,8 +20,12 @@ use Symfony\Component\Cache\Adapter\ProxyAdapter; */ class NamespacedProxyAdapterTest extends ProxyAdapterTest { - public function createCachePool($defaultLifetime = 0) + public function createCachePool($defaultLifetime = 0, $testMethod = null) { + if ('testGetMetadata' === $testMethod) { + return new ProxyAdapter(new FilesystemAdapter(), 'foo', $defaultLifetime); + } + return new ProxyAdapter(new ArrayAdapter($defaultLifetime), 'foo', $defaultLifetime); } } diff --git a/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php index f89a27ce64..eea89b7458 100644 --- a/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/PdoDbalAdapterTest.php @@ -33,7 +33,6 @@ class PdoDbalAdapterTest extends AdapterTestCase self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache'); $pool = new PdoAdapter(DriverManager::getConnection(array('driver' => 'pdo_sqlite', 'path' => self::$dbFile))); - $pool->createTable(); } public static function tearDownAfterClass() diff --git a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php index 930594fb92..96e63e64e3 100644 --- a/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Psr\Cache\CacheItemInterface; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\NullAdapter; use Symfony\Component\Cache\Adapter\PhpArrayAdapter; @@ -21,6 +22,7 @@ use Symfony\Component\Cache\Adapter\PhpArrayAdapter; class PhpArrayAdapterTest extends AdapterTestCase { protected $skippedTests = array( + 'testGet' => 'PhpArrayAdapter is read-only.', 'testBasicUsage' => 'PhpArrayAdapter is read-only.', 'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.', 'testClear' => 'PhpArrayAdapter is read-only.', @@ -67,8 +69,12 @@ class PhpArrayAdapterTest extends AdapterTestCase } } - public function createCachePool() + public function createCachePool($defaultLifetime = 0, $testMethod = null) { + if ('testGetMetadata' === $testMethod) { + return new PhpArrayAdapter(self::$file, new FilesystemAdapter()); + } + return new PhpArrayAdapterWrapper(self::$file, new NullAdapter()); } @@ -101,16 +107,32 @@ class PhpArrayAdapterTest extends AdapterTestCase public function testStoredFile() { - $expected = array( + $data = array( 'integer' => 42, 'float' => 42.42, 'boolean' => true, 'array_simple' => array('foo', 'bar'), 'array_associative' => array('foo' => 'bar', 'foo2' => 'bar2'), ); + $expected = array( + array( + 'integer' => 0, + 'float' => 1, + 'boolean' => 2, + 'array_simple' => 3, + 'array_associative' => 4, + ), + array( + 0 => 42, + 1 => 42.42, + 2 => true, + 3 => array('foo', 'bar'), + 4 => array('foo' => 'bar', 'foo2' => 'bar2'), + ), + ); $adapter = $this->createCachePool(); - $adapter->warmUp($expected); + $adapter->warmUp($data); $values = eval(substr(file_get_contents(self::$file), 6)); @@ -120,12 +142,16 @@ class PhpArrayAdapterTest extends AdapterTestCase class PhpArrayAdapterWrapper extends PhpArrayAdapter { + protected $data = array(); + public function save(CacheItemInterface $item) { \call_user_func(\Closure::bind(function () use ($item) { - $this->values[$item->getKey()] = $item->get(); - $this->warmUp($this->values); - $this->values = eval(substr(file_get_contents($this->file), 6)); + $key = $item->getKey(); + $this->keys[$key] = $id = \count($this->values); + $this->data[$key] = $this->values[$id] = $item->get(); + $this->warmUp($this->data); + list($this->keys, $this->values) = eval(substr(file_get_contents($this->file), 6)); }, $this, PhpArrayAdapter::class)); return true; diff --git a/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php index 8e93c937f6..9fecd9724b 100644 --- a/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/PhpFilesAdapterTest.php @@ -25,10 +25,6 @@ class PhpFilesAdapterTest extends AdapterTestCase public function createCachePool() { - if (!PhpFilesAdapter::isSupported()) { - $this->markTestSkipped('OPcache extension is not enabled.'); - } - return new PhpFilesAdapter('sf-cache'); } diff --git a/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php index c005d64abf..c65515b54d 100644 --- a/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/PredisAdapterTest.php @@ -34,19 +34,13 @@ class PredisAdapterTest extends AbstractRedisAdapterTest $params = array( 'scheme' => 'tcp', - 'host' => $redisHost, - 'path' => '', - 'dbindex' => '1', + 'host' => 'localhost', 'port' => 6379, - 'class' => 'Predis\Client', - 'timeout' => 3, 'persistent' => 0, - 'persistent_id' => null, - 'read_timeout' => 0, - 'retry_interval' => 0, - 'lazy' => false, + 'timeout' => 3, + 'read_write_timeout' => 0, + 'tcp_nodelay' => true, 'database' => '1', - 'password' => null, ); $this->assertSame($params, $connection->getParameters()->toArray()); } diff --git a/vendor/symfony/cache/Tests/Adapter/PredisRedisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/PredisRedisClusterAdapterTest.php new file mode 100644 index 0000000000..9974e93635 --- /dev/null +++ b/vendor/symfony/cache/Tests/Adapter/PredisRedisClusterAdapterTest.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\RedisAdapter; + +class PredisRedisClusterAdapterTest extends AbstractRedisAdapterTest +{ + public static function setupBeforeClass() + { + if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { + self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); + } + + self::$redis = RedisAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', array('class' => \Predis\Client::class, 'redis_cluster' => true)); + } + + public static function tearDownAfterClass() + { + self::$redis = null; + } +} diff --git a/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php index ff4b9d34bc..fbbdac22a8 100644 --- a/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/ProxyAdapterTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Tests\Adapter; use Psr\Cache\CacheItemInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\ProxyAdapter; use Symfony\Component\Cache\CacheItem; @@ -27,8 +28,12 @@ class ProxyAdapterTest extends AdapterTestCase 'testPrune' => 'ProxyAdapter just proxies', ); - public function createCachePool($defaultLifetime = 0) + public function createCachePool($defaultLifetime = 0, $testMethod = null) { + if ('testGetMetadata' === $testMethod) { + return new ProxyAdapter(new FilesystemAdapter(), '', $defaultLifetime); + } + return new ProxyAdapter(new ArrayAdapter(), '', $defaultLifetime); } diff --git a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php index 28c310fb18..5208df67cb 100644 --- a/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/RedisAdapterTest.php @@ -33,6 +33,11 @@ class RedisAdapterTest extends AbstractRedisAdapterTest public function testCreateConnection() { + $redis = RedisAdapter::createConnection('redis:?host[h1]&host[h2]&host[/foo:]'); + $this->assertInstanceOf(\RedisArray::class, $redis); + $this->assertSame(array('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); diff --git a/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php index 852079c00c..344f1d0743 100644 --- a/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/RedisClusterAdapterTest.php @@ -11,6 +11,10 @@ namespace Symfony\Component\Cache\Tests\Adapter; +use Symfony\Component\Cache\Adapter\AbstractAdapter; +use Symfony\Component\Cache\Adapter\RedisAdapter; +use Symfony\Component\Cache\Traits\RedisClusterProxy; + class RedisClusterAdapterTest extends AbstractRedisAdapterTest { public static function setupBeforeClass() @@ -22,6 +26,33 @@ class RedisClusterAdapterTest extends AbstractRedisAdapterTest self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); } - self::$redis = new \RedisCluster(null, explode(' ', $hosts)); + self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', array('lazy' => true, 'redis_cluster' => true)); + } + + public function createCachePool($defaultLifetime = 0) + { + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); + $adapter = new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); + + return $adapter; + } + + /** + * @dataProvider provideFailedCreateConnection + * @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException + * @expectedExceptionMessage Redis connection failed + */ + public function testFailedCreateConnection($dsn) + { + RedisAdapter::createConnection($dsn); + } + + public function provideFailedCreateConnection() + { + return array( + array('redis://localhost:1234?redis_cluster=1'), + array('redis://foo@localhost?redis_cluster=1'), + array('redis://localhost/123?redis_cluster=1'), + ); } } diff --git a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php index 7074299e7a..ad37fbef7d 100644 --- a/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/vendor/symfony/cache/Tests/Adapter/TagAwareAdapterTest.php @@ -14,6 +14,7 @@ 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; /** * @group time-sensitive @@ -138,6 +139,9 @@ class TagAwareAdapterTest extends AdapterTestCase $this->assertFalse($pool->getItem('foo')->isHit()); } + /** + * @group legacy + */ public function testGetPreviousTags() { $pool = $this->createCachePool(); @@ -149,6 +153,17 @@ class TagAwareAdapterTest extends AdapterTestCase $this->assertSame(array('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(array('foo' => 'foo'), $i->getMetadata()[CacheItem::METADATA_TAGS]); + } + public function testPrune() { $cache = new TagAwareAdapter($this->getPruneableMock()); diff --git a/vendor/symfony/cache/Tests/CacheItemTest.php b/vendor/symfony/cache/Tests/CacheItemTest.php index 4aae16b63c..6049f3ec9b 100644 --- a/vendor/symfony/cache/Tests/CacheItemTest.php +++ b/vendor/symfony/cache/Tests/CacheItemTest.php @@ -55,12 +55,15 @@ class CacheItemTest extends TestCase public function testTag() { $item = new CacheItem(); + $r = new \ReflectionProperty($item, 'isTaggable'); + $r->setAccessible(true); + $r->setValue($item, true); $this->assertSame($item, $item->tag('foo')); $this->assertSame($item, $item->tag(array('bar', 'baz'))); \call_user_func(\Closure::bind(function () use ($item) { - $this->assertSame(array('foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'), $item->tags); + $this->assertSame(array('foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'), $item->newMetadata[CacheItem::METADATA_TAGS]); }, $this, CacheItem::class)); } @@ -72,6 +75,24 @@ class CacheItemTest extends TestCase public function testInvalidTag($tag) { $item = new CacheItem(); + $r = new \ReflectionProperty($item, 'isTaggable'); + $r->setAccessible(true); + $r->setValue($item, true); + $item->tag($tag); } + + /** + * @expectedException \Symfony\Component\Cache\Exception\LogicException + * @expectedExceptionMessage Cache item "foo" comes from a non tag-aware pool: you cannot tag it. + */ + public function testNonTaggableItem() + { + $item = new CacheItem(); + $r = new \ReflectionProperty($item, 'key'); + $r->setAccessible(true); + $r->setValue($item, 'foo'); + + $item->tag(array()); + } } diff --git a/vendor/symfony/cache/Tests/DependencyInjection/CacheCollectorPassTest.php b/vendor/symfony/cache/Tests/DependencyInjection/CacheCollectorPassTest.php new file mode 100644 index 0000000000..421f5764de --- /dev/null +++ b/vendor/symfony/cache/Tests/DependencyInjection/CacheCollectorPassTest.php @@ -0,0 +1,49 @@ +<?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\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\Adapter\TagAwareAdapter; +use Symfony\Component\Cache\Adapter\TraceableAdapter; +use Symfony\Component\Cache\Adapter\TraceableTagAwareAdapter; +use Symfony\Component\Cache\DataCollector\CacheDataCollector; +use Symfony\Component\Cache\DependencyInjection\CacheCollectorPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +class CacheCollectorPassTest extends TestCase +{ + public function testProcess() + { + $container = new ContainerBuilder(); + $container + ->register('fs', FilesystemAdapter::class) + ->addTag('cache.pool'); + $container + ->register('tagged_fs', TagAwareAdapter::class) + ->addArgument(new Reference('fs')) + ->addTag('cache.pool'); + + $collector = $container->register('data_collector.cache', CacheDataCollector::class); + (new CacheCollectorPass())->process($container); + + $this->assertEquals(array( + array('addInstance', array('fs', new Reference('fs'))), + array('addInstance', array('tagged_fs', new Reference('tagged_fs'))), + ), $collector->getMethodCalls()); + + $this->assertSame(TraceableAdapter::class, $container->findDefinition('fs')->getClass()); + $this->assertSame(TraceableTagAwareAdapter::class, $container->getDefinition('tagged_fs')->getClass()); + $this->assertFalse($collector->isPublic(), 'The "data_collector.cache" should be private after processing'); + } +} diff --git a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolClearerPassTest.php b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolClearerPassTest.php new file mode 100644 index 0000000000..6aa68c29cd --- /dev/null +++ b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolClearerPassTest.php @@ -0,0 +1,73 @@ +<?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\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\DependencyInjection\CachePoolClearerPass; +use Symfony\Component\Cache\DependencyInjection\CachePoolPass; +use Symfony\Component\DependencyInjection\Compiler\RemoveUnusedDefinitionsPass; +use Symfony\Component\DependencyInjection\Compiler\RepeatedPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer; + +class CachePoolClearerPassTest extends TestCase +{ + public function testPoolRefsAreWeak() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + + $globalClearer = new Definition(Psr6CacheClearer::class); + $container->setDefinition('cache.global_clearer', $globalClearer); + + $publicPool = new Definition(); + $publicPool->addArgument('namespace'); + $publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias')); + $container->setDefinition('public.pool', $publicPool); + + $publicPool = new Definition(); + $publicPool->addArgument('namespace'); + $publicPool->addTag('cache.pool', array('clearer' => 'clearer_alias', 'name' => 'pool2')); + $container->setDefinition('public.pool2', $publicPool); + + $privatePool = new Definition(); + $privatePool->setPublic(false); + $privatePool->addArgument('namespace'); + $privatePool->addTag('cache.pool', array('clearer' => 'clearer_alias')); + $container->setDefinition('private.pool', $privatePool); + + $clearer = new Definition(); + $container->setDefinition('clearer', $clearer); + $container->setAlias('clearer_alias', 'clearer'); + + $pass = new RemoveUnusedDefinitionsPass(); + foreach ($container->getCompiler()->getPassConfig()->getRemovingPasses() as $removingPass) { + if ($removingPass instanceof RepeatedPass) { + $pass->setRepeatedPass(new RepeatedPass(array($pass))); + break; + } + } + foreach (array(new CachePoolPass(), $pass, new CachePoolClearerPass()) as $pass) { + $pass->process($container); + } + + $expected = array(array( + 'public.pool' => new Reference('public.pool'), + 'pool2' => new Reference('public.pool2'), + )); + $this->assertEquals($expected, $clearer->getArguments()); + $this->assertEquals($expected, $globalClearer->getArguments()); + } +} diff --git a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php new file mode 100644 index 0000000000..f757e79821 --- /dev/null +++ b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPassTest.php @@ -0,0 +1,130 @@ +<?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\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\DependencyInjection\CachePoolPass; +use Symfony\Component\DependencyInjection\ChildDefinition; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Reference; + +class CachePoolPassTest extends TestCase +{ + private $cachePoolPass; + + protected function setUp() + { + $this->cachePoolPass = new CachePoolPass(); + } + + public function testNamespaceArgumentIsReplaced() + { + $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'); + $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('z3X945Jbf5', $cachePool->getArgument(0)); + } + + public function testNamespaceArgumentIsNotReplacedIfArrayAdapterIsUsed() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + + $container->register('cache.adapter.array', ArrayAdapter::class)->addArgument(0); + + $cachePool = new ChildDefinition('cache.adapter.array'); + $cachePool->addTag('cache.pool'); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertCount(0, $container->getDefinition('app.cache_pool')->getArguments()); + } + + public function testArgsAreReplaced() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('cache.prefix.seed', 'foo'); + $cachePool = new Definition(); + $cachePool->addTag('cache.pool', array( + 'provider' => 'foobar', + 'default_lifetime' => 3, + )); + $cachePool->addArgument(null); + $cachePool->addArgument(null); + $cachePool->addArgument(null); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertInstanceOf(Reference::class, $cachePool->getArgument(0)); + $this->assertSame('foobar', (string) $cachePool->getArgument(0)); + $this->assertSame('tQNhcV-8xa', $cachePool->getArgument(1)); + $this->assertSame(3, $cachePool->getArgument(2)); + } + + public function testWithNameAttribute() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('cache.prefix.seed', 'foo'); + $cachePool = new Definition(); + $cachePool->addTag('cache.pool', array( + 'name' => 'foobar', + 'provider' => 'foobar', + )); + $cachePool->addArgument(null); + $cachePool->addArgument(null); + $cachePool->addArgument(null); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + + $this->assertSame('+naTpPa4Sm', $cachePool->getArgument(1)); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid "cache.pool" tag for service "app.cache_pool": accepted attributes are + */ + public function testThrowsExceptionWhenCachePoolTagHasUnknownAttributes() + { + $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'); + $container->setDefinition('app.cache_adapter', $adapter); + $cachePool = new ChildDefinition('app.cache_adapter'); + $cachePool->addTag('cache.pool', array('foobar' => 123)); + $container->setDefinition('app.cache_pool', $cachePool); + + $this->cachePoolPass->process($container); + } +} diff --git a/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPrunerPassTest.php b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPrunerPassTest.php new file mode 100644 index 0000000000..e4de6f6807 --- /dev/null +++ b/vendor/symfony/cache/Tests/DependencyInjection/CachePoolPrunerPassTest.php @@ -0,0 +1,72 @@ +<?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\DependencyInjection; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Adapter\FilesystemAdapter; +use Symfony\Component\Cache\Adapter\PhpFilesAdapter; +use Symfony\Component\Cache\DependencyInjection\CachePoolPrunerPass; +use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +class CachePoolPrunerPassTest extends TestCase +{ + public function testCompilerPassReplacesCommandArgument() + { + $container = new ContainerBuilder(); + $container->register('console.command.cache_pool_prune')->addArgument(array()); + $container->register('pool.foo', FilesystemAdapter::class)->addTag('cache.pool'); + $container->register('pool.bar', PhpFilesAdapter::class)->addTag('cache.pool'); + + $pass = new CachePoolPrunerPass(); + $pass->process($container); + + $expected = array( + 'pool.foo' => new Reference('pool.foo'), + 'pool.bar' => new Reference('pool.bar'), + ); + $argument = $container->getDefinition('console.command.cache_pool_prune')->getArgument(0); + + $this->assertInstanceOf(IteratorArgument::class, $argument); + $this->assertEquals($expected, $argument->getValues()); + } + + public function testCompilePassIsIgnoredIfCommandDoesNotExist() + { + $container = new ContainerBuilder(); + + $definitionsBefore = \count($container->getDefinitions()); + $aliasesBefore = \count($container->getAliases()); + + $pass = new CachePoolPrunerPass(); + $pass->process($container); + + // the container is untouched (i.e. no new definitions or aliases) + $this->assertCount($definitionsBefore, $container->getDefinitions()); + $this->assertCount($aliasesBefore, $container->getAliases()); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessage Class "Symfony\Component\Cache\Tests\DependencyInjection\NotFound" used for service "pool.not-found" cannot be found. + */ + public function testCompilerPassThrowsOnInvalidDefinitionClass() + { + $container = new ContainerBuilder(); + $container->register('console.command.cache_pool_prune')->addArgument(array()); + $container->register('pool.not-found', NotFound::class)->addTag('cache.pool'); + + $pass = new CachePoolPrunerPass(); + $pass->process($container); + } +} diff --git a/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php b/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php index 7cdcafd8e5..27fb82de01 100644 --- a/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php +++ b/vendor/symfony/cache/Tests/Fixtures/ArrayCache.php @@ -21,12 +21,12 @@ class ArrayCache extends CacheProvider $expiry = $this->data[$id][1]; - return !$expiry || time() < $expiry || !$this->doDelete($id); + return !$expiry || microtime(true) < $expiry || !$this->doDelete($id); } protected function doSave($id, $data, $lifeTime = 0) { - $this->data[$id] = array($data, $lifeTime ? time() + $lifeTime : false); + $this->data[$id] = array($data, $lifeTime ? microtime(true) + $lifeTime : false); return true; } diff --git a/vendor/symfony/cache/Tests/LockRegistryTest.php b/vendor/symfony/cache/Tests/LockRegistryTest.php new file mode 100644 index 0000000000..3f7d959570 --- /dev/null +++ b/vendor/symfony/cache/Tests/LockRegistryTest.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\Cache\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\LockRegistry; + +class LockRegistryTest extends TestCase +{ + public function testFiles() + { + $lockFiles = LockRegistry::setFiles(array()); + LockRegistry::setFiles($lockFiles); + $expected = array_map('realpath', glob(__DIR__.'/../Adapter/*')); + $this->assertSame($expected, $lockFiles); + } +} diff --git a/vendor/symfony/cache/Tests/Marshaller/DefaultMarshallerTest.php b/vendor/symfony/cache/Tests/Marshaller/DefaultMarshallerTest.php new file mode 100644 index 0000000000..fc625d12fc --- /dev/null +++ b/vendor/symfony/cache/Tests/Marshaller/DefaultMarshallerTest.php @@ -0,0 +1,104 @@ +<?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\Marshaller; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; + +class DefaultMarshallerTest extends TestCase +{ + public function testSerialize() + { + $marshaller = new DefaultMarshaller(); + $values = array( + 'a' => 123, + 'b' => function () {}, + ); + + $expected = array('a' => \extension_loaded('igbinary') ? igbinary_serialize(123) : serialize(123)); + $this->assertSame($expected, $marshaller->marshall($values, $failed)); + $this->assertSame(array('b'), $failed); + } + + public function testNativeUnserialize() + { + $marshaller = new DefaultMarshaller(); + $this->assertNull($marshaller->unmarshall(serialize(null))); + $this->assertFalse($marshaller->unmarshall(serialize(false))); + $this->assertSame('', $marshaller->unmarshall(serialize(''))); + $this->assertSame(0, $marshaller->unmarshall(serialize(0))); + } + + /** + * @requires extension igbinary + */ + public function testIgbinaryUnserialize() + { + $marshaller = new DefaultMarshaller(); + $this->assertNull($marshaller->unmarshall(igbinary_serialize(null))); + $this->assertFalse($marshaller->unmarshall(igbinary_serialize(false))); + $this->assertSame('', $marshaller->unmarshall(igbinary_serialize(''))); + $this->assertSame(0, $marshaller->unmarshall(igbinary_serialize(0))); + } + + /** + * @expectedException \DomainException + * @expectedExceptionMessage Class not found: NotExistingClass + */ + public function testNativeUnserializeNotFoundClass() + { + $marshaller = new DefaultMarshaller(); + $marshaller->unmarshall('O:16:"NotExistingClass":0:{}'); + } + + /** + * @requires extension igbinary + * @expectedException \DomainException + * @expectedExceptionMessage Class not found: NotExistingClass + */ + public function testIgbinaryUnserializeNotFoundClass() + { + $marshaller = new DefaultMarshaller(); + $marshaller->unmarshall(rawurldecode('%00%00%00%02%17%10NotExistingClass%14%00')); + } + + /** + * @expectedException \DomainException + * @expectedExceptionMessage unserialize(): Error at offset 0 of 3 bytes + */ + public function testNativeUnserializeInvalid() + { + $marshaller = new DefaultMarshaller(); + set_error_handler(function () { return false; }); + try { + @$marshaller->unmarshall(':::'); + } finally { + restore_error_handler(); + } + } + + /** + * @requires extension igbinary + * @expectedException \DomainException + * @expectedExceptionMessage igbinary_unserialize_zval: unknown type '61', position 5 + */ + public function testIgbinaryUnserializeInvalid() + { + $marshaller = new DefaultMarshaller(); + set_error_handler(function () { return false; }); + try { + @$marshaller->unmarshall(rawurldecode('%00%00%00%02abc')); + } finally { + restore_error_handler(); + } + } +} diff --git a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php index 737ed4e99d..3df32c1c5e 100644 --- a/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/ApcuCacheTest.php @@ -23,7 +23,7 @@ class ApcuCacheTest extends CacheTestCase public function createSimpleCache($defaultLifetime = 0) { - if (!\function_exists('apcu_fetch') || !ini_get('apc.enabled') || ('cli' === \PHP_SAPI && !ini_get('apc.enable_cli'))) { + if (!\function_exists('apcu_fetch') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) || ('cli' === \PHP_SAPI && !filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN))) { $this->markTestSkipped('APCu extension is required.'); } if ('\\' === \DIRECTORY_SEPARATOR) { diff --git a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php index d0d8573598..5b84d8b093 100644 --- a/vendor/symfony/cache/Tests/Simple/CacheTestCase.php +++ b/vendor/symfony/cache/Tests/Simple/CacheTestCase.php @@ -28,10 +28,6 @@ abstract class CacheTestCase extends SimpleCacheTest public static function validKeys() { - if (\defined('HHVM_VERSION')) { - return parent::validKeys(); - } - return array_merge(parent::validKeys(), array(array("a\0b"))); } diff --git a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php index b46d7e443d..ee9e49d3dd 100644 --- a/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/MemcachedCacheTest.php @@ -146,7 +146,7 @@ class MemcachedCacheTest extends CacheTestCase 'localhost', 11222, ); - if (ini_get('memcached.use_sasl')) { + if (filter_var(ini_get('memcached.use_sasl'), FILTER_VALIDATE_BOOLEAN)) { yield array( 'memcached://user:password@127.0.0.1?weight=50', '127.0.0.1', @@ -163,7 +163,7 @@ class MemcachedCacheTest extends CacheTestCase '/var/local/run/memcached.socket', 0, ); - if (ini_get('memcached.use_sasl')) { + if (filter_var(ini_get('memcached.use_sasl'), FILTER_VALIDATE_BOOLEAN)) { yield array( 'memcached://user:password@/var/local/run/memcached.socket?weight=25', '/var/local/run/memcached.socket', diff --git a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php index b4862c61bd..e0c7285802 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpArrayCacheTest.php @@ -95,16 +95,32 @@ class PhpArrayCacheTest extends CacheTestCase public function testStoredFile() { - $expected = array( + $data = array( 'integer' => 42, 'float' => 42.42, 'boolean' => true, 'array_simple' => array('foo', 'bar'), 'array_associative' => array('foo' => 'bar', 'foo2' => 'bar2'), ); + $expected = array( + array( + 'integer' => 0, + 'float' => 1, + 'boolean' => 2, + 'array_simple' => 3, + 'array_associative' => 4, + ), + array( + 0 => 42, + 1 => 42.42, + 2 => true, + 3 => array('foo', 'bar'), + 4 => array('foo' => 'bar', 'foo2' => 'bar2'), + ), + ); $cache = new PhpArrayCache(self::$file, new NullCache()); - $cache->warmUp($expected); + $cache->warmUp($data); $values = eval(substr(file_get_contents(self::$file), 6)); @@ -114,12 +130,14 @@ class PhpArrayCacheTest extends CacheTestCase class PhpArrayCacheWrapper extends PhpArrayCache { + protected $data = array(); + public function set($key, $value, $ttl = null) { \call_user_func(\Closure::bind(function () use ($key, $value) { - $this->values[$key] = $value; - $this->warmUp($this->values); - $this->values = eval(substr(file_get_contents($this->file), 6)); + $this->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; @@ -132,10 +150,10 @@ class PhpArrayCacheWrapper extends PhpArrayCache } \call_user_func(\Closure::bind(function () use ($values) { foreach ($values as $key => $value) { - $this->values[$key] = $value; + $this->data[$key] = $value; } - $this->warmUp($this->values); - $this->values = eval(substr(file_get_contents($this->file), 6)); + $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 7a402682ae..38e5ee90b1 100644 --- a/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php +++ b/vendor/symfony/cache/Tests/Simple/PhpFilesCacheTest.php @@ -25,10 +25,6 @@ class PhpFilesCacheTest extends CacheTestCase public function createSimpleCache() { - if (!PhpFilesCache::isSupported()) { - $this->markTestSkipped('OPcache extension is not enabled.'); - } - return new PhpFilesCache('sf-cache'); } diff --git a/vendor/symfony/cache/Traits/AbstractTrait.php b/vendor/symfony/cache/Traits/AbstractTrait.php index 87aeba9e7b..01351f11c9 100644 --- a/vendor/symfony/cache/Traits/AbstractTrait.php +++ b/vendor/symfony/cache/Traits/AbstractTrait.php @@ -27,6 +27,7 @@ trait AbstractTrait private $namespaceVersion = ''; private $versioningIsEnabled = false; private $deferred = array(); + private $ids = array(); /** * @var int|null The maximum length to enforce for identifiers or null when no limit applies @@ -54,7 +55,7 @@ trait AbstractTrait /** * Deletes all items in the pool. * - * @param string The prefix used for all identifiers managed by this pool + * @param string $namespace The prefix used for all identifiers managed by this pool * * @return bool True if the pool was successfully cleared, false otherwise */ @@ -108,12 +109,13 @@ trait AbstractTrait if ($cleared = $this->versioningIsEnabled) { $namespaceVersion = substr_replace(base64_encode(pack('V', mt_rand())), ':', 5); try { - $cleared = $this->doSave(array('@'.$this->namespace => $namespaceVersion), 0); + $cleared = $this->doSave(array('/'.$this->namespace => $namespaceVersion), 0); } catch (\Exception $e) { $cleared = false; } if ($cleared = true === $cleared || array() === $cleared) { $this->namespaceVersion = $namespaceVersion; + $this->ids = array(); } } @@ -188,6 +190,7 @@ trait AbstractTrait $wasEnabled = $this->versioningIsEnabled; $this->versioningIsEnabled = (bool) $enable; $this->namespaceVersion = ''; + $this->ids = array(); return $wasEnabled; } @@ -201,6 +204,7 @@ trait AbstractTrait $this->commit(); } $this->namespaceVersion = ''; + $this->ids = array(); } /** @@ -211,9 +215,13 @@ trait AbstractTrait * @return mixed * * @throws \Exception + * + * @deprecated since Symfony 4.2, use DefaultMarshaller instead. */ protected static function unserialize($value) { + @trigger_error(sprintf('The "%s::unserialize()" method is deprecated since Symfony 4.2, use DefaultMarshaller instead.', __CLASS__), E_USER_DEPRECATED); + if ('b:0;' === $value) { return false; } @@ -232,12 +240,11 @@ trait AbstractTrait private function getId($key) { - CacheItem::validateKey($key); - if ($this->versioningIsEnabled && '' === $this->namespaceVersion) { - $this->namespaceVersion = '1:'; + $this->ids = array(); + $this->namespaceVersion = '1/'; try { - foreach ($this->doFetch(array('@'.$this->namespace)) as $v) { + foreach ($this->doFetch(array('/'.$this->namespace)) as $v) { $this->namespaceVersion = $v; } if ('1:' === $this->namespaceVersion) { @@ -248,11 +255,19 @@ trait AbstractTrait } } + if (\is_string($key) && isset($this->ids[$key])) { + return $this->namespace.$this->namespaceVersion.$this->ids[$key]; + } + CacheItem::validateKey($key); + $this->ids[$key] = $key; + if (null === $this->maxIdLength) { return $this->namespace.$this->namespaceVersion.$key; } if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) { - $id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -(\strlen($this->namespaceVersion) + 22)); + // Use MD5 to favor speed over security, which is not an issue here + $this->ids[$key] = $id = substr_replace(base64_encode(hash('md5', $key, true)), ':', -(\strlen($this->namespaceVersion) + 2)); + $id = $this->namespace.$this->namespaceVersion.$id; } return $id; diff --git a/vendor/symfony/cache/Traits/ApcuTrait.php b/vendor/symfony/cache/Traits/ApcuTrait.php index 65122cd8b7..a93fc812a1 100644 --- a/vendor/symfony/cache/Traits/ApcuTrait.php +++ b/vendor/symfony/cache/Traits/ApcuTrait.php @@ -23,7 +23,7 @@ trait ApcuTrait { public static function isSupported() { - return \function_exists('apcu_fetch') && ini_get('apc.enabled'); + return \function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN); } private function init($namespace, $defaultLifetime, $version) @@ -51,14 +51,20 @@ trait ApcuTrait */ protected function doFetch(array $ids) { + $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); try { + $values = array(); foreach (apcu_fetch($ids, $ok) ?: array() as $k => $v) { if (null !== $v || $ok) { - yield $k => $v; + $values[$k] = $v; } } + + return $values; } catch (\Error $e) { throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine()); + } finally { + ini_set('unserialize_callback_func', $unserializeCallbackHandler); } } @@ -75,7 +81,7 @@ trait ApcuTrait */ protected function doClear($namespace) { - return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli' !== \PHP_SAPI || ini_get('apc.enable_cli')) + return isset($namespace[0]) && class_exists('APCuIterator', false) && ('cli' !== \PHP_SAPI || filter_var(ini_get('apc.enable_cli'), FILTER_VALIDATE_BOOLEAN)) ? apcu_delete(new \APCuIterator(sprintf('/^%s/', preg_quote($namespace, '/')), APC_ITER_KEY)) : apcu_clear_cache(); } @@ -103,15 +109,13 @@ trait ApcuTrait } return array_keys($failures); - } catch (\Error $e) { - } catch (\Exception $e) { - } + } catch (\Throwable $e) { + if (1 === \count($values)) { + // Workaround https://github.com/krakjoe/apcu/issues/170 + apcu_delete(key($values)); + } - if (1 === \count($values)) { - // Workaround https://github.com/krakjoe/apcu/issues/170 - apcu_delete(key($values)); + throw $e; } - - throw $e; } } diff --git a/vendor/symfony/cache/Traits/ArrayTrait.php b/vendor/symfony/cache/Traits/ArrayTrait.php index 88385ed480..cfa73fa7b0 100644 --- a/vendor/symfony/cache/Traits/ArrayTrait.php +++ b/vendor/symfony/cache/Traits/ArrayTrait.php @@ -34,7 +34,21 @@ trait ArrayTrait */ public function getValues() { - return $this->values; + if (!$this->storeSerialized) { + return $this->values; + } + + $values = $this->values; + foreach ($values as $k => $v) { + if (null === $v || 'N;' === $v) { + continue; + } + if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) { + $values[$k] = serialize($v); + } + } + + return $values; } /** @@ -42,9 +56,12 @@ trait ArrayTrait */ public function hasItem($key) { + if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) { + return true; + } CacheItem::validateKey($key); - return isset($this->expiries[$key]) && ($this->expiries[$key] > time() || !$this->deleteItem($key)); + return isset($this->expiries[$key]) && !$this->deleteItem($key); } /** @@ -62,8 +79,9 @@ trait ArrayTrait */ public function deleteItem($key) { - CacheItem::validateKey($key); - + if (!\is_string($key) || !isset($this->expiries[$key])) { + CacheItem::validateKey($key); + } unset($this->values[$key], $this->expiries[$key]); return true; @@ -80,21 +98,10 @@ trait ArrayTrait private function generateItems(array $keys, $now, $f) { foreach ($keys as $i => $key) { - try { - if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) { - $this->values[$key] = $value = null; - } elseif (!$this->storeSerialized) { - $value = $this->values[$key]; - } elseif ('b:0;' === $value = $this->values[$key]) { - $value = false; - } elseif (false === $value = unserialize($value)) { - $this->values[$key] = $value = null; - $isHit = false; - } - } catch (\Exception $e) { - CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e)); + if (!$isHit = isset($this->expiries[$key]) && ($this->expiries[$key] > $now || !$this->deleteItem($key))) { $this->values[$key] = $value = null; - $isHit = false; + } else { + $value = $this->storeSerialized ? $this->unfreeze($key, $isHit) : $this->values[$key]; } unset($keys[$i]); @@ -105,4 +112,53 @@ trait ArrayTrait yield $key => $f($key, null, false); } } + + private function freeze($value) + { + if (null === $value) { + return 'N;'; + } + if (\is_string($value)) { + // Serialize strings if they could be confused with serialized objects or arrays + if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { + return serialize($value); + } + } elseif (!\is_scalar($value)) { + try { + $serialized = serialize($value); + } catch (\Exception $e) { + $type = \is_object($value) ? \get_class($value) : \gettype($value); + CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e)); + + return; + } + // Keep value serialized if it contains any objects or any internal references + if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) { + return $serialized; + } + } + + return $value; + } + + private function unfreeze(string $key, bool &$isHit) + { + if ('N;' === $value = $this->values[$key]) { + return null; + } + if (\is_string($value) && isset($value[2]) && ':' === $value[1]) { + try { + $value = unserialize($value); + } catch (\Exception $e) { + CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e)); + $value = false; + } + if (false === $value) { + $this->values[$key] = $value = null; + $isHit = false; + } + } + + return $value; + } } diff --git a/vendor/symfony/cache/Traits/ContractsTrait.php b/vendor/symfony/cache/Traits/ContractsTrait.php new file mode 100644 index 0000000000..f755e65fc3 --- /dev/null +++ b/vendor/symfony/cache/Traits/ContractsTrait.php @@ -0,0 +1,90 @@ +<?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 Symfony\Component\Cache\Adapter\AdapterInterface; +use Symfony\Component\Cache\CacheItem; +use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\LockRegistry; +use Symfony\Contracts\Cache\CacheInterface; +use Symfony\Contracts\Cache\CacheTrait; +use Symfony\Contracts\Cache\ItemInterface; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +trait ContractsTrait +{ + use CacheTrait { + doGet as private contractsGet; + } + + private $callbackWrapper = array(LockRegistry::class, 'compute'); + + /** + * Wraps the callback passed to ->get() in a callable. + * + * @return callable the previous callback wrapper + */ + public function setCallbackWrapper(?callable $callbackWrapper): callable + { + $previousWrapper = $this->callbackWrapper; + $this->callbackWrapper = $callbackWrapper ?? function (callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool) { + return $callback($item, $save); + }; + + return $previousWrapper; + } + + private function doGet(AdapterInterface $pool, string $key, callable $callback, ?float $beta, array &$metadata = null) + { + if (0 > $beta = $beta ?? 1.0) { + throw new InvalidArgumentException(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', \get_class($this), $beta)); + } + + static $setMetadata; + + $setMetadata = $setMetadata ?? \Closure::bind( + function (AdapterInterface $pool, ItemInterface $item, float $startTime) { + if ($item->expiry > $endTime = microtime(true)) { + $item->newMetadata[ItemInterface::METADATA_EXPIRY] = $item->expiry; + $item->newMetadata[ItemInterface::METADATA_CTIME] = 1000 * (int) ($endTime - $startTime); + } + }, + null, + CacheItem::class + ); + + return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata) { + // don't wrap nor save recursive calls + if (null === $callbackWrapper = $this->callbackWrapper) { + $value = $callback($item, $save); + $save = false; + + return $value; + } + $this->callbackWrapper = null; + $startTime = microtime(true); + + try { + $value = $callbackWrapper($callback, $item, $save, $pool); + $setMetadata($pool, $item, $startTime); + + return $value; + } finally { + $this->callbackWrapper = $callbackWrapper; + } + }, $beta, $metadata); + } +} diff --git a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php index 274eb73259..c20be5eecb 100644 --- a/vendor/symfony/cache/Traits/FilesystemCommonTrait.php +++ b/vendor/symfony/cache/Traits/FilesystemCommonTrait.php @@ -56,7 +56,7 @@ trait FilesystemCommonTrait $ok = true; foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->directory, \FilesystemIterator::SKIP_DOTS)) as $file) { - $ok = ($file->isDir() || @unlink($file) || !file_exists($file)) && $ok; + $ok = ($file->isDir() || $this->doUnlink($file) || !file_exists($file)) && $ok; } return $ok; @@ -71,12 +71,17 @@ trait FilesystemCommonTrait foreach ($ids as $id) { $file = $this->getFile($id); - $ok = (!file_exists($file) || @unlink($file) || !file_exists($file)) && $ok; + $ok = (!file_exists($file) || $this->doUnlink($file) || !file_exists($file)) && $ok; } return $ok; } + protected function doUnlink($file) + { + return @unlink($file); + } + private function write($file, $data, $expiresAt = null) { set_error_handler(__CLASS__.'::throwError'); @@ -98,7 +103,8 @@ trait FilesystemCommonTrait private function getFile($id, $mkdir = false) { - $hash = str_replace('/', '-', base64_encode(hash('sha256', static::class.$id, true))); + // 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); if ($mkdir && !file_exists($dir)) { diff --git a/vendor/symfony/cache/Traits/FilesystemTrait.php b/vendor/symfony/cache/Traits/FilesystemTrait.php index 23974b3bc5..52dcf985dd 100644 --- a/vendor/symfony/cache/Traits/FilesystemTrait.php +++ b/vendor/symfony/cache/Traits/FilesystemTrait.php @@ -23,6 +23,8 @@ trait FilesystemTrait { use FilesystemCommonTrait; + private $marshaller; + /** * @return bool */ @@ -68,7 +70,7 @@ trait FilesystemTrait $value = stream_get_contents($h); fclose($h); if ($i === $id) { - $values[$id] = parent::unserialize($value); + $values[$id] = $this->marshaller->unmarshall($value); } } } @@ -91,17 +93,19 @@ trait FilesystemTrait */ protected function doSave(array $values, $lifetime) { - $ok = true; $expiresAt = $lifetime ? (time() + $lifetime) : 0; + $values = $this->marshaller->marshall($values, $failed); foreach ($values as $id => $value) { - $ok = $this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".serialize($value), $expiresAt) && $ok; + if (!$this->write($this->getFile($id, true), $expiresAt."\n".rawurlencode($id)."\n".$value, $expiresAt)) { + $failed[] = $id; + } } - if (!$ok && !is_writable($this->directory)) { + if ($failed && !is_writable($this->directory)) { throw new CacheException(sprintf('Cache directory is not writable (%s)', $this->directory)); } - return $ok; + return $failed; } } diff --git a/vendor/symfony/cache/Traits/MemcachedTrait.php b/vendor/symfony/cache/Traits/MemcachedTrait.php index 5983d9ebd1..534de598e3 100644 --- a/vendor/symfony/cache/Traits/MemcachedTrait.php +++ b/vendor/symfony/cache/Traits/MemcachedTrait.php @@ -13,6 +13,8 @@ namespace Symfony\Component\Cache\Traits; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @author Rob Frawley 2nd <rmf@src.run> @@ -29,6 +31,7 @@ trait MemcachedTrait 'serializer' => 'php', ); + private $marshaller; private $client; private $lazyClient; @@ -37,7 +40,7 @@ trait MemcachedTrait return \extension_loaded('memcached') && version_compare(phpversion('memcached'), '2.2.0', '>='); } - private function init(\Memcached $client, $namespace, $defaultLifetime) + private function init(\Memcached $client, $namespace, $defaultLifetime, ?MarshallerInterface $marshaller) { if (!static::isSupported()) { throw new CacheException('Memcached >= 2.2.0 is required'); @@ -55,6 +58,7 @@ trait MemcachedTrait parent::__construct($namespace, $defaultLifetime); $this->enableVersioning(); + $this->marshaller = $marshaller ?? new DefaultMarshaller(); } /** @@ -66,8 +70,8 @@ trait MemcachedTrait * - 'memcached://user:pass@localhost?weight=33' * - array(array('localhost', 11211, 33)) * - * @param array[]|string|string[] An array of servers, a DSN, or an array of DSNs - * @param array An array of options + * @param array[]|string|string[] $servers An array of servers, a DSN, or an array of DSNs + * @param array $options An array of options * * @return \Memcached * @@ -95,19 +99,43 @@ trait MemcachedTrait if (\is_array($dsn)) { continue; } - if (0 !== strpos($dsn, 'memcached://')) { - throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s does not start with "memcached://"', $dsn)); + if (0 !== strpos($dsn, 'memcached:')) { + throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s does not start with "memcached:"', $dsn)); } - $params = preg_replace_callback('#^memcached://(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) { - if (!empty($m[1])) { - list($username, $password) = explode(':', $m[1], 2) + array(1 => null); + $params = preg_replace_callback('#^memcached:(//)?(?:([^@]*+)@)?#', function ($m) use (&$username, &$password) { + if (!empty($m[2])) { + list($username, $password) = explode(':', $m[2], 2) + array(1 => null); } - return 'file://'; + return 'file:'.($m[1] ?? ''); }, $dsn); if (false === $params = parse_url($params)) { throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn)); } + $query = $hosts = array(); + if (isset($params['query'])) { + parse_str($params['query'], $query); + + if (isset($query['host'])) { + if (!\is_array($hosts = $query['host'])) { + throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn)); + } + foreach ($hosts as $host => $weight) { + if (false === $port = strrpos($host, ':')) { + $hosts[$host] = array($host, 11211, (int) $weight); + } else { + $hosts[$host] = array(substr($host, 0, $port), (int) substr($host, 1 + $port), (int) $weight); + } + } + $hosts = array_values($hosts); + unset($query['host']); + } + if ($hosts && !isset($params['host']) && !isset($params['path'])) { + unset($servers[$i]); + $servers = array_merge($servers, $hosts); + continue; + } + } if (!isset($params['host']) && !isset($params['path'])) { throw new InvalidArgumentException(sprintf('Invalid Memcached DSN: %s', $dsn)); } @@ -120,13 +148,16 @@ trait MemcachedTrait 'port' => isset($params['host']) ? 11211 : null, 'weight' => 0, ); - if (isset($params['query'])) { - parse_str($params['query'], $query); + if ($query) { $params += $query; $options = $query + $options; } $servers[$i] = array($params['host'], $params['port'], $params['weight']); + + if ($hosts) { + $servers = array_merge($servers, $hosts); + } } // set client's options @@ -195,6 +226,10 @@ trait MemcachedTrait */ protected function doSave(array $values, $lifetime) { + if (!$values = $this->marshaller->marshall($values, $failed)) { + return $failed; + } + if ($lifetime && $lifetime > 30 * 86400) { $lifetime += time(); } @@ -204,7 +239,7 @@ trait MemcachedTrait $encodedValues[rawurlencode($key)] = $value; } - return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)); + return $this->checkResultCode($this->getClient()->setMulti($encodedValues, $lifetime)) ? $failed : false; } /** @@ -212,7 +247,6 @@ trait MemcachedTrait */ protected function doFetch(array $ids) { - $unserializeCallbackHandler = ini_set('unserialize_callback_func', __CLASS__.'::handleUnserializeCallback'); try { $encodedIds = array_map('rawurlencode', $ids); @@ -220,14 +254,12 @@ trait MemcachedTrait $result = array(); foreach ($encodedResult as $key => $value) { - $result[rawurldecode($key)] = $value; + $result[rawurldecode($key)] = $this->marshaller->unmarshall($value); } return $result; } catch (\Error $e) { throw new \ErrorException($e->getMessage(), $e->getCode(), E_ERROR, $e->getFile(), $e->getLine()); - } finally { - ini_set('unserialize_callback_func', $unserializeCallbackHandler); } } diff --git a/vendor/symfony/cache/Traits/PdoTrait.php b/vendor/symfony/cache/Traits/PdoTrait.php index a22714c80f..ea4feee4ac 100644 --- a/vendor/symfony/cache/Traits/PdoTrait.php +++ b/vendor/symfony/cache/Traits/PdoTrait.php @@ -14,14 +14,18 @@ namespace Symfony\Component\Cache\Traits; use Doctrine\DBAL\Connection; use Doctrine\DBAL\DBALException; use Doctrine\DBAL\Driver\ServerInfoAwareConnection; +use Doctrine\DBAL\Exception\TableNotFoundException; use Doctrine\DBAL\Schema\Schema; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @internal */ trait PdoTrait { + private $marshaller; private $conn; private $dsn; private $driver; @@ -36,7 +40,7 @@ trait PdoTrait private $connectionOptions = array(); private $namespace; - private function init($connOrDsn, $namespace, $defaultLifetime, array $options) + private function init($connOrDsn, $namespace, $defaultLifetime, array $options, ?MarshallerInterface $marshaller) { if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); @@ -65,6 +69,7 @@ trait PdoTrait $this->password = isset($options['db_password']) ? $options['db_password'] : $this->password; $this->connectionOptions = isset($options['db_connection_options']) ? $options['db_connection_options'] : $this->connectionOptions; $this->namespace = $namespace; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); parent::__construct($namespace, $defaultLifetime); } @@ -150,7 +155,11 @@ trait PdoTrait $deleteSql .= " AND $this->idCol LIKE :namespace"; } - $delete = $this->getConnection()->prepare($deleteSql); + try { + $delete = $this->getConnection()->prepare($deleteSql); + } catch (TableNotFoundException $e) { + return true; + } $delete->bindValue(':time', time(), \PDO::PARAM_INT); if ('' !== $this->namespace) { @@ -181,7 +190,7 @@ trait PdoTrait if (null === $row[1]) { $expired[] = $row[0]; } else { - yield $row[0] => parent::unserialize(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); + yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); } } @@ -229,7 +238,10 @@ trait PdoTrait $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'"; } - $conn->exec($sql); + try { + $conn->exec($sql); + } catch (TableNotFoundException $e) { + } return true; } @@ -241,8 +253,11 @@ trait PdoTrait { $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); $sql = "DELETE FROM $this->table WHERE $this->idCol IN ($sql)"; - $stmt = $this->getConnection()->prepare($sql); - $stmt->execute(array_values($ids)); + try { + $stmt = $this->getConnection()->prepare($sql); + $stmt->execute(array_values($ids)); + } catch (TableNotFoundException $e) { + } return true; } @@ -252,18 +267,7 @@ trait PdoTrait */ protected function doSave(array $values, $lifetime) { - $serialized = array(); - $failed = array(); - - foreach ($values as $id => $value) { - try { - $serialized[$id] = serialize($value); - } catch (\Exception $e) { - $failed[] = $id; - } - } - - if (!$serialized) { + if (!$values = $this->marshaller->marshall($values, $failed)) { return $failed; } @@ -302,7 +306,14 @@ trait PdoTrait $now = time(); $lifetime = $lifetime ?: null; - $stmt = $conn->prepare($sql); + try { + $stmt = $conn->prepare($sql); + } catch (TableNotFoundException $e) { + if (!$conn->isTransactionActive() || \in_array($this->driver, array('pgsql', 'sqlite', 'sqlsrv'), true)) { + $this->createTable(); + } + $stmt = $conn->prepare($sql); + } if ('sqlsrv' === $driver || 'oci' === $driver) { $stmt->bindParam(1, $id); @@ -328,7 +339,7 @@ trait PdoTrait $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT); } - foreach ($serialized as $id => $data) { + foreach ($values as $id => $data) { $stmt->execute(); if (null === $driver && !$stmt->rowCount()) { diff --git a/vendor/symfony/cache/Traits/PhpArrayTrait.php b/vendor/symfony/cache/Traits/PhpArrayTrait.php index 65dded87c2..587da5a498 100644 --- a/vendor/symfony/cache/Traits/PhpArrayTrait.php +++ b/vendor/symfony/cache/Traits/PhpArrayTrait.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Traits; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\VarExporter\VarExporter; /** * @author Titouan Galopin <galopintitouan@gmail.com> @@ -25,8 +26,8 @@ trait PhpArrayTrait use ProxyTrait; private $file; + private $keys; private $values; - private $zendDetectUnicode; /** * Store an array of cached values. @@ -55,56 +56,63 @@ trait PhpArrayTrait } } + $dumpedValues = ''; + $dumpedMap = array(); $dump = <<<'EOF' <?php // This file has been auto-generated by the Symfony Cache Component. -return array( +return array(array( EOF; foreach ($values as $key => $value) { CacheItem::validateKey(\is_int($key) ? (string) $key : $key); + $isStaticValue = true; - if (null === $value || \is_object($value)) { + if (null === $value) { + $value = "'N;'"; + } elseif (\is_object($value) || \is_array($value)) { try { - $value = serialize($value); + $value = VarExporter::export($value, $isStaticValue); } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \get_class($value)), 0, $e); - } - } elseif (\is_array($value)) { - try { - $serialized = serialize($value); - $unserialized = unserialize($serialized); - } catch (\Exception $e) { - throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable array value.', $key), 0, $e); - } - // Store arrays serialized if they contain any objects or references - if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) { - $value = $serialized; + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e); } } elseif (\is_string($value)) { - // Serialize strings if they could be confused with serialized objects or arrays - if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { - $value = serialize($value); + // Wrap "N;" in a closure to not confuse it with an encoded `null` + if ('N;' === $value) { + $isStaticValue = false; } + $value = var_export($value, true); } elseif (!\is_scalar($value)) { throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value))); + } else { + $value = var_export($value, true); + } + + if (!$isStaticValue) { + $value = str_replace("\n", "\n ", $value); + $value = "static function () {\n return {$value};\n}"; } + $hash = hash('md5', $value); - $dump .= var_export($key, true).' => '.var_export($value, true).",\n"; + if (null === $id = $dumpedMap[$hash] ?? null) { + $id = $dumpedMap[$hash] = \count($dumpedMap); + $dumpedValues .= "{$id} => {$value},\n"; + } + + $dump .= var_export($key, true)." => {$id},\n"; } - $dump .= "\n);\n"; - $dump = str_replace("' . \"\\0\" . '", "\0", $dump); + $dump .= "\n), array(\n\n{$dumpedValues}\n));\n"; $tmpFile = uniqid($this->file, true); file_put_contents($tmpFile, $dump); @chmod($tmpFile, 0666 & ~umask()); - unset($serialized, $unserialized, $value, $dump); + unset($serialized, $value, $dump); @rename($tmpFile, $this->file); @@ -116,7 +124,7 @@ EOF; */ public function clear() { - $this->values = array(); + $this->keys = $this->values = array(); $cleared = @unlink($this->file) || !file_exists($this->file); @@ -128,15 +136,17 @@ EOF; */ private function initialize() { - if ($this->zendDetectUnicode) { - $zmb = ini_set('zend.detect_unicode', 0); + if (!file_exists($this->file)) { + $this->keys = $this->values = array(); + + return; } - try { - $this->values = file_exists($this->file) ? (include $this->file ?: array()) : array(); - } finally { - if ($this->zendDetectUnicode) { - ini_set('zend.detect_unicode', $zmb); - } + $values = (include $this->file) ?: array(array(), array()); + + if (2 !== \count($values) || !isset($values[0], $values[1])) { + $this->keys = $this->values = array(); + } else { + list($this->keys, $this->values) = $values; } } } diff --git a/vendor/symfony/cache/Traits/PhpFilesTrait.php b/vendor/symfony/cache/Traits/PhpFilesTrait.php index 7728d17c53..4dacec8cfc 100644 --- a/vendor/symfony/cache/Traits/PhpFilesTrait.php +++ b/vendor/symfony/cache/Traits/PhpFilesTrait.php @@ -13,6 +13,7 @@ namespace Symfony\Component\Cache\Traits; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\VarExporter\VarExporter; /** * @author Piotr Stankowski <git@trakos.pl> @@ -23,14 +24,23 @@ use Symfony\Component\Cache\Exception\InvalidArgumentException; */ trait PhpFilesTrait { - use FilesystemCommonTrait; + use FilesystemCommonTrait { + doClear as private doCommonClear; + doDelete as private doCommonDelete; + } private $includeHandler; - private $zendDetectUnicode; + private $appendOnly; + private $values = array(); + private $files = array(); + + private static $startTime; public static function isSupported() { - return \function_exists('opcache_invalidate') && ini_get('opcache.enable'); + self::$startTime = self::$startTime ?? $_SERVER['REQUEST_TIME'] ?? time(); + + return \function_exists('opcache_invalidate') && ('cli' !== \PHP_SAPI || filter_var(ini_get('opcache.enable_cli'), FILTER_VALIDATE_BOOLEAN)) && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN); } /** @@ -40,7 +50,6 @@ trait PhpFilesTrait { $time = time(); $pruned = true; - $allowCompile = 'cli' !== \PHP_SAPI || ini_get('opcache.enable_cli'); set_error_handler($this->includeHandler); try { @@ -48,11 +57,7 @@ trait PhpFilesTrait list($expiresAt) = include $file; if ($time >= $expiresAt) { - $pruned = @unlink($file) && !file_exists($file) && $pruned; - - if ($allowCompile) { - @opcache_invalidate($file, true); - } + $pruned = $this->doUnlink($file) && !file_exists($file) && $pruned; } } } finally { @@ -67,41 +72,56 @@ trait PhpFilesTrait */ protected function doFetch(array $ids) { + if ($this->appendOnly) { + $now = 0; + $missingIds = array(); + } else { + $now = time(); + $missingIds = $ids; + $ids = array(); + } $values = array(); - $now = time(); - if ($this->zendDetectUnicode) { - $zmb = ini_set('zend.detect_unicode', 0); + begin: + foreach ($ids as $id) { + if (null === $value = $this->values[$id] ?? null) { + $missingIds[] = $id; + } elseif ('N;' === $value) { + $values[$id] = null; + } elseif ($value instanceof \Closure) { + $values[$id] = $value(); + } else { + $values[$id] = $value; + } + if (!$this->appendOnly) { + unset($this->values[$id]); + } + } + + if (!$missingIds) { + return $values; } + set_error_handler($this->includeHandler); try { - foreach ($ids as $id) { + foreach ($missingIds as $k => $id) { try { - $file = $this->getFile($id); - list($expiresAt, $values[$id]) = include $file; + $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id); + list($expiresAt, $this->values[$id]) = include $file; if ($now >= $expiresAt) { - unset($values[$id]); + unset($this->values[$id], $missingIds[$k]); } } catch (\Exception $e) { - continue; + unset($missingIds[$k]); } } } finally { restore_error_handler(); - if ($this->zendDetectUnicode) { - ini_set('zend.detect_unicode', $zmb); - } } - foreach ($values as $id => $value) { - if ('N;' === $value) { - $values[$id] = null; - } elseif (\is_string($value) && isset($value[2]) && ':' === $value[1]) { - $values[$id] = parent::unserialize($value); - } - } - - return $values; + $ids = $missingIds; + $missingIds = array(); + goto begin; } /** @@ -109,7 +129,25 @@ trait PhpFilesTrait */ protected function doHave($id) { - return (bool) $this->doFetch(array($id)); + if ($this->appendOnly && $this->values[$id]) { + return true; + } + + set_error_handler($this->includeHandler); + try { + $file = $this->files[$id] ?? $this->files[$id] = $this->getFile($id); + list($expiresAt, $value) = include $file; + } finally { + restore_error_handler(); + } + if ($this->appendOnly) { + $now = 0; + $this->values[$id] = $value; + } else { + $now = time(); + } + + return $now < $expiresAt; } /** @@ -118,34 +156,44 @@ trait PhpFilesTrait protected function doSave(array $values, $lifetime) { $ok = true; - $data = array($lifetime ? time() + $lifetime : PHP_INT_MAX, ''); - $allowCompile = 'cli' !== \PHP_SAPI || ini_get('opcache.enable_cli'); + $expiry = $lifetime ? time() + $lifetime : 'PHP_INT_MAX'; + $allowCompile = self::isSupported(); foreach ($values as $key => $value) { - if (null === $value || \is_object($value)) { - $value = serialize($value); - } elseif (\is_array($value)) { - $serialized = serialize($value); - $unserialized = parent::unserialize($serialized); - // Store arrays serialized if they contain any objects or references - if ($unserialized !== $value || (false !== strpos($serialized, ';R:') && preg_match('/;R:[1-9]/', $serialized))) { - $value = $serialized; + unset($this->values[$key]); + $isStaticValue = true; + if (null === $value) { + $value = "'N;'"; + } elseif (\is_object($value) || \is_array($value)) { + try { + $value = VarExporter::export($value, $isStaticValue); + } catch (\Exception $e) { + throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \is_object($value) ? \get_class($value) : 'array'), 0, $e); } } elseif (\is_string($value)) { - // Serialize strings if they could be confused with serialized objects or arrays - if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) { - $value = serialize($value); + // Wrap "N;" in a closure to not confuse it with an encoded `null` + if ('N;' === $value) { + $isStaticValue = false; } + $value = var_export($value, true); } elseif (!\is_scalar($value)) { throw new InvalidArgumentException(sprintf('Cache key "%s" has non-serializable %s value.', $key, \gettype($value))); + } else { + $value = var_export($value, true); } - $data[1] = $value; - $file = $this->getFile($key, true); - $ok = $this->write($file, '<?php return '.var_export($data, true).';') && $ok; + if (!$isStaticValue) { + $value = str_replace("\n", "\n ", $value); + $value = "static function () {\n\n return {$value};\n\n}"; + } + + $file = $this->files[$key] = $this->getFile($key, true); + // Since OPcache only compiles files older than the script execution start, set the file's mtime in the past + $ok = $this->write($file, "<?php return array({$expiry}, {$value});\n", self::$startTime - 10) && $ok; if ($allowCompile) { @opcache_invalidate($file, true); + @opcache_compile_file($file); } } @@ -155,4 +203,35 @@ trait PhpFilesTrait return $ok; } + + /** + * {@inheritdoc} + */ + protected function doClear($namespace) + { + $this->values = array(); + + return $this->doCommonClear($namespace); + } + + /** + * {@inheritdoc} + */ + protected function doDelete(array $ids) + { + foreach ($ids as $id) { + unset($this->values[$id]); + } + + return $this->doCommonDelete($ids); + } + + protected function doUnlink($file) + { + if (self::isSupported()) { + @opcache_invalidate($file, true); + } + + return @unlink($file); + } } diff --git a/vendor/symfony/cache/Traits/ProxyTrait.php b/vendor/symfony/cache/Traits/ProxyTrait.php index d9e085b9ea..c86f360ab7 100644 --- a/vendor/symfony/cache/Traits/ProxyTrait.php +++ b/vendor/symfony/cache/Traits/ProxyTrait.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Cache\Traits; use Symfony\Component\Cache\PruneableInterface; -use Symfony\Component\Cache\ResettableInterface; +use Symfony\Contracts\Service\ResetInterface; /** * @author Nicolas Grekas <p@tchwork.com> @@ -36,7 +36,7 @@ trait ProxyTrait */ public function reset() { - if ($this->pool instanceof ResettableInterface) { + if ($this->pool instanceof ResetInterface) { $this->pool->reset(); } } diff --git a/vendor/symfony/cache/Traits/RedisClusterProxy.php b/vendor/symfony/cache/Traits/RedisClusterProxy.php new file mode 100644 index 0000000000..b4cef59a3e --- /dev/null +++ b/vendor/symfony/cache/Traits/RedisClusterProxy.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\Cache\Traits; + +/** + * @author Alessandro Chitolina <alekitto@gmail.com> + * + * @internal + */ +class RedisClusterProxy +{ + private $redis; + private $initializer; + + public function __construct(\Closure $initializer) + { + $this->initializer = $initializer; + } + + public function __call($method, array $args) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->{$method}(...$args); + } + + public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->hscan($strKey, $iIterator, $strPattern, $iCount); + } + + public function scan(&$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->scan($iIterator, $strPattern, $iCount); + } + + public function sscan($strKey, &$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->sscan($strKey, $iIterator, $strPattern, $iCount); + } + + public function zscan($strKey, &$iIterator, $strPattern = null, $iCount = null) + { + $this->redis ?: $this->redis = $this->initializer->__invoke(); + + return $this->redis->zscan($strKey, $iIterator, $strPattern, $iCount); + } +} diff --git a/vendor/symfony/cache/Traits/RedisProxy.php b/vendor/symfony/cache/Traits/RedisProxy.php index b328f94cd8..2b0b857367 100644 --- a/vendor/symfony/cache/Traits/RedisProxy.php +++ b/vendor/symfony/cache/Traits/RedisProxy.php @@ -32,7 +32,7 @@ class RedisProxy { $this->ready ?: $this->ready = $this->initializer->__invoke($this->redis); - return \call_user_func_array(array($this->redis, $method), $args); + return $this->redis->{$method}(...$args); } public function hscan($strKey, &$iIterator, $strPattern = null, $iCount = null) diff --git a/vendor/symfony/cache/Traits/RedisTrait.php b/vendor/symfony/cache/Traits/RedisTrait.php index 77e3decf50..dc9d9590be 100644 --- a/vendor/symfony/cache/Traits/RedisTrait.php +++ b/vendor/symfony/cache/Traits/RedisTrait.php @@ -12,12 +12,12 @@ namespace Symfony\Component\Cache\Traits; use Predis\Connection\Aggregate\ClusterInterface; -use Predis\Connection\Aggregate\PredisCluster; use Predis\Connection\Aggregate\RedisCluster; -use Predis\Connection\Factory; use Predis\Response\Status; use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; +use Symfony\Component\Cache\Marshaller\DefaultMarshaller; +use Symfony\Component\Cache\Marshaller\MarshallerInterface; /** * @author Aurimas Niekis <aurimas@niekis.lt> @@ -34,26 +34,31 @@ trait RedisTrait 'timeout' => 30, 'read_timeout' => 0, 'retry_interval' => 0, - 'lazy' => false, + 'compression' => true, + 'tcp_keepalive' => 0, + 'lazy' => null, + 'redis_cluster' => false, + 'dbindex' => 0, + 'failover' => 'none', ); private $redis; + private $marshaller; /** * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client $redisClient */ - private function init($redisClient, $namespace = '', $defaultLifetime = 0) + private function init($redisClient, $namespace, $defaultLifetime, ?MarshallerInterface $marshaller) { parent::__construct($namespace, $defaultLifetime); if (preg_match('#[^-+_.A-Za-z0-9]#', $namespace, $match)) { throw new InvalidArgumentException(sprintf('RedisAdapter namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } - if ($redisClient instanceof \RedisCluster) { - $this->enableVersioning(); - } elseif (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy) { - throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient))); + if (!$redisClient instanceof \Redis && !$redisClient instanceof \RedisArray && !$redisClient instanceof \RedisCluster && !$redisClient instanceof \Predis\Client && !$redisClient instanceof RedisProxy && !$redisClient instanceof RedisClusterProxy) { + throw new InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given.', __METHOD__, \is_object($redisClient) ? \get_class($redisClient) : \gettype($redisClient))); } $this->redis = $redisClient; + $this->marshaller = $marshaller ?? new DefaultMarshaller(); } /** @@ -71,57 +76,87 @@ trait RedisTrait * * @throws InvalidArgumentException when the DSN is invalid * - * @return \Redis|\Predis\Client According to the "class" option + * @return \Redis|\RedisCluster|\Predis\Client According to the "class" option */ public static function createConnection($dsn, array $options = array()) { - if (0 !== strpos($dsn, 'redis://')) { - throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis://"', $dsn)); + if (0 !== strpos($dsn, 'redis:')) { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s does not start with "redis:".', $dsn)); } - $params = preg_replace_callback('#^redis://(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { - if (isset($m[1])) { - $auth = $m[1]; + + if (!\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { + throw new CacheException(sprintf('Cannot find the "redis" extension nor the "predis/predis" package: %s', $dsn)); + } + + $params = preg_replace_callback('#^redis:(//)?(?:(?:[^:@]*+:)?([^@]*+)@)?#', function ($m) use (&$auth) { + if (isset($m[2])) { + $auth = $m[2]; } - return 'file://'; + return 'file:'.($m[1] ?? ''); }, $dsn); - if (false === $params = parse_url($params)) { - throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn)); - } - if (!isset($params['host']) && !isset($params['path'])) { + + if (false === $params = parse_url($dsn)) { throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn)); } - if (isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) { - $params['dbindex'] = $m[1]; - $params['path'] = substr($params['path'], 0, -\strlen($m[0])); - } - if (isset($params['host'])) { - $scheme = 'tcp'; - } else { - $scheme = 'unix'; - } - $params += array( - 'host' => isset($params['host']) ? $params['host'] : $params['path'], - 'port' => isset($params['host']) ? 6379 : null, - 'dbindex' => 0, - ); + + $query = $hosts = array(); + if (isset($params['query'])) { parse_str($params['query'], $query); - $params += $query; + + if (isset($query['host'])) { + if (!\is_array($hosts = $query['host'])) { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn)); + } + foreach ($hosts as $host => $parameters) { + if (\is_string($parameters)) { + parse_str($parameters, $parameters); + } + if (false === $i = strrpos($host, ':')) { + $hosts[$host] = array('scheme' => 'tcp', 'host' => $host, 'port' => 6379) + $parameters; + } elseif ($port = (int) substr($host, 1 + $i)) { + $hosts[$host] = array('scheme' => 'tcp', 'host' => substr($host, 0, $i), 'port' => $port) + $parameters; + } else { + $hosts[$host] = array('scheme' => 'unix', 'path' => substr($host, 0, $i)) + $parameters; + } + } + $hosts = array_values($hosts); + } + } + + if (isset($params['host']) || isset($params['path'])) { + if (!isset($params['dbindex']) && isset($params['path']) && preg_match('#/(\d+)$#', $params['path'], $m)) { + $params['dbindex'] = $m[1]; + $params['path'] = substr($params['path'], 0, -\strlen($m[0])); + } + + if (isset($params['host'])) { + array_unshift($hosts, array('scheme' => 'tcp', 'host' => $params['host'], 'port' => $params['port'] ?? 6379)); + } else { + array_unshift($hosts, array('scheme' => 'unix', 'path' => $params['path'])); + } } - $params += $options + self::$defaultConnectionOptions; - if (null === $params['class'] && !\extension_loaded('redis') && !class_exists(\Predis\Client::class)) { - throw new CacheException(sprintf('Cannot find the "redis" extension, and "predis/predis" is not installed: %s', $dsn)); + + if (!$hosts) { + throw new InvalidArgumentException(sprintf('Invalid Redis DSN: %s', $dsn)); + } + + $params += $query + $options + self::$defaultConnectionOptions; + + if (null === $params['class'] && \extension_loaded('redis')) { + $class = $params['redis_cluster'] ? \RedisCluster::class : (1 < \count($hosts) ? \RedisArray::class : \Redis::class); + } else { + $class = null === $params['class'] ? \Predis\Client::class : $params['class']; } - $class = null === $params['class'] ? (\extension_loaded('redis') ? \Redis::class : \Predis\Client::class) : $params['class']; if (is_a($class, \Redis::class, true)) { $connect = $params['persistent'] || $params['persistent_id'] ? 'pconnect' : 'connect'; $redis = new $class(); - $initializer = function ($redis) use ($connect, $params, $dsn, $auth) { + $initializer = function ($redis) use ($connect, $params, $dsn, $auth, $hosts) { try { - @$redis->{$connect}($params['host'], $params['port'], $params['timeout'], $params['persistent_id'], $params['retry_interval']); + @$redis->{$connect}($hosts[0]['host'], $hosts[0]['port'], $params['timeout'], (string) $params['persistent_id'], $params['retry_interval']); } catch (\RedisException $e) { throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e->getMessage(), $dsn)); } @@ -142,6 +177,13 @@ trait RedisTrait throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e, $dsn)); } + if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) { + $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + if ($params['compression'] && \defined('Redis::COMPRESSION_LZF')) { + $redis->setOption(\Redis::OPT_COMPRESSION, \Redis::COMPRESSION_LZF); + } + return true; }; @@ -150,15 +192,82 @@ trait RedisTrait } else { $initializer($redis); } + } elseif (is_a($class, \RedisArray::class, true)) { + foreach ($hosts as $i => $host) { + $hosts[$i] = 'tcp' === $host['scheme'] ? $host['host'].':'.$host['port'] : $host['path']; + } + $params['lazy_connect'] = $params['lazy'] ?? true; + $params['connect_timeout'] = $params['timeout']; + + try { + $redis = new $class($hosts, $params); + } catch (\RedisClusterException $e) { + throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e->getMessage(), $dsn)); + } + + if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) { + $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + if ($params['compression'] && \defined('Redis::COMPRESSION_LZF')) { + $redis->setOption(\Redis::OPT_COMPRESSION, \Redis::COMPRESSION_LZF); + } + } elseif (is_a($class, \RedisCluster::class, true)) { + $initializer = function () use ($class, $params, $dsn, $hosts) { + foreach ($hosts as $i => $host) { + $hosts[$i] = 'tcp' === $host['scheme'] ? $host['host'].':'.$host['port'] : $host['path']; + } + + try { + $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent']); + } catch (\RedisClusterException $e) { + throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e->getMessage(), $dsn)); + } + + if (0 < $params['tcp_keepalive'] && \defined('Redis::OPT_TCP_KEEPALIVE')) { + $redis->setOption(\Redis::OPT_TCP_KEEPALIVE, $params['tcp_keepalive']); + } + if ($params['compression'] && \defined('Redis::COMPRESSION_LZF')) { + $redis->setOption(\Redis::OPT_COMPRESSION, \Redis::COMPRESSION_LZF); + } + switch ($params['failover']) { + case 'error': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_ERROR); break; + case 'distribute': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE); break; + case 'slaves': $redis->setOption(\RedisCluster::OPT_SLAVE_FAILOVER, \RedisCluster::FAILOVER_DISTRIBUTE_SLAVES); break; + } + + return $redis; + }; + + $redis = $params['lazy'] ? new RedisClusterProxy($initializer) : $initializer(); } elseif (is_a($class, \Predis\Client::class, true)) { - $params['scheme'] = $scheme; - $params['database'] = $params['dbindex'] ?: null; - $params['password'] = $auth; - $redis = new $class((new Factory())->create($params)); + if ($params['redis_cluster']) { + $params['cluster'] = 'redis'; + } + $params += array('parameters' => array()); + $params['parameters'] += array( + 'persistent' => $params['persistent'], + 'timeout' => $params['timeout'], + 'read_write_timeout' => $params['read_timeout'], + 'tcp_nodelay' => true, + ); + if ($params['dbindex']) { + $params['parameters']['database'] = $params['dbindex']; + } + if (null !== $auth) { + $params['parameters']['password'] = $auth; + } + if (1 === \count($hosts) && !$params['redis_cluster']) { + $hosts = $hosts[0]; + } elseif (\in_array($params['failover'], array('slaves', 'distribute'), true) && !isset($params['replication'])) { + $params['replication'] = true; + $hosts[0] += array('alias' => 'master'); + } + + $redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions)); } elseif (class_exists($class, false)) { - throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis" or "Predis\Client"', $class)); + throw new InvalidArgumentException(sprintf('"%s" is not a subclass of "Redis", "RedisArray", "RedisCluster" nor "Predis\Client".', $class)); } else { - throw new InvalidArgumentException(sprintf('Class "%s" does not exist', $class)); + throw new InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); } return $redis; @@ -169,18 +278,29 @@ trait RedisTrait */ protected function doFetch(array $ids) { - if ($ids) { + if (!$ids) { + return array(); + } + + $result = array(); + + if ($this->redis instanceof \Predis\Client) { $values = $this->pipeline(function () use ($ids) { foreach ($ids as $id) { yield 'get' => array($id); } }); - foreach ($values as $id => $v) { - if ($v) { - yield $id => parent::unserialize($v); - } + } else { + $values = array_combine($ids, $this->redis->mget($ids)); + } + + foreach ($values as $id => $v) { + if ($v) { + $result[$id] = $this->marshaller->unmarshall($v); } } + + return $result; } /** @@ -196,9 +316,6 @@ trait RedisTrait */ protected function doClear($namespace) { - // When using a native Redis cluster, clearing the cache is done by versioning in AbstractTrait::clear(). - // This means old keys are not really removed until they expire and may need garbage collection. - $cleared = true; $hosts = array($this->redis); $evalArgs = array(array($namespace), 0); @@ -207,22 +324,25 @@ trait RedisTrait $evalArgs = array(0, $namespace); $connection = $this->redis->getConnection(); - if ($connection instanceof PredisCluster) { + if ($connection instanceof ClusterInterface && $connection instanceof \Traversable) { $hosts = array(); foreach ($connection as $c) { $hosts[] = new \Predis\Client($c); } - } elseif ($connection instanceof RedisCluster) { - return false; } } elseif ($this->redis instanceof \RedisArray) { $hosts = array(); foreach ($this->redis->_hosts() as $host) { $hosts[] = $this->redis->_instance($host); } - } elseif ($this->redis instanceof \RedisCluster) { - return false; + } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { + $hosts = array(); + foreach ($this->redis->_masters() as $host) { + $hosts[] = $h = new \Redis(); + $h->connect($host[0], $host[1]); + } } + foreach ($hosts as $host) { if (!isset($namespace[0])) { $cleared = $host->flushDb() && $cleared; @@ -248,7 +368,7 @@ trait RedisTrait $keys = $keys[1]; } if ($keys) { - $host->del($keys); + $this->doDelete($keys); } } while ($cursor = (int) $cursor); } @@ -261,7 +381,17 @@ trait RedisTrait */ protected function doDelete(array $ids) { - if ($ids) { + if (!$ids) { + return true; + } + + if ($this->redis instanceof \Predis\Client) { + $this->pipeline(function () use ($ids) { + foreach ($ids as $id) { + yield 'del' => array($id); + } + })->rewind(); + } else { $this->redis->del($ids); } @@ -273,23 +403,12 @@ trait RedisTrait */ protected function doSave(array $values, $lifetime) { - $serialized = array(); - $failed = array(); - - foreach ($values as $id => $value) { - try { - $serialized[$id] = serialize($value); - } catch (\Exception $e) { - $failed[] = $id; - } - } - - if (!$serialized) { + if (!$values = $this->marshaller->marshall($values, $failed)) { return $failed; } - $results = $this->pipeline(function () use ($serialized, $lifetime) { - foreach ($serialized as $id => $value) { + $results = $this->pipeline(function () use ($values, $lifetime) { + foreach ($values as $id => $value) { if (0 >= $lifetime) { yield 'set' => array($id, $value); } else { @@ -310,10 +429,19 @@ trait RedisTrait { $ids = array(); - if ($this->redis instanceof \Predis\Client && !$this->redis->getConnection() instanceof ClusterInterface) { + if ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof RedisCluster)) { + // phpredis & predis don't support pipelining with RedisCluster + // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining + // see https://github.com/nrk/predis/issues/267#issuecomment-123781423 + $results = array(); + foreach ($generator() as $command => $args) { + $results[] = $this->redis->{$command}(...$args); + $ids[] = $args[0]; + } + } elseif ($this->redis instanceof \Predis\Client) { $results = $this->redis->pipeline(function ($redis) use ($generator, &$ids) { foreach ($generator() as $command => $args) { - \call_user_func_array(array($redis, $command), $args); + $redis->{$command}(...$args); $ids[] = $args[0]; } }); @@ -324,7 +452,7 @@ trait RedisTrait $connections[$h] = array($this->redis->_instance($h), -1); $connections[$h][0]->multi(\Redis::PIPELINE); } - \call_user_func_array(array($connections[$h][0], $command), $args); + $connections[$h][0]->{$command}(...$args); $results[] = array($h, ++$connections[$h][1]); $ids[] = $args[0]; } @@ -334,19 +462,10 @@ trait RedisTrait foreach ($results as $k => list($h, $c)) { $results[$k] = $connections[$h][$c]; } - } elseif ($this->redis instanceof \RedisCluster || ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface)) { - // phpredis & predis don't support pipelining with RedisCluster - // see https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#pipelining - // see https://github.com/nrk/predis/issues/267#issuecomment-123781423 - $results = array(); - foreach ($generator() as $command => $args) { - $results[] = \call_user_func_array(array($this->redis, $command), $args); - $ids[] = $args[0]; - } } else { $this->redis->multi(\Redis::PIPELINE); foreach ($generator() as $command => $args) { - \call_user_func_array(array($this->redis, $command), $args); + $this->redis->{$command}(...$args); $ids[] = $args[0]; } $results = $this->redis->exec(); diff --git a/vendor/symfony/cache/composer.json b/vendor/symfony/cache/composer.json index e13cd96751..8f9e669a33 100644 --- a/vendor/symfony/cache/composer.json +++ b/vendor/symfony/cache/composer.json @@ -17,23 +17,30 @@ ], "provide": { "psr/cache-implementation": "1.0", - "psr/simple-cache-implementation": "1.0" + "psr/simple-cache-implementation": "1.0", + "symfony/cache-contracts-implementation": "1.0" }, "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/cache": "~1.0", "psr/log": "~1.0", "psr/simple-cache": "^1.0", - "symfony/polyfill-apcu": "~1.1" + "symfony/contracts": "^1.0", + "symfony/var-exporter": "^4.2" }, "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "~1.6", - "doctrine/dbal": "~2.4", - "predis/predis": "~1.0" + "doctrine/dbal": "~2.5", + "predis/predis": "~1.1", + "symfony/config": "~4.2", + "symfony/dependency-injection": "~3.4|~4.1", + "symfony/var-dumper": "^4.1.1" }, "conflict": { - "symfony/var-dumper": "<3.3" + "doctrine/dbal": "<2.5", + "symfony/dependency-injection": "<3.4", + "symfony/var-dumper": "<3.4" }, "autoload": { "psr-4": { "Symfony\\Component\\Cache\\": "" }, @@ -44,7 +51,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } } } diff --git a/vendor/symfony/cache/phpunit.xml.dist b/vendor/symfony/cache/phpunit.xml.dist index 9b3c30d76f..c35458ca44 100644 --- a/vendor/symfony/cache/phpunit.xml.dist +++ b/vendor/symfony/cache/phpunit.xml.dist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" @@ -36,11 +36,11 @@ <array> <element key="time-sensitive"> <array> - <element><string>Cache\IntegrationTests</string></element> - <element><string>Doctrine\Common\Cache</string></element> - <element><string>Symfony\Component\Cache</string></element> - <element><string>Symfony\Component\Cache\Tests\Fixtures</string></element> - <element><string>Symfony\Component\Cache\Traits</string></element> + <element key="0"><string>Cache\IntegrationTests</string></element> + <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> </array> </element> </array> diff --git a/vendor/symfony/contracts/.gitignore b/vendor/symfony/contracts/.gitignore new file mode 100644 index 0000000000..5414c2c655 --- /dev/null +++ b/vendor/symfony/contracts/.gitignore @@ -0,0 +1,3 @@ +composer.lock +phpunit.xml +vendor/ diff --git a/vendor/symfony/contracts/CHANGELOG.md b/vendor/symfony/contracts/CHANGELOG.md new file mode 100644 index 0000000000..fba42d5954 --- /dev/null +++ b/vendor/symfony/contracts/CHANGELOG.md @@ -0,0 +1,12 @@ +CHANGELOG +========= + +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/Cache/CacheInterface.php b/vendor/symfony/contracts/Cache/CacheInterface.php new file mode 100644 index 0000000000..0e2aec324a --- /dev/null +++ b/vendor/symfony/contracts/Cache/CacheInterface.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\Contracts\Cache; + +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * Covers most simple to advanced caching needs. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +interface CacheInterface +{ + /** + * Fetches a value from the pool or computes it if not found. + * + * On cache misses, a callback is called that should return the missing value. + * This callback is given a PSR-6 CacheItemInterface instance corresponding to the + * requested key, that could be used e.g. for expiration control. It could also + * be an ItemInterface instance when its additional features are needed. + * + * @param string $key The key of the item to retrieve from the cache + * @param callable|CallbackInterface $callback Should return the computed value for the given key/item + * @param float|null $beta A float that, as it grows, controls the likeliness of triggering + * early expiration. 0 disables it, INF forces immediate expiration. + * The default (or providing null) is implementation dependent but should + * typically be 1.0, which should provide optimal stampede protection. + * See https://en.wikipedia.org/wiki/Cache_stampede#Probabilistic_early_expiration + * + * @return mixed The value corresponding to the provided key + * + * @throws InvalidArgumentException When $key is not valid or when $beta is negative + */ + public function get(string $key, callable $callback, float $beta = null); + + /** + * Removes an item from the pool. + * + * @param string $key The key to delete + * + * @throws InvalidArgumentException When $key is not valid + * + * @return bool True if the item was successfully removed, false if there was any error + */ + public function delete(string $key): bool; +} diff --git a/vendor/symfony/contracts/Cache/CacheTrait.php b/vendor/symfony/contracts/Cache/CacheTrait.php new file mode 100644 index 0000000000..d3ff783a9c --- /dev/null +++ b/vendor/symfony/contracts/Cache/CacheTrait.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\Contracts\Cache; + +use Psr\Cache\CacheItemPoolInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * An implementation of CacheInterface for PSR-6 CacheItemPoolInterface classes. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +trait CacheTrait +{ + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null) + { + return $this->doGet($this, $key, $callback, $beta); + } + + /** + * {@inheritdoc} + */ + public function delete(string $key): bool + { + return $this->deleteItem($key); + } + + private function doGet(CacheItemPoolInterface $pool, string $key, callable $callback, ?float $beta) + { + if (0 > $beta = $beta ?? 1.0) { + throw new class(sprintf('Argument "$beta" provided to "%s::get()" must be a positive number, %f given.', \get_class($this), $beta)) extends \InvalidArgumentException implements InvalidArgumentException { + }; + } + + $item = $pool->getItem($key); + $recompute = !$item->isHit() || INF === $beta; + + if (!$recompute && $item instanceof ItemInterface) { + $metadata = $item->getMetadata(); + $expiry = $metadata[ItemInterface::METADATA_EXPIRY] ?? false; + $ctime = $metadata[ItemInterface::METADATA_CTIME] ?? false; + + if ($recompute = $ctime && $expiry && $expiry <= microtime(true) - $ctime / 1000 * $beta * log(random_int(1, PHP_INT_MAX) / PHP_INT_MAX)) { + // force applying defaultLifetime to expiry + $item->expiresAt(null); + } + } + + if ($recompute) { + $save = true; + $item->set($callback($item, $save)); + if ($save) { + $pool->save($item); + } + } + + return $item->get(); + } +} diff --git a/vendor/symfony/contracts/Cache/CallbackInterface.php b/vendor/symfony/contracts/Cache/CallbackInterface.php new file mode 100644 index 0000000000..7dae2aac37 --- /dev/null +++ b/vendor/symfony/contracts/Cache/CallbackInterface.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\Contracts\Cache; + +use Psr\Cache\CacheItemInterface; + +/** + * Computes and returns the cached value of an item. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +interface CallbackInterface +{ + /** + * @param CacheItemInterface|ItemInterface $item The item to compute the value for + * @param bool &$save Should be set to false when the value should not be saved in the pool + * + * @return mixed The computed value for the passed item + */ + public function __invoke(CacheItemInterface $item, bool &$save); +} diff --git a/vendor/symfony/contracts/Cache/ItemInterface.php b/vendor/symfony/contracts/Cache/ItemInterface.php new file mode 100644 index 0000000000..4884a2fffe --- /dev/null +++ b/vendor/symfony/contracts/Cache/ItemInterface.php @@ -0,0 +1,60 @@ +<?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\Cache; + +use Psr\Cache\CacheException; +use Psr\Cache\CacheItemInterface; +use Psr\Cache\InvalidArgumentException; + +/** + * Augments PSR-6's CacheItemInterface with support for tags and metadata. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +interface ItemInterface extends CacheItemInterface +{ + /** + * References the Unix timestamp stating when the item will expire. + */ + const METADATA_EXPIRY = 'expiry'; + + /** + * References the time the item took to be created, in milliseconds. + */ + const METADATA_CTIME = 'ctime'; + + /** + * References the list of tags that were assigned to the item, as string[]. + */ + const METADATA_TAGS = 'tags'; + + /** + * Adds a tag to a cache item. + * + * Tags are strings that follow the same validation rules as keys. + * + * @param string|string[] $tags A tag or array of tags + * + * @return $this + * + * @throws InvalidArgumentException When $tag is not valid + * @throws CacheException When the item comes from a pool that is not tag-aware + */ + public function tag($tags): self; + + /** + * Returns a list of metadata info that were saved alongside with the cached value. + * + * See ItemInterface::METADATA_* consts for keys potentially found in the returned array. + */ + public function getMetadata(): array; +} diff --git a/vendor/symfony/contracts/Cache/TagAwareCacheInterface.php b/vendor/symfony/contracts/Cache/TagAwareCacheInterface.php new file mode 100644 index 0000000000..86b867df9c --- /dev/null +++ b/vendor/symfony/contracts/Cache/TagAwareCacheInterface.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\Contracts\Cache; + +use Psr\Cache\InvalidArgumentException; + +/** + * Allows invalidating cached items using tags. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +interface TagAwareCacheInterface extends CacheInterface +{ + /** + * {@inheritdoc} + */ + public function get(string $key, callable $callback, float $beta = null); + + /** + * Invalidates cached items using tags. + * + * When implemented on a PSR-6 pool, invalidation should not apply + * to deferred items. Instead, they should be committed as usual. + * This allows replacing old tagged values by new ones without + * race conditions. + * + * @param string[] $tags An array of tags to invalidate + * + * @return bool True on success + * + * @throws InvalidArgumentException When $tags is not valid + */ + public function invalidateTags(array $tags); +} diff --git a/vendor/symfony/polyfill-apcu/LICENSE b/vendor/symfony/contracts/LICENSE index 24fa32c2e9..ad399a798d 100644 --- a/vendor/symfony/polyfill-apcu/LICENSE +++ b/vendor/symfony/contracts/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2018 Fabien Potencier +Copyright (c) 2018 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/contracts/README.md b/vendor/symfony/contracts/README.md new file mode 100644 index 0000000000..819288532c --- /dev/null +++ b/vendor/symfony/contracts/README.md @@ -0,0 +1,72 @@ +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, etc.; + * 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 implementation that matches 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. We +encourage relying on them and won't duplicate the effort. Still, the FIG has +different goals and different processes. Here, we don't need to seek universal +standards. Instead, we're providing abstractions that are compatible with the +implementations provided by Symfony. This should actually also contribute +positively to the PHP-FIG (of which Symfony is a member), by hinting the group +at some abstractions the PHP world might like to take inspiration from. + +### 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/Service/ResetInterface.php b/vendor/symfony/contracts/Service/ResetInterface.php new file mode 100644 index 0000000000..1af1075eee --- /dev/null +++ b/vendor/symfony/contracts/Service/ResetInterface.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\Contracts\Service; + +/** + * Provides a way to reset an object to its initial state. + * + * When calling the "reset()" method on an object, it should be put back to its + * initial state. This usually means clearing any internal buffers and forwarding + * the call to internal dependencies. All properties of the object should be put + * back to the same state it had when it was first ready to use. + * + * This method could be called, for example, to recycle objects that are used as + * services, so that they can be used to handle several requests in the same + * process loop (note that we advise making your services stateless instead of + * implementing this interface when possible.) + */ +interface ResetInterface +{ + public function reset(); +} diff --git a/vendor/symfony/contracts/Service/ServiceLocatorTrait.php b/vendor/symfony/contracts/Service/ServiceLocatorTrait.php new file mode 100644 index 0000000000..8ffa2b4f10 --- /dev/null +++ b/vendor/symfony/contracts/Service/ServiceLocatorTrait.php @@ -0,0 +1,97 @@ +<?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\Service; + +use Psr\Container\ContainerExceptionInterface; +use Psr\Container\NotFoundExceptionInterface; + +/** + * A trait to help implement PSR-11 service locators. + * + * @author Robin Chalas <robin.chalas@gmail.com> + * @author Nicolas Grekas <p@tchwork.com> + */ +trait ServiceLocatorTrait +{ + private $factories; + private $loading = array(); + + /** + * @param callable[] $factories + */ + public function __construct(array $factories) + { + $this->factories = $factories; + } + + /** + * {@inheritdoc} + */ + public function has($id) + { + return isset($this->factories[$id]); + } + + /** + * {@inheritdoc} + */ + public function get($id) + { + if (!isset($this->factories[$id])) { + throw $this->createNotFoundException($id); + } + + if (isset($this->loading[$id])) { + $ids = array_values($this->loading); + $ids = \array_slice($this->loading, array_search($id, $ids)); + $ids[] = $id; + + throw $this->createCircularReferenceException($id, $ids); + } + + $this->loading[$id] = $id; + try { + return $this->factories[$id]($this); + } finally { + unset($this->loading[$id]); + } + } + + private function createNotFoundException(string $id): NotFoundExceptionInterface + { + if (!$alternatives = array_keys($this->factories)) { + $message = 'is empty...'; + } else { + $last = array_pop($alternatives); + if ($alternatives) { + $message = sprintf('only knows about the "%s" and "%s" services.', implode('", "', $alternatives), $last); + } else { + $message = sprintf('only knows about the "%s" service.', $last); + } + } + + if ($this->loading) { + $message = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $message); + } else { + $message = sprintf('Service "%s" not found: the current service locator %s', $id, $message); + } + + return new class($message) extends \InvalidArgumentException implements NotFoundExceptionInterface { + }; + } + + private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface + { + return new class(sprintf('Circular reference detected for service "%s", path: "%s".', $id, implode(' -> ', $path))) extends \RuntimeException implements ContainerExceptionInterface { + }; + } +} diff --git a/vendor/symfony/contracts/Service/ServiceSubscriberInterface.php b/vendor/symfony/contracts/Service/ServiceSubscriberInterface.php new file mode 100644 index 0000000000..cffccadb54 --- /dev/null +++ b/vendor/symfony/contracts/Service/ServiceSubscriberInterface.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\Contracts\Service; + +/** + * A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method. + * + * The getSubscribedServices method returns an array of service types required by such instances, + * optionally keyed by the service names used internally. Service types that start with an interrogation + * mark "?" are optional, while the other ones are mandatory service dependencies. + * + * The injected service locators SHOULD NOT allow access to any other services not specified by the method. + * + * It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally. + * This interface does not dictate any injection method for these service locators, although constructor + * injection is recommended. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +interface ServiceSubscriberInterface +{ + /** + * Returns an array of service types required by such instances, optionally keyed by the service names used internally. + * + * For mandatory dependencies: + * + * * array('logger' => 'Psr\Log\LoggerInterface') means the objects use the "logger" name + * internally to fetch a service which must implement Psr\Log\LoggerInterface. + * * array('loggers' => 'Psr\Log\LoggerInterface[]') means the objects use the "loggers" name + * internally to fetch an iterable of Psr\Log\LoggerInterface instances. + * * array('Psr\Log\LoggerInterface') is a shortcut for + * * array('Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface') + * + * otherwise: + * + * * array('logger' => '?Psr\Log\LoggerInterface') denotes an optional dependency + * * array('loggers' => '?Psr\Log\LoggerInterface[]') denotes an optional iterable dependency + * * array('?Psr\Log\LoggerInterface') is a shortcut for + * * array('Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface') + * + * @return array The required service types, optionally keyed by service names + */ + public static function getSubscribedServices(); +} diff --git a/vendor/symfony/contracts/Service/ServiceSubscriberTrait.php b/vendor/symfony/contracts/Service/ServiceSubscriberTrait.php new file mode 100644 index 0000000000..457ffb26b7 --- /dev/null +++ b/vendor/symfony/contracts/Service/ServiceSubscriberTrait.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\Contracts\Service; + +use Psr\Container\ContainerInterface; + +/** + * Implementation of ServiceSubscriberInterface that determines subscribed services from + * private method return types. Service ids are available as "ClassName::methodName". + * + * @author Kevin Bond <kevinbond@gmail.com> + */ +trait ServiceSubscriberTrait +{ + /** @var ContainerInterface */ + private $container; + + public static function getSubscribedServices(): array + { + static $services; + + if (null !== $services) { + return $services; + } + + $services = \is_callable(array('parent', __FUNCTION__)) ? parent::getSubscribedServices() : array(); + + foreach ((new \ReflectionClass(self::class))->getMethods() as $method) { + if ($method->isStatic() || $method->isAbstract() || $method->isGenerator() || $method->isInternal() || $method->getNumberOfRequiredParameters()) { + continue; + } + + if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { + $services[self::class.'::'.$method->name] = '?'.$returnType->getName(); + } + } + + return $services; + } + + /** + * @required + */ + public function setContainer(ContainerInterface $container) + { + $this->container = $container; + + if (\is_callable(array('parent', __FUNCTION__))) { + return parent::setContainer($container); + } + } +} diff --git a/vendor/symfony/contracts/Tests/Cache/CacheTraitTest.php b/vendor/symfony/contracts/Tests/Cache/CacheTraitTest.php new file mode 100644 index 0000000000..5134a9339f --- /dev/null +++ b/vendor/symfony/contracts/Tests/Cache/CacheTraitTest.php @@ -0,0 +1,165 @@ +<?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(array('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(array('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(array('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(array('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 = array()) + { + } + + public function getItem($key) + { + } + + public function getItems(array $key = array()) + { + } + + public function saveDeferred(CacheItemInterface $item) + { + } + + public function save(CacheItemInterface $item) + { + } + + public function commit() + { + } + + public function clear() + { + } +} diff --git a/vendor/symfony/contracts/Tests/Service/ServiceLocatorTest.php b/vendor/symfony/contracts/Tests/Service/ServiceLocatorTest.php new file mode 100644 index 0000000000..265af909df --- /dev/null +++ b/vendor/symfony/contracts/Tests/Service/ServiceLocatorTest.php @@ -0,0 +1,94 @@ +<?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; + +class ServiceLocatorTest extends TestCase +{ + public function getServiceLocator(array $factories) + { + return new class($factories) implements ContainerInterface { + use ServiceLocatorTrait; + }; + } + + public function testHas() + { + $locator = $this->getServiceLocator(array( + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + function () { return 'dummy'; }, + )); + + $this->assertTrue($locator->has('foo')); + $this->assertTrue($locator->has('bar')); + $this->assertFalse($locator->has('dummy')); + } + + public function testGet() + { + $locator = $this->getServiceLocator(array( + 'foo' => function () { return 'bar'; }, + 'bar' => function () { return 'baz'; }, + )); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('baz', $locator->get('bar')); + } + + public function testGetDoesNotMemoize() + { + $i = 0; + $locator = $this->getServiceLocator(array( + 'foo' => function () use (&$i) { + ++$i; + + return 'bar'; + }, + )); + + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame('bar', $locator->get('foo')); + $this->assertSame(2, $i); + } + + /** + * @expectedException \Psr\Container\NotFoundExceptionInterface + * @expectedExceptionMessage The service "foo" has a dependency on a non-existent service "bar". This locator only knows about the "foo" service. + */ + public function testThrowsOnUndefinedInternalService() + { + $locator = $this->getServiceLocator(array( + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + )); + + $locator->get('foo'); + } + + /** + * @expectedException \Psr\Container\ContainerExceptionInterface + * @expectedExceptionMessage Circular reference detected for service "bar", path: "bar -> baz -> bar". + */ + public function testThrowsOnCircularReference() + { + $locator = $this->getServiceLocator(array( + 'foo' => function () use (&$locator) { return $locator->get('bar'); }, + 'bar' => function () use (&$locator) { return $locator->get('baz'); }, + 'baz' => function () use (&$locator) { return $locator->get('bar'); }, + )); + + $locator->get('foo'); + } +} diff --git a/vendor/symfony/contracts/Tests/Service/ServiceSubscriberTraitTest.php b/vendor/symfony/contracts/Tests/Service/ServiceSubscriberTraitTest.php new file mode 100644 index 0000000000..c7742c65d4 --- /dev/null +++ b/vendor/symfony/contracts/Tests/Service/ServiceSubscriberTraitTest.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\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 = array(TestService::class.'::aService' => '?Symfony\Contracts\Tests\Service\Service2'); + + $this->assertEquals($expected, ChildTestService::getSubscribedServices()); + } + + public function testSetContainerIsCalledOnParent() + { + $container = new class(array()) 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/Tests/Translation/TranslatorTest.php b/vendor/symfony/contracts/Tests/Translation/TranslatorTest.php new file mode 100644 index 0000000000..a3b67dfe5e --- /dev/null +++ b/vendor/symfony/contracts/Tests/Translation/TranslatorTest.php @@ -0,0 +1,353 @@ +<?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\Translation; + +use PHPUnit\Framework\TestCase; +use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Contracts\Translation\TranslatorTrait; + +/** + * Test should cover all languages mentioned on http://translate.sourceforge.net/wiki/l10n/pluralforms + * and Plural forms mentioned on http://www.gnu.org/software/gettext/manual/gettext.html#Plural-forms. + * + * See also https://developer.mozilla.org/en/Localization_and_Plurals which mentions 15 rules having a maximum of 6 forms. + * The mozilla code is also interesting to check for. + * + * As mentioned by chx http://drupal.org/node/1273968 we can cover all by testing number from 0 to 199 + * + * The goal to cover all languages is to far fetched so this test case is smaller. + * + * @author Clemens Tolboom clemens@build2be.nl + */ +class TranslatorTest extends TestCase +{ + public function getTranslator() + { + return new class() implements TranslatorInterface { + use TranslatorTrait; + }; + } + + /** + * @dataProvider getTransTests + */ + public function testTrans($expected, $id, $parameters) + { + $translator = $this->getTranslator(); + + $this->assertEquals($expected, $translator->trans($id, $parameters)); + } + + /** + * @dataProvider getTransChoiceTests + */ + public function testTransChoiceWithExplicitLocale($expected, $id, $number) + { + $translator = $this->getTranslator(); + $translator->setLocale('en'); + + $this->assertEquals($expected, $translator->trans($id, array('%count%' => $number))); + } + + /** + * @dataProvider getTransChoiceTests + */ + public function testTransChoiceWithDefaultLocale($expected, $id, $number) + { + \Locale::setDefault('en'); + + $translator = $this->getTranslator(); + + $this->assertEquals($expected, $translator->trans($id, array('%count%' => $number))); + } + + public function testGetSetLocale() + { + $translator = $this->getTranslator(); + $translator->setLocale('en'); + + $this->assertEquals('en', $translator->getLocale()); + } + + /** + * @requires extension intl + */ + public function testGetLocaleReturnsDefaultLocaleIfNotSet() + { + $translator = $this->getTranslator(); + + \Locale::setDefault('pt_BR'); + $this->assertEquals('pt_BR', $translator->getLocale()); + + \Locale::setDefault('en'); + $this->assertEquals('en', $translator->getLocale()); + } + + public function getTransTests() + { + return array( + array('Symfony is great!', 'Symfony is great!', array()), + array('Symfony is awesome!', 'Symfony is %what%!', array('%what%' => 'awesome')), + ); + } + + public function getTransChoiceTests() + { + return array( + array('There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0), + array('There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1), + array('There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10), + array('There are 0 apples', 'There is 1 apple|There are %count% apples', 0), + array('There is 1 apple', 'There is 1 apple|There are %count% apples', 1), + array('There are 10 apples', 'There is 1 apple|There are %count% apples', 10), + // custom validation messages may be coded with a fixed value + array('There are 2 apples', 'There are 2 apples', 2), + ); + } + + /** + * @dataProvider getInternal + */ + public function testInterval($expected, $number, $interval) + { + $translator = $this->getTranslator(); + + $this->assertEquals($expected, $translator->trans($interval.' foo|[1,Inf[ bar', array('%count%' => $number))); + } + + public function getInternal() + { + return array( + array('foo', 3, '{1,2, 3 ,4}'), + array('bar', 10, '{1,2, 3 ,4}'), + array('bar', 3, '[1,2]'), + array('foo', 1, '[1,2]'), + array('foo', 2, '[1,2]'), + array('bar', 1, ']1,2['), + array('bar', 2, ']1,2['), + array('foo', log(0), '[-Inf,2['), + array('foo', -log(0), '[-2,+Inf]'), + ); + } + + /** + * @dataProvider getChooseTests + */ + public function testChoose($expected, $id, $number) + { + $translator = $this->getTranslator(); + + $this->assertEquals($expected, $translator->trans($id, array('%count%' => $number))); + } + + public function testReturnMessageIfExactlyOneStandardRuleIsGiven() + { + $translator = $this->getTranslator(); + + $this->assertEquals('There are two apples', $translator->trans('There are two apples', array('%count%' => 2))); + } + + /** + * @dataProvider getNonMatchingMessages + * @expectedException \InvalidArgumentException + */ + public function testThrowExceptionIfMatchingMessageCannotBeFound($id, $number) + { + $translator = $this->getTranslator(); + + $translator->trans($id, array('%count%' => $number)); + } + + public function getNonMatchingMessages() + { + return array( + array('{0} There are no apples|{1} There is one apple', 2), + array('{1} There is one apple|]1,Inf] There are %count% apples', 0), + array('{1} There is one apple|]2,Inf] There are %count% apples', 2), + array('{0} There are no apples|There is one apple', 2), + ); + } + + public function getChooseTests() + { + return array( + array('There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0), + array('There are no apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0), + array('There are no apples', '{0}There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 0), + + array('There is one apple', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 1), + + array('There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10), + array('There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf]There are %count% apples', 10), + array('There are 10 apples', '{0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples', 10), + + array('There are 0 apples', 'There is one apple|There are %count% apples', 0), + array('There is one apple', 'There is one apple|There are %count% apples', 1), + array('There are 10 apples', 'There is one apple|There are %count% apples', 10), + + array('There are 0 apples', 'one: There is one apple|more: There are %count% apples', 0), + array('There is one apple', 'one: There is one apple|more: There are %count% apples', 1), + array('There are 10 apples', 'one: There is one apple|more: There are %count% apples', 10), + + array('There are no apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 0), + array('There is one apple', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 1), + array('There are 10 apples', '{0} There are no apples|one: There is one apple|more: There are %count% apples', 10), + + array('', '{0}|{1} There is one apple|]1,Inf] There are %count% apples', 0), + array('', '{0} There are no apples|{1}|]1,Inf] There are %count% apples', 1), + + // Indexed only tests which are Gettext PoFile* compatible strings. + array('There are 0 apples', 'There is one apple|There are %count% apples', 0), + array('There is one apple', 'There is one apple|There are %count% apples', 1), + array('There are 2 apples', 'There is one apple|There are %count% apples', 2), + + // Tests for float numbers + array('There is almost one apple', '{0} There are no apples|]0,1[ There is almost one apple|{1} There is one apple|[1,Inf] There is more than one apple', 0.7), + array('There is one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1), + array('There is more than one apple', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 1.7), + array('There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0), + array('There are no apples', '{0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0.0), + array('There are no apples', '{0.0} There are no apples|]0,1[There are %count% apples|{1} There is one apple|[1,Inf] There is more than one apple', 0), + + // Test texts with new-lines + // with double-quotes and \n in id & double-quotes and actual newlines in text + array("This is a text with a\n new-line in it. Selector = 0.", '{0}This is a text with a + new-line in it. Selector = 0.|{1}This is a text with a + new-line in it. Selector = 1.|[1,Inf]This is a text with a + new-line in it. Selector > 1.', 0), + // with double-quotes and \n in id and single-quotes and actual newlines in text + array("This is a text with a\n new-line in it. Selector = 1.", '{0}This is a text with a + new-line in it. Selector = 0.|{1}This is a text with a + new-line in it. Selector = 1.|[1,Inf]This is a text with a + new-line in it. Selector > 1.', 1), + array("This is a text with a\n new-line in it. Selector > 1.", '{0}This is a text with a + new-line in it. Selector = 0.|{1}This is a text with a + new-line in it. Selector = 1.|[1,Inf]This is a text with a + new-line in it. Selector > 1.', 5), + // with double-quotes and id split accros lines + array('This is a text with a + new-line in it. Selector = 1.', '{0}This is a text with a + new-line in it. Selector = 0.|{1}This is a text with a + new-line in it. Selector = 1.|[1,Inf]This is a text with a + new-line in it. Selector > 1.', 1), + // with single-quotes and id split accros lines + array('This is a text with a + new-line in it. Selector > 1.', '{0}This is a text with a + new-line in it. Selector = 0.|{1}This is a text with a + new-line in it. Selector = 1.|[1,Inf]This is a text with a + new-line in it. Selector > 1.', 5), + // with single-quotes and \n in text + array('This is a text with a\nnew-line in it. Selector = 0.', '{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.', 0), + // with double-quotes and id split accros lines + array("This is a text with a\nnew-line in it. Selector = 1.", "{0}This is a text with a\nnew-line in it. Selector = 0.|{1}This is a text with a\nnew-line in it. Selector = 1.|[1,Inf]This is a text with a\nnew-line in it. Selector > 1.", 1), + // esacape pipe + array('This is a text with | in it. Selector = 0.', '{0}This is a text with || in it. Selector = 0.|{1}This is a text with || in it. Selector = 1.', 0), + // Empty plural set (2 plural forms) from a .PO file + array('', '|', 1), + // Empty plural set (3 plural forms) from a .PO file + array('', '||', 1), + ); + } + + /** + * @dataProvider failingLangcodes + */ + public function testFailedLangcodes($nplural, $langCodes) + { + $matrix = $this->generateTestData($langCodes); + $this->validateMatrix($nplural, $matrix, false); + } + + /** + * @dataProvider successLangcodes + */ + public function testLangcodes($nplural, $langCodes) + { + $matrix = $this->generateTestData($langCodes); + $this->validateMatrix($nplural, $matrix); + } + + /** + * This array should contain all currently known langcodes. + * + * As it is impossible to have this ever complete we should try as hard as possible to have it almost complete. + * + * @return array + */ + public function successLangcodes() + { + return array( + array('1', array('ay', 'bo', 'cgg', 'dz', 'id', 'ja', 'jbo', 'ka', 'kk', 'km', 'ko', 'ky')), + array('2', array('nl', 'fr', 'en', 'de', 'de_GE', 'hy', 'hy_AM')), + array('3', array('be', 'bs', 'cs', 'hr')), + array('4', array('cy', 'mt', 'sl')), + array('6', array('ar')), + ); + } + + /** + * This array should be at least empty within the near future. + * + * This both depends on a complete list trying to add above as understanding + * the plural rules of the current failing languages. + * + * @return array with nplural together with langcodes + */ + public function failingLangcodes() + { + return array( + array('1', array('fa')), + array('2', array('jbo')), + array('3', array('cbs')), + array('4', array('gd', 'kw')), + array('5', array('ga')), + ); + } + + /** + * We validate only on the plural coverage. Thus the real rules is not tested. + * + * @param string $nplural Plural expected + * @param array $matrix Containing langcodes and their plural index values + * @param bool $expectSuccess + */ + protected function validateMatrix($nplural, $matrix, $expectSuccess = true) + { + foreach ($matrix as $langCode => $data) { + $indexes = array_flip($data); + if ($expectSuccess) { + $this->assertEquals($nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms."); + } else { + $this->assertNotEquals((int) $nplural, \count($indexes), "Langcode '$langCode' has '$nplural' plural forms."); + } + } + } + + protected function generateTestData($langCodes) + { + $translator = new class() { + use TranslatorTrait { + getPluralizationRule as public; + } + }; + + $matrix = array(); + foreach ($langCodes as $langCode) { + for ($count = 0; $count < 200; ++$count) { + $plural = $translator->getPluralizationRule($count, $langCode); + $matrix[$langCode][$count] = $plural; + } + } + + return $matrix; + } +} diff --git a/vendor/symfony/contracts/Translation/TranslatorInterface.php b/vendor/symfony/contracts/Translation/TranslatorInterface.php new file mode 100644 index 0000000000..2130c1b2cf --- /dev/null +++ b/vendor/symfony/contracts/Translation/TranslatorInterface.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\Contracts\Translation; + +/** + * @author Fabien Potencier <fabien@symfony.com> + */ +interface TranslatorInterface +{ + /** + * Translates the given message. + * + * When a number is provided as a parameter named "%count%", the message is parsed for plural + * forms and a translation is chosen according to this number using the following rules: + * + * Given a message with different plural translations separated by a + * pipe (|), this method returns the correct portion of the message based + * on the given number, locale and the pluralization rules in the message + * itself. + * + * The message supports two different types of pluralization rules: + * + * interval: {0} There are no apples|{1} There is one apple|]1,Inf] There are %count% apples + * indexed: There is one apple|There are %count% apples + * + * The indexed solution can also contain labels (e.g. one: There is one apple). + * This is purely for making the translations more clear - it does not + * affect the functionality. + * + * The two methods can also be mixed: + * {0} There are no apples|one: There is one apple|more: There are %count% apples + * + * An interval can represent a finite set of numbers: + * {1,2,3,4} + * + * An interval can represent numbers between two numbers: + * [1, +Inf] + * ]-1,2[ + * + * The left delimiter can be [ (inclusive) or ] (exclusive). + * The right delimiter can be [ (exclusive) or ] (inclusive). + * Beside numbers, you can use -Inf and +Inf for the infinite. + * + * @see https://en.wikipedia.org/wiki/ISO_31-11 + * + * @param string $id The message id (may also be an object that can be cast to string) + * @param array $parameters An array of parameters for the message + * @param string|null $domain The domain for the message or null to use the default + * @param string|null $locale The locale or null to use the default + * + * @return string The translated string + * + * @throws \InvalidArgumentException If the locale contains invalid characters + */ + public function trans($id, array $parameters = array(), $domain = null, $locale = null); + + /** + * Sets the current locale. + * + * @param string $locale The locale + * + * @throws \InvalidArgumentException If the locale contains invalid characters + */ + public function setLocale($locale); + + /** + * Returns the current locale. + * + * @return string The locale + */ + public function getLocale(); +} diff --git a/vendor/symfony/contracts/Translation/TranslatorTrait.php b/vendor/symfony/contracts/Translation/TranslatorTrait.php new file mode 100644 index 0000000000..e19e37cfe5 --- /dev/null +++ b/vendor/symfony/contracts/Translation/TranslatorTrait.php @@ -0,0 +1,255 @@ +<?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\Translation; + +use Symfony\Component\Translation\Exception\InvalidArgumentException; + +/** + * A trait to help implement TranslatorInterface. + * + * @author Fabien Potencier <fabien@symfony.com> + */ +trait TranslatorTrait +{ + private $locale; + + /** + * {@inheritdoc} + */ + public function setLocale($locale) + { + $this->locale = (string) $locale; + } + + /** + * {@inheritdoc} + */ + public function getLocale() + { + return $this->locale ?: \Locale::getDefault(); + } + + /** + * {@inheritdoc} + */ + public function trans($id, array $parameters = array(), $domain = null, $locale = null) + { + $id = (string) $id; + + if (!isset($parameters['%count%']) || !is_numeric($parameters['%count%'])) { + return strtr($id, $parameters); + } + + $number = (float) $parameters['%count%']; + $locale = (string) $locale ?: $this->getLocale(); + + $parts = array(); + if (preg_match('/^\|++$/', $id)) { + $parts = explode('|', $id); + } elseif (preg_match_all('/(?:\|\||[^\|])++/', $id, $matches)) { + $parts = $matches[0]; + } + + $intervalRegexp = <<<'EOF' +/^(?P<interval> + ({\s* + (\-?\d+(\.\d+)?[\s*,\s*\-?\d+(\.\d+)?]*) + \s*}) + + | + + (?P<left_delimiter>[\[\]]) + \s* + (?P<left>-Inf|\-?\d+(\.\d+)?) + \s*,\s* + (?P<right>\+?Inf|\-?\d+(\.\d+)?) + \s* + (?P<right_delimiter>[\[\]]) +)\s*(?P<message>.*?)$/xs +EOF; + + $standardRules = array(); + foreach ($parts as $part) { + $part = trim(str_replace('||', '|', $part)); + + // try to match an explicit rule, then fallback to the standard ones + if (preg_match($intervalRegexp, $part, $matches)) { + if ($matches[2]) { + foreach (explode(',', $matches[3]) as $n) { + if ($number == $n) { + return strtr($matches['message'], $parameters); + } + } + } else { + $leftNumber = '-Inf' === $matches['left'] ? -INF : (float) $matches['left']; + $rightNumber = \is_numeric($matches['right']) ? (float) $matches['right'] : INF; + + if (('[' === $matches['left_delimiter'] ? $number >= $leftNumber : $number > $leftNumber) + && (']' === $matches['right_delimiter'] ? $number <= $rightNumber : $number < $rightNumber) + ) { + return strtr($matches['message'], $parameters); + } + } + } elseif (preg_match('/^\w+\:\s*(.*?)$/', $part, $matches)) { + $standardRules[] = $matches[1]; + } else { + $standardRules[] = $part; + } + } + + $position = $this->getPluralizationRule($number, $locale); + + if (!isset($standardRules[$position])) { + // when there's exactly one rule given, and that rule is a standard + // rule, use this rule + if (1 === \count($parts) && isset($standardRules[0])) { + return strtr($standardRules[0], $parameters); + } + + $message = sprintf('Unable to choose a translation for "%s" with locale "%s" for value "%d". Double check that this translation has the correct plural options (e.g. "There is one apple|There are %%count%% apples").', $id, $locale, $number); + + if (\class_exists(InvalidArgumentException::class)) { + throw new InvalidArgumentException($message); + } + + throw new \InvalidArgumentException($message); + } + + return strtr($standardRules[$position], $parameters); + } + + /** + * Returns the plural position to use for the given locale and number. + * + * The plural rules are derived from code of the Zend Framework (2010-09-25), + * which is subject to the new BSD license (http://framework.zend.com/license/new-bsd). + * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + */ + private function getPluralizationRule(int $number, string $locale): int + { + switch ('pt_BR' !== $locale && \strlen($locale) > 3 ? substr($locale, 0, strrpos($locale, '_')) : $locale) { + case 'af': + case 'bn': + case 'bg': + case 'ca': + case 'da': + case 'de': + case 'el': + case 'en': + case 'eo': + case 'es': + case 'et': + case 'eu': + case 'fa': + case 'fi': + case 'fo': + case 'fur': + case 'fy': + case 'gl': + case 'gu': + case 'ha': + case 'he': + case 'hu': + case 'is': + case 'it': + case 'ku': + case 'lb': + case 'ml': + case 'mn': + case 'mr': + case 'nah': + case 'nb': + case 'ne': + case 'nl': + case 'nn': + case 'no': + case 'oc': + case 'om': + case 'or': + case 'pa': + case 'pap': + case 'ps': + case 'pt': + case 'so': + case 'sq': + case 'sv': + case 'sw': + case 'ta': + case 'te': + case 'tk': + case 'ur': + case 'zu': + return (1 == $number) ? 0 : 1; + + case 'am': + case 'bh': + case 'fil': + case 'fr': + case 'gun': + case 'hi': + case 'hy': + case 'ln': + case 'mg': + case 'nso': + case 'pt_BR': + case 'ti': + case 'wa': + return ((0 == $number) || (1 == $number)) ? 0 : 1; + + case 'be': + case 'bs': + case 'hr': + case 'ru': + case 'sh': + case 'sr': + case 'uk': + return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); + + case 'cs': + case 'sk': + return (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); + + case 'ga': + return (1 == $number) ? 0 : ((2 == $number) ? 1 : 2); + + case 'lt': + return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); + + case 'sl': + return (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3)); + + case 'mk': + return (1 == $number % 10) ? 0 : 1; + + case 'mt': + return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); + + case 'lv': + return (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2); + + case 'pl': + return (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); + + case 'cy': + return (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3)); + + case 'ro': + return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); + + case 'ar': + return (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))); + + default: + return 0; + } + } +} diff --git a/vendor/symfony/contracts/composer.json b/vendor/symfony/contracts/composer.json new file mode 100644 index 0000000000..2f198a0c3b --- /dev/null +++ b/vendor/symfony/contracts/composer.json @@ -0,0 +1,44 @@ +{ + "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" + }, + "suggest": { + "psr/cache": "When using the Cache contracts", + "psr/container": "When using the Service contracts", + "symfony/cache-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.0-dev" + } + } +} diff --git a/vendor/symfony/contracts/phpunit.xml.dist b/vendor/symfony/contracts/phpunit.xml.dist new file mode 100644 index 0000000000..bf26eb0b3d --- /dev/null +++ b/vendor/symfony/contracts/phpunit.xml.dist @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + backupGlobals="false" + colors="true" + bootstrap="vendor/autoload.php" + failOnRisky="true" + failOnWarning="true" +> + <php> + <ini name="error_reporting" value="-1" /> + </php> + + <testsuites> + <testsuite name="Symfony Contracts Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./Tests</directory> + <directory>./vendor</directory> + </exclude> + </whitelist> + </filter> + +</phpunit> diff --git a/vendor/symfony/debug/CHANGELOG.md b/vendor/symfony/debug/CHANGELOG.md index 31c67eb60c..122af73174 100644 --- a/vendor/symfony/debug/CHANGELOG.md +++ b/vendor/symfony/debug/CHANGELOG.md @@ -1,6 +1,12 @@ CHANGELOG ========= +4.0.0 +----- + +* removed the symfony_debug extension +* removed `ContextErrorException` + 3.4.0 ----- diff --git a/vendor/symfony/debug/Debug.php b/vendor/symfony/debug/Debug.php index 2a3d7f3159..a31d71e6aa 100644 --- a/vendor/symfony/debug/Debug.php +++ b/vendor/symfony/debug/Debug.php @@ -23,7 +23,7 @@ class Debug /** * Enables the debug tools. * - * This method registers an error handler, an exception handler and a special class loader. + * This method registers an error handler and an exception handler. * * @param int $errorReportingLevel The level of error reporting you want * @param bool $displayErrors Whether to display errors (for development) or just log them (for production) diff --git a/vendor/symfony/debug/DebugClassLoader.php b/vendor/symfony/debug/DebugClassLoader.php index c9fa76cfe7..6d5fc9c2c3 100644 --- a/vendor/symfony/debug/DebugClassLoader.php +++ b/vendor/symfony/debug/DebugClassLoader.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Debug; +use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation; + /** * Autoloader checking if the class is really defined in the file found. * @@ -21,6 +23,7 @@ namespace Symfony\Component\Debug; * @author Fabien Potencier <fabien@symfony.com> * @author Christophe Coevoet <stof@notk.org> * @author Nicolas Grekas <p@tchwork.com> + * @author Guilhem Niot <guilhem.niot@gmail.com> */ class DebugClassLoader { @@ -34,7 +37,7 @@ class DebugClassLoader private static $deprecated = array(); private static $internal = array(); private static $internalMethods = array(); - private static $php7Reserved = array('int' => 1, 'float' => 1, 'bool' => 1, 'string' => 1, 'true' => 1, 'false' => 1, 'null' => 1); + private static $annotatedParameters = array(); private static $darwinCache = array('/' => array('/', array())); public function __construct(callable $classLoader) @@ -138,14 +141,14 @@ class DebugClassLoader try { if ($this->isFinder && !isset($this->loaded[$class])) { $this->loaded[$class] = true; - if ($file = $this->classLoader[0]->findFile($class) ?: false) { - $wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file); - + if (!$file = $this->classLoader[0]->findFile($class) ?: false) { + // no-op + } elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) { require $file; - if ($wasCached) { - return; - } + return; + } else { + require $file; } } else { \call_user_func($this->classLoader, $class); @@ -184,10 +187,6 @@ class DebugClassLoader $deprecations = $this->checkAnnotations($refl, $name); - if (isset(self::$php7Reserved[\strtolower($refl->getShortName())])) { - $deprecations[] = sprintf('The "%s" class uses the reserved name "%s", it will break on PHP 7 and higher', $name, $refl->getShortName()); - } - foreach ($deprecations as $message) { @trigger_error($message, E_USER_DEPRECATED); } @@ -265,11 +264,12 @@ class DebugClassLoader return $deprecations; } - // Inherit @final and @internal annotations for methods + // Inherit @final, @internal and @param annotations for methods self::$finalMethods[$class] = array(); self::$internalMethods[$class] = array(); + self::$annotatedParameters[$class] = array(); foreach ($parentAndOwnInterfaces as $use) { - foreach (array('finalMethods', 'internalMethods') as $property) { + foreach (array('finalMethods', 'internalMethods', 'annotatedParameters') as $property) { if (isset(self::${$property}[$use])) { self::${$property}[$class] = self::${$property}[$class] ? self::${$property}[$use] + self::${$property}[$class] : self::${$property}[$use]; } @@ -293,15 +293,52 @@ class DebugClassLoader } } - // Detect method annotations - if (false === $doc = $method->getDocComment()) { + // To read method annotations + $doc = $method->getDocComment(); + + if (isset(self::$annotatedParameters[$class][$method->name])) { + $definedParameters = array(); + foreach ($method->getParameters() as $parameter) { + $definedParameters[$parameter->name] = true; + } + + foreach (self::$annotatedParameters[$class][$method->name] as $parameterName => $deprecation) { + if (!isset($definedParameters[$parameterName]) && !($doc && preg_match("/\\n\\s+\\* @param (.*?)(?<= )\\\${$parameterName}\\b/", $doc))) { + $deprecations[] = sprintf($deprecation, $class); + } + } + } + + if (!$doc) { continue; } + $finalOrInternal = false; + foreach (array('final', 'internal') as $annotation) { if (false !== \strpos($doc, $annotation) && preg_match('#\n\s+\* @'.$annotation.'(?:( .+?)\.?)?\r?\n\s+\*(?: @|/$)#s', $doc, $notice)) { $message = isset($notice[1]) ? preg_replace('#\s*\r?\n \* +#', ' ', $notice[1]) : ''; self::${$annotation.'Methods'}[$class][$method->name] = array($class, $message); + $finalOrInternal = true; + } + } + + 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)) { + continue; + } + if (!isset(self::$annotatedParameters[$class][$method->name])) { + $definedParameters = array(); + foreach ($method->getParameters() as $parameter) { + $definedParameters[$parameter->name] = true; + } + } + foreach ($matches as list(, $parameterType, $parameterName)) { + if (!isset($definedParameters[$parameterName])) { + $parameterType = trim($parameterType); + self::$annotatedParameters[$class][$method->name][$parameterName] = sprintf('The "%%s::%s()" method will require a new "%s$%s" argument in the next major version of its parent class "%s", not defining it is deprecated.', $method->name, $parameterType ? $parameterType.' ' : '', $parameterName, $method->class); } } } diff --git a/vendor/symfony/debug/ErrorHandler.php b/vendor/symfony/debug/ErrorHandler.php index 69a7280417..ecae93dbc1 100644 --- a/vendor/symfony/debug/ErrorHandler.php +++ b/vendor/symfony/debug/ErrorHandler.php @@ -13,9 +13,9 @@ namespace Symfony\Component\Debug; use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; -use Symfony\Component\Debug\Exception\ContextErrorException; use Symfony\Component\Debug\Exception\FatalErrorException; use Symfony\Component\Debug\Exception\FatalThrowableError; +use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\Debug\Exception\OutOfMemoryException; use Symfony\Component\Debug\Exception\SilencedErrorContext; use Symfony\Component\Debug\FatalErrorHandler\ClassNotFoundFatalErrorHandler; @@ -97,8 +97,6 @@ class ErrorHandler private $bootstrappingLogger; private static $reservedMemory; - private static $stackedErrors = array(); - private static $stackedErrorLevels = array(); private static $toStringException = null; private static $silencedErrorCache = array(); private static $silencedErrorCount = 0; @@ -398,10 +396,8 @@ class ErrorHandler if (4 < $numArgs = \func_num_args()) { $context = $scope ? (func_get_arg(4) ?: array()) : array(); - $backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM } else { $context = array(); - $backtrace = null; } if (isset($context['GLOBALS']) && $scope) { @@ -410,24 +406,19 @@ class ErrorHandler $context = $e; } - if (null !== $backtrace && $type & E_ERROR) { - // E_ERROR fatal errors are triggered on HHVM when - // hhvm.error_handling.call_user_handler_on_fatals=1 - // which is the way to get their backtrace. - $this->handleFatalError(compact('type', 'message', 'file', 'line', 'backtrace')); - - return true; + if (false !== strpos($message, "class@anonymous\0")) { + $logMessage = $this->levels[$type].': '.(new FlattenException())->setMessage($message)->getMessage(); + } else { + $logMessage = $this->levels[$type].': '.$message; } - $logMessage = $this->levels[$type].': '.$message; - if (null !== self::$toStringException) { $errorAsException = self::$toStringException; self::$toStringException = null; } elseif (!$throw && !($type & $level)) { if (!isset(self::$silencedErrorCache[$id = $file.':'.$line])) { - $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3), $type, $file, $line, false) : array(); - $errorAsException = new SilencedErrorContext($type, $file, $line, $lightTrace); + $lightTrace = $this->tracedErrors & $type ? $this->cleanTrace(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5), $type, $file, $line, false) : array(); + $errorAsException = new SilencedErrorContext($type, $file, $line, isset($lightTrace[1]) ? array($lightTrace[0]) : $lightTrace); } elseif (isset(self::$silencedErrorCache[$id][$message])) { $lightTrace = null; $errorAsException = self::$silencedErrorCache[$id][$message]; @@ -448,19 +439,15 @@ class ErrorHandler return; } } else { - if ($scope) { - $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context); - } else { - $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); - } + $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); - // Clean the trace by removing function arguments and the first frames added by the error handler itself. if ($throw || $this->tracedErrors & $type) { - $backtrace = $backtrace ?: $errorAsException->getTrace(); + $backtrace = $errorAsException->getTrace(); $lightTrace = $this->cleanTrace($backtrace, $type, $file, $line, $throw); $this->traceReflector->setValue($errorAsException, $lightTrace); } else { $this->traceReflector->setValue($errorAsException, array()); + $backtrace = array(); } } @@ -474,32 +461,25 @@ class ErrorHandler && ('trigger_error' === $backtrace[$i - 1]['function'] || 'user_error' === $backtrace[$i - 1]['function']) ) { // Here, we know trigger_error() has been called from __toString(). - // HHVM is fine with throwing from __toString() but PHP triggers a fatal error instead. + // PHP triggers a fatal error when throwing from __toString(). // A small convention allows working around the limitation: // given a caught $e exception in __toString(), quitting the method with // `return trigger_error($e, E_USER_ERROR);` allows this error handler // to make $e get through the __toString() barrier. foreach ($context as $e) { - if (($e instanceof \Exception || $e instanceof \Throwable) && $e->__toString() === $message) { - if (1 === $i) { - // On HHVM - $errorAsException = $e; - break; - } + if ($e instanceof \Throwable && $e->__toString() === $message) { self::$toStringException = $e; return true; } } - if (1 < $i) { - // On PHP (not on HHVM), display the original error message instead of the default one. - $this->handleException($errorAsException); + // Display the original error message instead of the default one. + $this->handleException($errorAsException); - // Stop the process by giving back the error to the native handler. - return false; - } + // Stop the process by giving back the error to the native handler. + return false; } } } @@ -509,13 +489,6 @@ class ErrorHandler if ($this->isRecursive) { $log = 0; - } elseif (self::$stackedErrorLevels) { - self::$stackedErrors[] = array( - $this->loggers[$type][0], - ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG, - $logMessage, - $errorAsException ? array('exception' => $errorAsException) : array(), - ); } else { try { $this->isRecursive = true; @@ -549,27 +522,29 @@ class ErrorHandler $handlerException = null; if (($this->loggedErrors & $type) || $exception instanceof FatalThrowableError) { + if (false !== strpos($message = $exception->getMessage(), "class@anonymous\0")) { + $message = (new FlattenException())->setMessage($message)->getMessage(); + } if ($exception instanceof FatalErrorException) { if ($exception instanceof FatalThrowableError) { $error = array( 'type' => $type, - 'message' => $message = $exception->getMessage(), + 'message' => $message, 'file' => $exception->getFile(), 'line' => $exception->getLine(), ); } else { - $message = 'Fatal '.$exception->getMessage(); + $message = 'Fatal '.$message; } } elseif ($exception instanceof \ErrorException) { - $message = 'Uncaught '.$exception->getMessage(); + $message = 'Uncaught '.$message; } else { - $message = 'Uncaught Exception: '.$exception->getMessage(); + $message = 'Uncaught Exception: '.$message; } } if ($this->loggedErrors & $type) { try { $this->loggers[$type][0]->log($this->loggers[$type][1], $message, array('exception' => $exception)); - } catch (\Exception $handlerException) { } catch (\Throwable $handlerException) { } } @@ -588,7 +563,6 @@ class ErrorHandler return \call_user_func($exceptionHandler, $exception); } $handlerException = $handlerException ?: $exception; - } catch (\Exception $handlerException) { } catch (\Throwable $handlerException) { } if ($exception === $handlerException) { @@ -649,16 +623,6 @@ class ErrorHandler $error = error_get_last(); } - try { - while (self::$stackedErrorLevels) { - static::unstackErrors(); - } - } catch (\Exception $exception) { - // Handled below - } catch (\Throwable $exception) { - // Handled below - } - if ($error && $error['type'] &= E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR) { // Let's not throw anymore but keep logging $handler->throwAt(0, true); @@ -669,10 +633,12 @@ class ErrorHandler } else { $exception = new FatalErrorException($handler->levels[$error['type']].': '.$error['message'], 0, $error['type'], $error['file'], $error['line'], 2, true, $trace); } + } else { + $exception = null; } try { - if (isset($exception)) { + if (null !== $exception) { self::$exitCode = 255; $handler->handleException($exception, $error); } @@ -687,55 +653,6 @@ class ErrorHandler } /** - * Configures the error handler for delayed handling. - * Ensures also that non-catchable fatal errors are never silenced. - * - * As shown by http://bugs.php.net/42098 and http://bugs.php.net/60724 - * PHP has a compile stage where it behaves unusually. To workaround it, - * we plug an error handler that only stacks errors for later. - * - * The most important feature of this is to prevent - * autoloading until unstackErrors() is called. - * - * @deprecated since version 3.4, to be removed in 4.0. - */ - public static function stackErrors() - { - @trigger_error('Support for stacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED); - - self::$stackedErrorLevels[] = error_reporting(error_reporting() | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR); - } - - /** - * Unstacks stacked errors and forwards to the logger. - * - * @deprecated since version 3.4, to be removed in 4.0. - */ - public static function unstackErrors() - { - @trigger_error('Support for unstacking errors is deprecated since Symfony 3.4 and will be removed in 4.0.', E_USER_DEPRECATED); - - $level = array_pop(self::$stackedErrorLevels); - - if (null !== $level) { - $errorReportingLevel = error_reporting($level); - if ($errorReportingLevel !== ($level | E_PARSE | E_ERROR | E_CORE_ERROR | E_COMPILE_ERROR)) { - // If the user changed the error level, do not overwrite it - error_reporting($errorReportingLevel); - } - } - - if (empty(self::$stackedErrorLevels)) { - $errors = self::$stackedErrors; - self::$stackedErrors = array(); - - foreach ($errors as $error) { - $error[0]->log($error[1], $error[2], $error[3]); - } - } - } - - /** * Gets the fatal error handlers. * * Override this method if you want to define more fatal error handlers. @@ -751,6 +668,9 @@ class ErrorHandler ); } + /** + * Cleans the trace by removing function arguments and the frames added by the error handler and DebugClassLoader. + */ private function cleanTrace($backtrace, $type, $file, $line, $throw) { $lightTrace = $backtrace; @@ -761,6 +681,13 @@ class ErrorHandler break; } } + if (class_exists(DebugClassLoader::class, false)) { + for ($i = \count($lightTrace) - 2; 0 < $i; --$i) { + if (DebugClassLoader::class === ($lightTrace[$i]['class'] ?? null)) { + array_splice($lightTrace, --$i, 2); + } + } + } if (!($throw || $this->scopedErrors & $type)) { for ($i = 0; isset($lightTrace[$i]); ++$i) { unset($lightTrace[$i]['args'], $lightTrace[$i]['object']); diff --git a/vendor/symfony/debug/Exception/ClassNotFoundException.php b/vendor/symfony/debug/Exception/ClassNotFoundException.php index de5c456443..fa98c4975d 100644 --- a/vendor/symfony/debug/Exception/ClassNotFoundException.php +++ b/vendor/symfony/debug/Exception/ClassNotFoundException.php @@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception; */ class ClassNotFoundException extends FatalErrorException { - public function __construct($message, \ErrorException $previous) + public function __construct(string $message, \ErrorException $previous) { parent::__construct( $message, diff --git a/vendor/symfony/debug/Exception/ContextErrorException.php b/vendor/symfony/debug/Exception/ContextErrorException.php deleted file mode 100644 index 554139da3b..0000000000 --- a/vendor/symfony/debug/Exception/ContextErrorException.php +++ /dev/null @@ -1,40 +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\Debug\Exception; - -/** - * Error Exception with Variable Context. - * - * @author Christian Sciberras <uuf6429@gmail.com> - * - * @deprecated since version 3.3. Instead, \ErrorException will be used directly in 4.0. - */ -class ContextErrorException extends \ErrorException -{ - private $context = array(); - - public function __construct($message, $code, $severity, $filename, $lineno, $context = array()) - { - parent::__construct($message, $code, $severity, $filename, $lineno); - $this->context = $context; - } - - /** - * @return array Array of variables that existed when the exception occurred - */ - public function getContext() - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0.', __CLASS__), E_USER_DEPRECATED); - - return $this->context; - } -} diff --git a/vendor/symfony/debug/Exception/FatalErrorException.php b/vendor/symfony/debug/Exception/FatalErrorException.php index 8d996a422b..8305d39218 100644 --- a/vendor/symfony/debug/Exception/FatalErrorException.php +++ b/vendor/symfony/debug/Exception/FatalErrorException.php @@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception; */ class FatalErrorException extends \ErrorException { - public function __construct($message, $code, $severity, $filename, $lineno, $traceOffset = null, $traceArgs = true, array $trace = null, $previous = null) + public function __construct(string $message, int $code, int $severity, string $filename, int $lineno, int $traceOffset = null, bool $traceArgs = true, array $trace = null, \Throwable $previous = null) { parent::__construct($message, $code, $severity, $filename, $lineno, $previous); @@ -60,11 +60,6 @@ class FatalErrorException extends \ErrorException unset($frame); $trace = array_reverse($trace); - } elseif (\function_exists('symfony_debug_backtrace')) { - $trace = symfony_debug_backtrace(); - if (0 < $traceOffset) { - array_splice($trace, 0, $traceOffset); - } } else { $trace = array(); } diff --git a/vendor/symfony/debug/Exception/FatalThrowableError.php b/vendor/symfony/debug/Exception/FatalThrowableError.php index fafc92263e..cdafb2a568 100644 --- a/vendor/symfony/debug/Exception/FatalThrowableError.php +++ b/vendor/symfony/debug/Exception/FatalThrowableError.php @@ -18,21 +18,22 @@ namespace Symfony\Component\Debug\Exception; */ class FatalThrowableError extends FatalErrorException { + private $originalClassName; + public function __construct(\Throwable $e) { + $this->originalClassName = \get_class($e); + if ($e instanceof \ParseError) { - $message = 'Parse error: '.$e->getMessage(); $severity = E_PARSE; } elseif ($e instanceof \TypeError) { - $message = 'Type error: '.$e->getMessage(); $severity = E_RECOVERABLE_ERROR; } else { - $message = $e->getMessage(); $severity = E_ERROR; } \ErrorException::__construct( - $message, + $e->getMessage(), $e->getCode(), $severity, $e->getFile(), @@ -42,4 +43,9 @@ class FatalThrowableError extends FatalErrorException $this->setTrace($e->getTrace()); } + + public function getOriginalClassName(): string + { + return $this->originalClassName; + } } diff --git a/vendor/symfony/debug/Exception/FlattenException.php b/vendor/symfony/debug/Exception/FlattenException.php index f76cf23f33..f85522ce62 100644 --- a/vendor/symfony/debug/Exception/FlattenException.php +++ b/vendor/symfony/debug/Exception/FlattenException.php @@ -15,7 +15,7 @@ use Symfony\Component\HttpFoundation\Exception\RequestExceptionInterface; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; /** - * FlattenException wraps a PHP Exception to be able to serialize it. + * FlattenException wraps a PHP Error or Exception to be able to serialize it. * * Basically, this class removes all objects from the trace. * @@ -35,6 +35,11 @@ class FlattenException public static function create(\Exception $exception, $statusCode = null, array $headers = array()) { + return static::createFromThrowable($exception, $statusCode, $headers); + } + + public static function createFromThrowable(\Throwable $exception, ?int $statusCode = null, array $headers = array()): self + { $e = new static(); $e->setMessage($exception->getMessage()); $e->setCode($exception->getCode()); @@ -52,17 +57,15 @@ class FlattenException $e->setStatusCode($statusCode); $e->setHeaders($headers); - $e->setTraceFromException($exception); - $e->setClass(\get_class($exception)); + $e->setTraceFromThrowable($exception); + $e->setClass($exception instanceof FatalThrowableError ? $exception->getOriginalClassName() : \get_class($exception)); $e->setFile($exception->getFile()); $e->setLine($exception->getLine()); $previous = $exception->getPrevious(); - if ($previous instanceof \Exception) { - $e->setPrevious(static::create($previous)); - } elseif ($previous instanceof \Throwable) { - $e->setPrevious(static::create(new FatalThrowableError($previous))); + if ($previous instanceof \Throwable) { + $e->setPrevious(static::createFromThrowable($previous)); } return $e; @@ -87,9 +90,14 @@ class FlattenException return $this->statusCode; } + /** + * @return $this + */ public function setStatusCode($code) { $this->statusCode = $code; + + return $this; } public function getHeaders() @@ -97,9 +105,14 @@ class FlattenException return $this->headers; } + /** + * @return $this + */ public function setHeaders(array $headers) { $this->headers = $headers; + + return $this; } public function getClass() @@ -107,9 +120,14 @@ class FlattenException return $this->class; } + /** + * @return $this + */ public function setClass($class) { - $this->class = $class; + $this->class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; + + return $this; } public function getFile() @@ -117,9 +135,14 @@ class FlattenException return $this->file; } + /** + * @return $this + */ public function setFile($file) { $this->file = $file; + + return $this; } public function getLine() @@ -127,9 +150,14 @@ class FlattenException return $this->line; } + /** + * @return $this + */ public function setLine($line) { $this->line = $line; + + return $this; } public function getMessage() @@ -137,9 +165,20 @@ class FlattenException return $this->message; } + /** + * @return $this + */ public function setMessage($message) { + if (false !== strpos($message, "class@anonymous\0")) { + $message = preg_replace_callback('/class@anonymous\x00.*?\.php0x?[0-9a-fA-F]++/', function ($m) { + return \class_exists($m[0], false) ? get_parent_class($m[0]).'@anonymous' : $m[0]; + }, $message); + } + $this->message = $message; + + return $this; } public function getCode() @@ -147,9 +186,14 @@ class FlattenException return $this->code; } + /** + * @return $this + */ public function setCode($code) { $this->code = $code; + + return $this; } public function getPrevious() @@ -157,9 +201,14 @@ class FlattenException return $this->previous; } + /** + * @return $this + */ public function setPrevious(self $previous) { $this->previous = $previous; + + return $this; } public function getAllPrevious() @@ -178,11 +227,24 @@ class FlattenException return $this->trace; } + /** + * @deprecated since 4.1, use {@see setTraceFromThrowable()} instead. + */ public function setTraceFromException(\Exception $exception) { - $this->setTrace($exception->getTrace(), $exception->getFile(), $exception->getLine()); + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), E_USER_DEPRECATED); + + $this->setTraceFromThrowable($exception); } + public function setTraceFromThrowable(\Throwable $throwable) + { + return $this->setTrace($throwable->getTrace(), $throwable->getFile(), $throwable->getLine()); + } + + /** + * @return $this + */ public function setTrace($trace, $file, $line) { $this->trace = array(); @@ -216,6 +278,8 @@ class FlattenException 'args' => isset($entry['args']) ? $this->flattenArgs($entry['args']) : array(), ); } + + return $this; } private function flattenArgs($args, $level = 0, &$count = 0) diff --git a/vendor/symfony/debug/Exception/SilencedErrorContext.php b/vendor/symfony/debug/Exception/SilencedErrorContext.php index 4be83491b9..6f84617c46 100644 --- a/vendor/symfony/debug/Exception/SilencedErrorContext.php +++ b/vendor/symfony/debug/Exception/SilencedErrorContext.php @@ -25,7 +25,7 @@ class SilencedErrorContext implements \JsonSerializable private $line; private $trace; - public function __construct($severity, $file, $line, array $trace = array(), $count = 1) + public function __construct(int $severity, string $file, int $line, array $trace = array(), int $count = 1) { $this->severity = $severity; $this->file = $file; diff --git a/vendor/symfony/debug/Exception/UndefinedFunctionException.php b/vendor/symfony/debug/Exception/UndefinedFunctionException.php index 8f5f454e55..d936c8759e 100644 --- a/vendor/symfony/debug/Exception/UndefinedFunctionException.php +++ b/vendor/symfony/debug/Exception/UndefinedFunctionException.php @@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception; */ class UndefinedFunctionException extends FatalErrorException { - public function __construct($message, \ErrorException $previous) + public function __construct(string $message, \ErrorException $previous) { parent::__construct( $message, diff --git a/vendor/symfony/debug/Exception/UndefinedMethodException.php b/vendor/symfony/debug/Exception/UndefinedMethodException.php index f7e340baf4..f627561fe1 100644 --- a/vendor/symfony/debug/Exception/UndefinedMethodException.php +++ b/vendor/symfony/debug/Exception/UndefinedMethodException.php @@ -18,7 +18,7 @@ namespace Symfony\Component\Debug\Exception; */ class UndefinedMethodException extends FatalErrorException { - public function __construct($message, \ErrorException $previous) + public function __construct(string $message, \ErrorException $previous) { parent::__construct( $message, diff --git a/vendor/symfony/debug/ExceptionHandler.php b/vendor/symfony/debug/ExceptionHandler.php index f18ee2a9f0..ea666b1ac3 100644 --- a/vendor/symfony/debug/ExceptionHandler.php +++ b/vendor/symfony/debug/ExceptionHandler.php @@ -36,7 +36,7 @@ class ExceptionHandler private $caughtLength; private $fileLinkFormat; - public function __construct($debug = true, $charset = null, $fileLinkFormat = null) + public function __construct(bool $debug = true, string $charset = null, $fileLinkFormat = null) { $this->debug = $debug; $this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8'; @@ -253,7 +253,8 @@ EOF } catch (\Exception $e) { // something nasty happened and we cannot throw an exception anymore if ($this->debug) { - $title = sprintf('Exception thrown when handling an exception (%s: %s)', \get_class($e), $this->escapeHtml($e->getMessage())); + $e = FlattenException::create($e); + $title = sprintf('Exception thrown when handling an exception (%s: %s)', $e->getClass(), $this->escapeHtml($e->getMessage())); } else { $title = 'Whoops, looks like something went wrong.'; } diff --git a/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php index 2b59c14692..4ccd16fe30 100644 --- a/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/vendor/symfony/debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php @@ -83,7 +83,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface * * @return array An array of possible fully qualified class names */ - private function getClassCandidates($class) + private function getClassCandidates(string $class): array { if (!\is_array($functions = spl_autoload_functions())) { return array(); @@ -124,14 +124,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface return array_unique($classes); } - /** - * @param string $path - * @param string $class - * @param string $prefix - * - * @return array - */ - private function findClassInPath($path, $class, $prefix) + private function findClassInPath(string $path, string $class, string $prefix): array { if (!$path = realpath($path.'/'.strtr($prefix, '\\_', '//')) ?: realpath($path.'/'.\dirname(strtr($prefix, '\\_', '//'))) ?: realpath($path)) { return array(); @@ -148,14 +141,7 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface return $classes; } - /** - * @param string $path - * @param string $file - * @param string $prefix - * - * @return string|null - */ - private function convertFileToClass($path, $file, $prefix) + private function convertFileToClass(string $path, string $file, string $prefix): ?string { $candidates = array( // namespaced class @@ -192,14 +178,11 @@ class ClassNotFoundFatalErrorHandler implements FatalErrorHandlerInterface return $candidate; } } + + return null; } - /** - * @param string $class - * - * @return bool - */ - private function classExists($class) + private function classExists(string $class): bool { return class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false); } diff --git a/vendor/symfony/debug/Resources/ext/README.md b/vendor/symfony/debug/Resources/ext/README.md deleted file mode 100644 index 25dccf0766..0000000000 --- a/vendor/symfony/debug/Resources/ext/README.md +++ /dev/null @@ -1,134 +0,0 @@ -Symfony Debug Extension for PHP 5 -================================= - -This extension publishes several functions to help building powerful debugging tools. -It is compatible with PHP 5.3, 5.4, 5.5 and 5.6; with ZTS and non-ZTS modes. -It is not required thus not provided for PHP 7. - -symfony_zval_info() -------------------- - -- exposes zval_hash/refcounts, allowing e.g. efficient exploration of arbitrary structures in PHP, -- does work with references, preventing memory copying. - -Its behavior is about the same as: - -```php -<?php - -function symfony_zval_info($key, $array, $options = 0) -{ - - // $options is currently not used, but could be in future version. - - if (!array_key_exists($key, $array)) { - return null; - } - - $info = array( - 'type' => gettype($array[$key]), - 'zval_hash' => /* hashed memory address of $array[$key] */, - 'zval_refcount' => /* internal zval refcount of $array[$key] */, - 'zval_isref' => /* is_ref status of $array[$key] */, - ); - - switch ($info['type']) { - case 'object': - $info += array( - 'object_class' => get_class($array[$key]), - 'object_refcount' => /* internal object refcount of $array[$key] */, - 'object_hash' => spl_object_hash($array[$key]), - 'object_handle' => /* internal object handle $array[$key] */, - ); - break; - - case 'resource': - $info += array( - 'resource_handle' => (int) $array[$key], - 'resource_type' => get_resource_type($array[$key]), - 'resource_refcount' => /* internal resource refcount of $array[$key] */, - ); - break; - - case 'array': - $info += array( - 'array_count' => count($array[$key]), - ); - break; - - case 'string': - $info += array( - 'strlen' => strlen($array[$key]), - ); - break; - } - - return $info; -} -``` - -symfony_debug_backtrace() -------------------------- - -This function works like debug_backtrace(), except that it can fetch the full backtrace in case of fatal errors: - -```php -function foo() { fatal(); } -function bar() { foo(); } - -function sd() { var_dump(symfony_debug_backtrace()); } - -register_shutdown_function('sd'); - -bar(); - -/* Will output -Fatal error: Call to undefined function fatal() in foo.php on line 42 -array(3) { - [0]=> - array(2) { - ["function"]=> - string(2) "sd" - ["args"]=> - array(0) { - } - } - [1]=> - array(4) { - ["file"]=> - string(7) "foo.php" - ["line"]=> - int(1) - ["function"]=> - string(3) "foo" - ["args"]=> - array(0) { - } - } - [2]=> - array(4) { - ["file"]=> - string(102) "foo.php" - ["line"]=> - int(2) - ["function"]=> - string(3) "bar" - ["args"]=> - array(0) { - } - } -} -*/ -``` - -Usage ------ - -To enable the extension from source, run: - -``` - phpize - ./configure - make - sudo make install -``` diff --git a/vendor/symfony/debug/Resources/ext/config.m4 b/vendor/symfony/debug/Resources/ext/config.m4 deleted file mode 100644 index 3c56047150..0000000000 --- a/vendor/symfony/debug/Resources/ext/config.m4 +++ /dev/null @@ -1,63 +0,0 @@ -dnl $Id$ -dnl config.m4 for extension symfony_debug - -dnl Comments in this file start with the string 'dnl'. -dnl Remove where necessary. This file will not work -dnl without editing. - -dnl If your extension references something external, use with: - -dnl PHP_ARG_WITH(symfony_debug, for symfony_debug support, -dnl Make sure that the comment is aligned: -dnl [ --with-symfony_debug Include symfony_debug support]) - -dnl Otherwise use enable: - -PHP_ARG_ENABLE(symfony_debug, whether to enable symfony_debug support, -dnl Make sure that the comment is aligned: -[ --enable-symfony_debug Enable symfony_debug support]) - -if test "$PHP_SYMFONY_DEBUG" != "no"; then - dnl Write more examples of tests here... - - dnl # --with-symfony_debug -> check with-path - dnl SEARCH_PATH="/usr/local /usr" # you might want to change this - dnl SEARCH_FOR="/include/symfony_debug.h" # you most likely want to change this - dnl if test -r $PHP_SYMFONY_DEBUG/$SEARCH_FOR; then # path given as parameter - dnl SYMFONY_DEBUG_DIR=$PHP_SYMFONY_DEBUG - dnl else # search default path list - dnl AC_MSG_CHECKING([for symfony_debug files in default path]) - dnl for i in $SEARCH_PATH ; do - dnl if test -r $i/$SEARCH_FOR; then - dnl SYMFONY_DEBUG_DIR=$i - dnl AC_MSG_RESULT(found in $i) - dnl fi - dnl done - dnl fi - dnl - dnl if test -z "$SYMFONY_DEBUG_DIR"; then - dnl AC_MSG_RESULT([not found]) - dnl AC_MSG_ERROR([Please reinstall the symfony_debug distribution]) - dnl fi - - dnl # --with-symfony_debug -> add include path - dnl PHP_ADD_INCLUDE($SYMFONY_DEBUG_DIR/include) - - dnl # --with-symfony_debug -> check for lib and symbol presence - dnl LIBNAME=symfony_debug # you may want to change this - dnl LIBSYMBOL=symfony_debug # you most likely want to change this - - dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, - dnl [ - dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SYMFONY_DEBUG_DIR/lib, SYMFONY_DEBUG_SHARED_LIBADD) - dnl AC_DEFINE(HAVE_SYMFONY_DEBUGLIB,1,[ ]) - dnl ],[ - dnl AC_MSG_ERROR([wrong symfony_debug lib version or lib not found]) - dnl ],[ - dnl -L$SYMFONY_DEBUG_DIR/lib -lm - dnl ]) - dnl - dnl PHP_SUBST(SYMFONY_DEBUG_SHARED_LIBADD) - - PHP_NEW_EXTENSION(symfony_debug, symfony_debug.c, $ext_shared) -fi diff --git a/vendor/symfony/debug/Resources/ext/config.w32 b/vendor/symfony/debug/Resources/ext/config.w32 deleted file mode 100644 index 487e691389..0000000000 --- a/vendor/symfony/debug/Resources/ext/config.w32 +++ /dev/null @@ -1,13 +0,0 @@ -// $Id$ -// vim:ft=javascript - -// If your extension references something external, use ARG_WITH -// ARG_WITH("symfony_debug", "for symfony_debug support", "no"); - -// Otherwise, use ARG_ENABLE -// ARG_ENABLE("symfony_debug", "enable symfony_debug support", "no"); - -if (PHP_SYMFONY_DEBUG != "no") { - EXTENSION("symfony_debug", "symfony_debug.c"); -} - diff --git a/vendor/symfony/debug/Resources/ext/php_symfony_debug.h b/vendor/symfony/debug/Resources/ext/php_symfony_debug.h deleted file mode 100644 index 26d0e8c012..0000000000 --- a/vendor/symfony/debug/Resources/ext/php_symfony_debug.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifndef PHP_SYMFONY_DEBUG_H -#define PHP_SYMFONY_DEBUG_H - -extern zend_module_entry symfony_debug_module_entry; -#define phpext_symfony_debug_ptr &symfony_debug_module_entry - -#define PHP_SYMFONY_DEBUG_VERSION "2.7" - -#ifdef PHP_WIN32 -# define PHP_SYMFONY_DEBUG_API __declspec(dllexport) -#elif defined(__GNUC__) && __GNUC__ >= 4 -# define PHP_SYMFONY_DEBUG_API __attribute__ ((visibility("default"))) -#else -# define PHP_SYMFONY_DEBUG_API -#endif - -#ifdef ZTS -#include "TSRM.h" -#endif - -ZEND_BEGIN_MODULE_GLOBALS(symfony_debug) - intptr_t req_rand_init; - void (*old_error_cb)(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); - zval *debug_bt; -ZEND_END_MODULE_GLOBALS(symfony_debug) - -PHP_MINIT_FUNCTION(symfony_debug); -PHP_MSHUTDOWN_FUNCTION(symfony_debug); -PHP_RINIT_FUNCTION(symfony_debug); -PHP_RSHUTDOWN_FUNCTION(symfony_debug); -PHP_MINFO_FUNCTION(symfony_debug); -PHP_GINIT_FUNCTION(symfony_debug); -PHP_GSHUTDOWN_FUNCTION(symfony_debug); - -PHP_FUNCTION(symfony_zval_info); -PHP_FUNCTION(symfony_debug_backtrace); - -static char *_symfony_debug_memory_address_hash(void * TSRMLS_DC); -static const char *_symfony_debug_zval_type(zval *); -static const char* _symfony_debug_get_resource_type(long TSRMLS_DC); -static int _symfony_debug_get_resource_refcount(long TSRMLS_DC); - -void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args); - -#ifdef ZTS -#define SYMFONY_DEBUG_G(v) TSRMG(symfony_debug_globals_id, zend_symfony_debug_globals *, v) -#else -#define SYMFONY_DEBUG_G(v) (symfony_debug_globals.v) -#endif - -#endif /* PHP_SYMFONY_DEBUG_H */ diff --git a/vendor/symfony/debug/Resources/ext/symfony_debug.c b/vendor/symfony/debug/Resources/ext/symfony_debug.c deleted file mode 100644 index 0d7cb60232..0000000000 --- a/vendor/symfony/debug/Resources/ext/symfony_debug.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * This file is part of the Symfony package. - * - * (c) Fabien Potencier <fabien@symfony.com> - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#ifdef ZTS -#include "TSRM.h" -#endif -#include "php_ini.h" -#include "ext/standard/info.h" -#include "php_symfony_debug.h" -#include "ext/standard/php_rand.h" -#include "ext/standard/php_lcg.h" -#include "ext/spl/php_spl.h" -#include "Zend/zend_gc.h" -#include "Zend/zend_builtin_functions.h" -#include "Zend/zend_extensions.h" /* for ZEND_EXTENSION_API_NO */ -#include "ext/standard/php_array.h" -#include "Zend/zend_interfaces.h" -#include "SAPI.h" - -#define IS_PHP_53 ZEND_EXTENSION_API_NO == 220090626 - -ZEND_DECLARE_MODULE_GLOBALS(symfony_debug) - -ZEND_BEGIN_ARG_INFO_EX(symfony_zval_arginfo, 0, 0, 2) - ZEND_ARG_INFO(0, key) - ZEND_ARG_ARRAY_INFO(0, array, 0) - ZEND_ARG_INFO(0, options) -ZEND_END_ARG_INFO() - -const zend_function_entry symfony_debug_functions[] = { - PHP_FE(symfony_zval_info, symfony_zval_arginfo) - PHP_FE(symfony_debug_backtrace, NULL) - PHP_FE_END -}; - -PHP_FUNCTION(symfony_debug_backtrace) -{ - if (zend_parse_parameters_none() == FAILURE) { - return; - } -#if IS_PHP_53 - zend_fetch_debug_backtrace(return_value, 1, 0 TSRMLS_CC); -#else - zend_fetch_debug_backtrace(return_value, 1, 0, 0 TSRMLS_CC); -#endif - - if (!SYMFONY_DEBUG_G(debug_bt)) { - return; - } - - php_array_merge(Z_ARRVAL_P(return_value), Z_ARRVAL_P(SYMFONY_DEBUG_G(debug_bt)), 0 TSRMLS_CC); -} - -PHP_FUNCTION(symfony_zval_info) -{ - zval *key = NULL, *arg = NULL; - zval **data = NULL; - HashTable *array = NULL; - long options = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zh|l", &key, &array, &options) == FAILURE) { - return; - } - - switch (Z_TYPE_P(key)) { - case IS_STRING: - if (zend_symtable_find(array, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&data) == FAILURE) { - return; - } - break; - case IS_LONG: - if (zend_hash_index_find(array, Z_LVAL_P(key), (void **)&data)) { - return; - } - break; - } - - arg = *data; - - array_init(return_value); - - add_assoc_string(return_value, "type", (char *)_symfony_debug_zval_type(arg), 1); - add_assoc_stringl(return_value, "zval_hash", _symfony_debug_memory_address_hash((void *)arg TSRMLS_CC), 16, 0); - add_assoc_long(return_value, "zval_refcount", Z_REFCOUNT_P(arg)); - add_assoc_bool(return_value, "zval_isref", (zend_bool)Z_ISREF_P(arg)); - - if (Z_TYPE_P(arg) == IS_OBJECT) { - char hash[33] = {0}; - - php_spl_object_hash(arg, (char *)hash TSRMLS_CC); - add_assoc_stringl(return_value, "object_class", (char *)Z_OBJCE_P(arg)->name, Z_OBJCE_P(arg)->name_length, 1); - add_assoc_long(return_value, "object_refcount", EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(arg)].bucket.obj.refcount); - add_assoc_string(return_value, "object_hash", hash, 1); - add_assoc_long(return_value, "object_handle", Z_OBJ_HANDLE_P(arg)); - } else if (Z_TYPE_P(arg) == IS_ARRAY) { - add_assoc_long(return_value, "array_count", zend_hash_num_elements(Z_ARRVAL_P(arg))); - } else if(Z_TYPE_P(arg) == IS_RESOURCE) { - add_assoc_long(return_value, "resource_handle", Z_LVAL_P(arg)); - add_assoc_string(return_value, "resource_type", (char *)_symfony_debug_get_resource_type(Z_LVAL_P(arg) TSRMLS_CC), 1); - add_assoc_long(return_value, "resource_refcount", _symfony_debug_get_resource_refcount(Z_LVAL_P(arg) TSRMLS_CC)); - } else if (Z_TYPE_P(arg) == IS_STRING) { - add_assoc_long(return_value, "strlen", Z_STRLEN_P(arg)); - } -} - -void symfony_debug_error_cb(int type, const char *error_filename, const uint error_lineno, const char *format, va_list args) -{ - TSRMLS_FETCH(); - zval *retval; - - switch (type) { - case E_ERROR: - case E_PARSE: - case E_CORE_ERROR: - case E_CORE_WARNING: - case E_COMPILE_ERROR: - case E_COMPILE_WARNING: - ALLOC_INIT_ZVAL(retval); -#if IS_PHP_53 - zend_fetch_debug_backtrace(retval, 1, 0 TSRMLS_CC); -#else - zend_fetch_debug_backtrace(retval, 1, 0, 0 TSRMLS_CC); -#endif - SYMFONY_DEBUG_G(debug_bt) = retval; - } - - SYMFONY_DEBUG_G(old_error_cb)(type, error_filename, error_lineno, format, args); -} - -static const char* _symfony_debug_get_resource_type(long rsid TSRMLS_DC) -{ - const char *res_type; - res_type = zend_rsrc_list_get_rsrc_type(rsid TSRMLS_CC); - - if (!res_type) { - return "Unknown"; - } - - return res_type; -} - -static int _symfony_debug_get_resource_refcount(long rsid TSRMLS_DC) -{ - zend_rsrc_list_entry *le; - - if (zend_hash_index_find(&EG(regular_list), rsid, (void **) &le)==SUCCESS) { - return le->refcount; - } - - return 0; -} - -static char *_symfony_debug_memory_address_hash(void *address TSRMLS_DC) -{ - char *result = NULL; - intptr_t address_rand; - - if (!SYMFONY_DEBUG_G(req_rand_init)) { - if (!BG(mt_rand_is_seeded)) { - php_mt_srand(GENERATE_SEED() TSRMLS_CC); - } - SYMFONY_DEBUG_G(req_rand_init) = (intptr_t)php_mt_rand(TSRMLS_C); - } - - address_rand = (intptr_t)address ^ SYMFONY_DEBUG_G(req_rand_init); - - spprintf(&result, 17, "%016zx", address_rand); - - return result; -} - -static const char *_symfony_debug_zval_type(zval *zv) -{ - switch (Z_TYPE_P(zv)) { - case IS_NULL: - return "NULL"; - break; - - case IS_BOOL: - return "boolean"; - break; - - case IS_LONG: - return "integer"; - break; - - case IS_DOUBLE: - return "double"; - break; - - case IS_STRING: - return "string"; - break; - - case IS_ARRAY: - return "array"; - break; - - case IS_OBJECT: - return "object"; - - case IS_RESOURCE: - return "resource"; - - default: - return "unknown type"; - } -} - -zend_module_entry symfony_debug_module_entry = { - STANDARD_MODULE_HEADER, - "symfony_debug", - symfony_debug_functions, - PHP_MINIT(symfony_debug), - PHP_MSHUTDOWN(symfony_debug), - PHP_RINIT(symfony_debug), - PHP_RSHUTDOWN(symfony_debug), - PHP_MINFO(symfony_debug), - PHP_SYMFONY_DEBUG_VERSION, - PHP_MODULE_GLOBALS(symfony_debug), - PHP_GINIT(symfony_debug), - PHP_GSHUTDOWN(symfony_debug), - NULL, - STANDARD_MODULE_PROPERTIES_EX -}; - -#ifdef COMPILE_DL_SYMFONY_DEBUG -ZEND_GET_MODULE(symfony_debug) -#endif - -PHP_GINIT_FUNCTION(symfony_debug) -{ - memset(symfony_debug_globals, 0 , sizeof(*symfony_debug_globals)); -} - -PHP_GSHUTDOWN_FUNCTION(symfony_debug) -{ - -} - -PHP_MINIT_FUNCTION(symfony_debug) -{ - SYMFONY_DEBUG_G(old_error_cb) = zend_error_cb; - zend_error_cb = symfony_debug_error_cb; - - return SUCCESS; -} - -PHP_MSHUTDOWN_FUNCTION(symfony_debug) -{ - zend_error_cb = SYMFONY_DEBUG_G(old_error_cb); - - return SUCCESS; -} - -PHP_RINIT_FUNCTION(symfony_debug) -{ - return SUCCESS; -} - -PHP_RSHUTDOWN_FUNCTION(symfony_debug) -{ - return SUCCESS; -} - -PHP_MINFO_FUNCTION(symfony_debug) -{ - php_info_print_table_start(); - php_info_print_table_header(2, "Symfony Debug support", "enabled"); - php_info_print_table_header(2, "Symfony Debug version", PHP_SYMFONY_DEBUG_VERSION); - php_info_print_table_end(); -} diff --git a/vendor/symfony/debug/Resources/ext/tests/001.phpt b/vendor/symfony/debug/Resources/ext/tests/001.phpt deleted file mode 100644 index 4a87cd3180..0000000000 --- a/vendor/symfony/debug/Resources/ext/tests/001.phpt +++ /dev/null @@ -1,155 +0,0 @@ ---TEST-- -Test symfony_zval_info API ---SKIPIF-- -<?php if (!extension_loaded('symfony_debug')) { - echo 'skip'; -} ?> ---FILE-- -<?php - -$int = 42; -$float = 42.42; -$str = 'foobar'; -$object = new StdClass(); -$array = array('foo', 'bar'); -$resource = tmpfile(); -$null = null; -$bool = true; - -$anotherint = 42; -$refcount2 = &$anotherint; - -$var = array( - 'int' => $int, - 'float' => $float, - 'str' => $str, - 'object' => $object, - 'array' => $array, - 'resource' => $resource, - 'null' => $null, - 'bool' => $bool, - 'refcount' => &$refcount2, -); - -var_dump(symfony_zval_info('int', $var)); -var_dump(symfony_zval_info('float', $var)); -var_dump(symfony_zval_info('str', $var)); -var_dump(symfony_zval_info('object', $var)); -var_dump(symfony_zval_info('array', $var)); -var_dump(symfony_zval_info('resource', $var)); -var_dump(symfony_zval_info('null', $var)); -var_dump(symfony_zval_info('bool', $var)); - -var_dump(symfony_zval_info('refcount', $var)); -var_dump(symfony_zval_info('not-exist', $var)); -?> ---EXPECTF-- -array(4) { - ["type"]=> - string(7) "integer" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(4) { - ["type"]=> - string(6) "double" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(5) { - ["type"]=> - string(6) "string" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["strlen"]=> - int(6) -} -array(8) { - ["type"]=> - string(6) "object" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["object_class"]=> - string(8) "stdClass" - ["object_refcount"]=> - int(1) - ["object_hash"]=> - string(32) "%s" - ["object_handle"]=> - int(%d) -} -array(5) { - ["type"]=> - string(5) "array" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["array_count"]=> - int(2) -} -array(7) { - ["type"]=> - string(8) "resource" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) - ["resource_handle"]=> - int(%d) - ["resource_type"]=> - string(6) "stream" - ["resource_refcount"]=> - int(1) -} -array(4) { - ["type"]=> - string(4) "NULL" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(4) { - ["type"]=> - string(7) "boolean" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(2) - ["zval_isref"]=> - bool(false) -} -array(4) { - ["type"]=> - string(7) "integer" - ["zval_hash"]=> - string(16) "%s" - ["zval_refcount"]=> - int(3) - ["zval_isref"]=> - bool(true) -} -NULL diff --git a/vendor/symfony/debug/Resources/ext/tests/002.phpt b/vendor/symfony/debug/Resources/ext/tests/002.phpt deleted file mode 100644 index afc7bb4902..0000000000 --- a/vendor/symfony/debug/Resources/ext/tests/002.phpt +++ /dev/null @@ -1,65 +0,0 @@ ---TEST-- -Test symfony_debug_backtrace in case of fatal error ---SKIPIF-- -<?php if (!extension_loaded('symfony_debug')) { - echo 'skip'; -} ?> ---FILE-- -<?php - -function bar() -{ - foo(); -} - -function foo() -{ - notexist(); -} - -function bt() -{ - print_r(symfony_debug_backtrace()); -} - -register_shutdown_function('bt'); - -bar(); - -?> ---EXPECTF-- -Fatal error: Call to undefined function notexist() in %s on line %d -Array -( - [0] => Array - ( - [function] => bt - [args] => Array - ( - ) - - ) - - [1] => Array - ( - [file] => %s - [line] => %d - [function] => foo - [args] => Array - ( - ) - - ) - - [2] => Array - ( - [file] => %s - [line] => %d - [function] => bar - [args] => Array - ( - ) - - ) - -) diff --git a/vendor/symfony/debug/Resources/ext/tests/002_1.phpt b/vendor/symfony/debug/Resources/ext/tests/002_1.phpt deleted file mode 100644 index 86de3e177d..0000000000 --- a/vendor/symfony/debug/Resources/ext/tests/002_1.phpt +++ /dev/null @@ -1,48 +0,0 @@ ---TEST-- -Test symfony_debug_backtrace in case of non fatal error ---SKIPIF-- -<?php if (!extension_loaded('symfony_debug')) { - echo 'skip'; -} ?> ---FILE-- -<?php - -function bar() -{ - bt(); -} - -function bt() -{ - print_r(symfony_debug_backtrace()); -} - -bar(); - -?> ---EXPECTF-- -Array -( - [0] => Array - ( - [file] => %s - [line] => %d - [function] => bt - [args] => Array - ( - ) - - ) - - [1] => Array - ( - [file] => %s - [line] => %d - [function] => bar - [args] => Array - ( - ) - - ) - -) diff --git a/vendor/symfony/debug/Resources/ext/tests/003.phpt b/vendor/symfony/debug/Resources/ext/tests/003.phpt deleted file mode 100644 index 4e7645031c..0000000000 --- a/vendor/symfony/debug/Resources/ext/tests/003.phpt +++ /dev/null @@ -1,87 +0,0 @@ ---TEST-- -Test ErrorHandler in case of fatal error ---SKIPIF-- -<?php if (!extension_loaded('symfony_debug')) { - echo 'skip'; -} ?> ---FILE-- -<?php - -namespace Psr\Log; - -class LogLevel -{ - const EMERGENCY = 'emergency'; - const ALERT = 'alert'; - const CRITICAL = 'critical'; - const ERROR = 'error'; - const WARNING = 'warning'; - const NOTICE = 'notice'; - const INFO = 'info'; - const DEBUG = 'debug'; -} - -namespace Symfony\Component\Debug; - -$dir = __DIR__.'/../../../'; -require $dir.'ErrorHandler.php'; -require $dir.'Exception/FatalErrorException.php'; -require $dir.'Exception/UndefinedFunctionException.php'; -require $dir.'FatalErrorHandler/FatalErrorHandlerInterface.php'; -require $dir.'FatalErrorHandler/ClassNotFoundFatalErrorHandler.php'; -require $dir.'FatalErrorHandler/UndefinedFunctionFatalErrorHandler.php'; -require $dir.'FatalErrorHandler/UndefinedMethodFatalErrorHandler.php'; - -function bar() -{ - foo(); -} - -function foo() -{ - notexist(); -} - -$handler = ErrorHandler::register(); -$handler->setExceptionHandler('print_r'); - -if (\function_exists('xdebug_disable')) { - xdebug_disable(); -} - -bar(); -?> ---EXPECTF-- -Fatal error: Call to undefined function Symfony\Component\Debug\notexist() in %s on line %d -Symfony\Component\Debug\Exception\UndefinedFunctionException Object -( - [message:protected] => Attempted to call function "notexist" from namespace "Symfony\Component\Debug". - [string:Exception:private] => - [code:protected] => 0 - [file:protected] => %s - [line:protected] => %d - [trace:Exception:private] => Array - ( - [0] => Array - ( -%A [function] => Symfony\Component\Debug\foo -%A [args] => Array - ( - ) - - ) - - [1] => Array - ( -%A [function] => Symfony\Component\Debug\bar -%A [args] => Array - ( - ) - - ) -%A - ) - - [previous:Exception:private] => - [severity:protected] => 1 -) diff --git a/vendor/symfony/debug/Tests/DebugClassLoaderTest.php b/vendor/symfony/debug/Tests/DebugClassLoaderTest.php index e9ce535ee7..c7e03fbef8 100644 --- a/vendor/symfony/debug/Tests/DebugClassLoaderTest.php +++ b/vendor/symfony/debug/Tests/DebugClassLoaderTest.php @@ -13,7 +13,6 @@ namespace Symfony\Component\Debug\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\Debug\DebugClassLoader; -use Symfony\Component\Debug\ErrorHandler; class DebugClassLoaderTest extends TestCase { @@ -76,72 +75,8 @@ class DebugClassLoaderTest extends TestCase class_exists(__NAMESPACE__.'\Fixtures\Throwing'); } - public function testUnsilencing() - { - if (\PHP_VERSION_ID >= 70000) { - $this->markTestSkipped('PHP7 throws exceptions, unsilencing is not required anymore.'); - } - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM is not handled in this test case.'); - } - - ob_start(); - - $this->iniSet('log_errors', 0); - $this->iniSet('display_errors', 1); - - // See below: this will fail with parse error - // but this should not be @-silenced. - @class_exists(__NAMESPACE__.'\TestingUnsilencing', true); - - $output = ob_get_clean(); - - $this->assertStringMatchesFormat('%aParse error%a', $output); - } - - public function testStacking() - { - // the ContextErrorException must not be loaded to test the workaround - // for https://bugs.php.net/65322. - if (class_exists('Symfony\Component\Debug\Exception\ContextErrorException', false)) { - $this->markTestSkipped('The ContextErrorException class is already loaded.'); - } - if (defined('HHVM_VERSION')) { - $this->markTestSkipped('HHVM is not handled in this test case.'); - } - - ErrorHandler::register(); - - try { - // Trigger autoloading + E_STRICT at compile time - // which in turn triggers $errorHandler->handle() - // that again triggers autoloading for ContextErrorException. - // Error stacking works around the bug above and everything is fine. - - eval(' - namespace '.__NAMESPACE__.'; - class ChildTestingStacking extends TestingStacking { function foo($bar) {} } - '); - $this->fail('ContextErrorException expected'); - } catch (\ErrorException $exception) { - // if an exception is thrown, the test passed - $this->assertStringStartsWith(__FILE__, $exception->getFile()); - if (\PHP_VERSION_ID < 70000) { - $this->assertRegExp('/^Runtime Notice: Declaration/', $exception->getMessage()); - $this->assertEquals(E_STRICT, $exception->getSeverity()); - } else { - $this->assertRegExp('/^Warning: Declaration/', $exception->getMessage()); - $this->assertEquals(E_WARNING, $exception->getSeverity()); - } - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - /** * @expectedException \RuntimeException - * @expectedExceptionMessage Case mismatch between loaded and declared class names */ public function testNameCaseMismatch() { @@ -163,7 +98,6 @@ class DebugClassLoaderTest extends TestCase /** * @expectedException \RuntimeException - * @expectedExceptionMessage Case mismatch between loaded and declared class names */ public function testPsr4CaseMismatch() { @@ -262,32 +196,6 @@ class DebugClassLoaderTest extends TestCase $this->assertSame($xError, $lastError); } - public function testReservedForPhp7() - { - if (\PHP_VERSION_ID >= 70000) { - $this->markTestSkipped('PHP7 already prevents using reserved names.'); - } - - set_error_handler(function () { return false; }); - $e = error_reporting(0); - trigger_error('', E_USER_NOTICE); - - class_exists('Test\\'.__NAMESPACE__.'\\Float', true); - - error_reporting($e); - restore_error_handler(); - - $lastError = error_get_last(); - unset($lastError['file'], $lastError['line']); - - $xError = array( - 'type' => E_USER_DEPRECATED, - 'message' => 'The "Test\Symfony\Component\Debug\Tests\Float" class uses the reserved name "Float", it will break on PHP 7 and higher', - ); - - $this->assertSame($xError, $lastError); - } - public function testExtendedFinalClass() { set_error_handler(function () { return false; }); @@ -304,7 +212,7 @@ class DebugClassLoaderTest extends TestCase $xError = array( 'type' => E_USER_DEPRECATED, - 'message' => 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass" class is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass".', + 'message' => 'The "Symfony\Component\Debug\Tests\Fixtures\FinalClass" class is considered final. It may change without further notice as of its next major version. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsFinalClass".', ); $this->assertSame($xError, $lastError); @@ -322,7 +230,7 @@ class DebugClassLoaderTest extends TestCase restore_error_handler(); $xError = array( - 'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".', + 'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".', 'The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod".', ); @@ -359,12 +267,30 @@ class DebugClassLoaderTest extends TestCase $this->assertSame($deprecations, array( 'The "Symfony\Component\Debug\Tests\Fixtures\InternalInterface" interface is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".', - 'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass" class is considered internal since version 3.4. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".', + 'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass" class is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternalsParent".', 'The "Symfony\Component\Debug\Tests\Fixtures\InternalTrait" trait is considered internal. It may change without further notice. You should not use it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".', - 'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass::internalMethod()" method is considered internal since version 3.4. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".', + 'The "Symfony\Component\Debug\Tests\Fixtures\InternalClass::internalMethod()" method is considered internal. It may change without further notice. You should not extend it from "Test\Symfony\Component\Debug\Tests\ExtendsInternals".', )); } + public function testExtendedMethodDefinesNewParameters() + { + $deprecations = array(); + set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); + $e = error_reporting(E_USER_DEPRECATED); + + class_exists(__NAMESPACE__.'\\Fixtures\SubClassWithAnnotatedParameters', true); + + error_reporting($e); + restore_error_handler(); + + $this->assertSame(array( + '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::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); + } + public function testUseTraitWithInternalMethod() { $deprecations = array(); diff --git a/vendor/symfony/debug/Tests/ErrorHandlerTest.php b/vendor/symfony/debug/Tests/ErrorHandlerTest.php index a8d40e849b..15e476381a 100644 --- a/vendor/symfony/debug/Tests/ErrorHandlerTest.php +++ b/vendor/symfony/debug/Tests/ErrorHandlerTest.php @@ -323,9 +323,6 @@ class ErrorHandlerTest extends TestCase @$handler->handleError(E_USER_DEPRECATED, 'Foo deprecation', __FILE__, __LINE__, array()); } - /** - * @group no-hhvm - */ public function testHandleException() { try { @@ -367,38 +364,6 @@ class ErrorHandlerTest extends TestCase } } - /** - * @group legacy - */ - public function testErrorStacking() - { - try { - $handler = ErrorHandler::register(); - $handler->screamAt(E_USER_WARNING); - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - - $logger - ->expects($this->exactly(2)) - ->method('log') - ->withConsecutive( - array($this->equalTo(LogLevel::WARNING), $this->equalTo('Dummy log')), - array($this->equalTo(LogLevel::DEBUG), $this->equalTo('User Warning: Silenced warning')) - ) - ; - - $handler->setDefaultLogger($logger, array(E_USER_WARNING => LogLevel::WARNING)); - - ErrorHandler::stackErrors(); - @trigger_error('Silenced warning', E_USER_WARNING); - $logger->log(LogLevel::WARNING, 'Dummy log'); - ErrorHandler::unstackErrors(); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - public function testBootstrappingLogger() { $bootLogger = new BufferingLogger(); @@ -450,9 +415,6 @@ class ErrorHandlerTest extends TestCase $handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING))); } - /** - * @group no-hhvm - */ public function testSettingLoggerWhenExceptionIsBuffered() { $bootLogger = new BufferingLogger(); @@ -472,9 +434,6 @@ class ErrorHandlerTest extends TestCase $handler->handleException($exception); } - /** - * @group no-hhvm - */ public function testHandleFatalError() { try { @@ -515,9 +474,6 @@ class ErrorHandlerTest extends TestCase } } - /** - * @requires PHP 7 - */ public function testHandleErrorException() { $exception = new \Error("Class 'Foo' not found"); @@ -534,45 +490,7 @@ class ErrorHandlerTest extends TestCase } /** - * @group no-hhvm - */ - public function testHandleFatalErrorOnHHVM() - { - try { - $handler = ErrorHandler::register(); - - $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); - $logger - ->expects($this->once()) - ->method('log') - ->with( - $this->equalTo(LogLevel::CRITICAL), - $this->equalTo('Fatal Error: foo') - ) - ; - - $handler->setDefaultLogger($logger, E_ERROR); - - $error = array( - 'type' => E_ERROR + 0x1000000, // This error level is used by HHVM for fatal errors - 'message' => 'foo', - 'file' => 'bar', - 'line' => 123, - 'context' => array(123), - 'backtrace' => array(456), - ); - - \call_user_func_array(array($handler, 'handleError'), $error); - $handler->handleFatalError($error); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } - - /** * @expectedException \Exception - * @group no-hhvm */ public function testCustomExceptionHandler() { diff --git a/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php b/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php index ce9f355530..5b77b999a7 100644 --- a/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php +++ b/vendor/symfony/debug/Tests/Exception/FlattenExceptionTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Debug\Tests\Exception; use PHPUnit\Framework\TestCase; +use Symfony\Component\Debug\Exception\FatalThrowableError; use Symfony\Component\Debug\Exception\FlattenException; use Symfony\Component\HttpFoundation\Exception\SuspiciousOperationException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -39,6 +40,12 @@ class FlattenExceptionTest extends TestCase $flattened = FlattenException::create(new \RuntimeException()); $this->assertEquals('500', $flattened->getStatusCode()); + $flattened = FlattenException::createFromThrowable(new \DivisionByZeroError(), 403); + $this->assertEquals('403', $flattened->getStatusCode()); + + $flattened = FlattenException::createFromThrowable(new \DivisionByZeroError()); + $this->assertEquals('500', $flattened->getStatusCode()); + $flattened = FlattenException::create(new NotFoundHttpException()); $this->assertEquals('404', $flattened->getStatusCode()); @@ -111,10 +118,10 @@ class FlattenExceptionTest extends TestCase /** * @dataProvider flattenDataProvider */ - public function testFlattenHttpException(\Exception $exception) + public function testFlattenHttpException(\Throwable $exception) { - $flattened = FlattenException::create($exception); - $flattened2 = FlattenException::create($exception); + $flattened = FlattenException::createFromThrowable($exception); + $flattened2 = FlattenException::createFromThrowable($exception); $flattened->setPrevious($flattened2); @@ -123,13 +130,33 @@ class FlattenExceptionTest extends TestCase $this->assertInstanceOf($flattened->getClass(), $exception, 'The class is set to the class of the original exception'); } + public function testWrappedThrowable() + { + $exception = new FatalThrowableError(new \DivisionByZeroError('Ouch', 42)); + $flattened = FlattenException::create($exception); + + $this->assertSame('Ouch', $flattened->getMessage(), 'The message is copied from the original error.'); + $this->assertSame(42, $flattened->getCode(), 'The code is copied from the original error.'); + $this->assertSame('DivisionByZeroError', $flattened->getClass(), 'The class is set to the class of the original error'); + } + + public function testThrowable() + { + $error = new \DivisionByZeroError('Ouch', 42); + $flattened = FlattenException::createFromThrowable($error); + + $this->assertSame('Ouch', $flattened->getMessage(), 'The message is copied from the original error.'); + $this->assertSame(42, $flattened->getCode(), 'The code is copied from the original error.'); + $this->assertSame('DivisionByZeroError', $flattened->getClass(), 'The class is set to the class of the original error'); + } + /** * @dataProvider flattenDataProvider */ - public function testPrevious(\Exception $exception) + public function testPrevious(\Throwable $exception) { - $flattened = FlattenException::create($exception); - $flattened2 = FlattenException::create($exception); + $flattened = FlattenException::createFromThrowable($exception); + $flattened2 = FlattenException::createFromThrowable($exception); $flattened->setPrevious($flattened2); @@ -138,50 +165,47 @@ class FlattenExceptionTest extends TestCase $this->assertSame(array($flattened2), $flattened->getAllPrevious()); } - /** - * @requires PHP 7.0 - */ public function testPreviousError() { $exception = new \Exception('test', 123, new \ParseError('Oh noes!', 42)); $flattened = FlattenException::create($exception)->getPrevious(); - $this->assertEquals($flattened->getMessage(), 'Parse error: Oh noes!', 'The message is copied from the original exception.'); + $this->assertEquals($flattened->getMessage(), 'Oh noes!', 'The message is copied from the original exception.'); $this->assertEquals($flattened->getCode(), 42, 'The code is copied from the original exception.'); - $this->assertEquals($flattened->getClass(), 'Symfony\Component\Debug\Exception\FatalThrowableError', 'The class is set to the class of the original exception'); + $this->assertEquals($flattened->getClass(), 'ParseError', 'The class is set to the class of the original exception'); } /** * @dataProvider flattenDataProvider */ - public function testLine(\Exception $exception) + public function testLine(\Throwable $exception) { - $flattened = FlattenException::create($exception); + $flattened = FlattenException::createFromThrowable($exception); $this->assertSame($exception->getLine(), $flattened->getLine()); } /** * @dataProvider flattenDataProvider */ - public function testFile(\Exception $exception) + public function testFile(\Throwable $exception) { - $flattened = FlattenException::create($exception); + $flattened = FlattenException::createFromThrowable($exception); $this->assertSame($exception->getFile(), $flattened->getFile()); } /** * @dataProvider flattenDataProvider */ - public function testToArray(\Exception $exception) + public function testToArray(\Throwable $exception, string $expectedClass) { - $flattened = FlattenException::create($exception); + $flattened = FlattenException::createFromThrowable($exception); $flattened->setTrace(array(), 'foo.php', 123); $this->assertEquals(array( array( 'message' => 'test', - 'class' => 'Exception', + 'class' => $expectedClass, 'trace' => array(array( 'namespace' => '', 'short_class' => '', 'class' => '', 'type' => '', 'function' => '', 'file' => 'foo.php', 'line' => 123, 'args' => array(), @@ -190,10 +214,24 @@ class FlattenExceptionTest extends TestCase ), $flattened->toArray()); } + public function testCreate() + { + $exception = new NotFoundHttpException( + 'test', + new \RuntimeException('previous', 123) + ); + + $this->assertSame( + FlattenException::createFromThrowable($exception)->toArray(), + FlattenException::create($exception)->toArray() + ); + } + public function flattenDataProvider() { return array( - array(new \Exception('test', 123)), + array(new \Exception('test', 123), 'Exception'), + array(new \Error('test', 123), 'Error'), ); } @@ -236,7 +274,7 @@ class FlattenExceptionTest extends TestCase $this->assertSame(array('object', 'stdClass'), $array[$i++]); $this->assertSame(array('object', 'Symfony\Component\HttpKernel\Exception\NotFoundHttpException'), $array[$i++]); $this->assertSame(array('incomplete-object', 'BogusTestClass'), $array[$i++]); - $this->assertSame(array('resource', \defined('HHVM_VERSION') ? 'Directory' : 'stream'), $array[$i++]); + $this->assertSame(array('resource', 'stream'), $array[$i++]); $this->assertSame(array('resource', 'stream'), $array[$i++]); $args = $array[$i++]; @@ -295,6 +333,19 @@ class FlattenExceptionTest extends TestCase $this->assertNotContains('*value1*', $serializeTrace); } + public function testAnonymousClass() + { + $flattened = FlattenException::create(new class() extends \RuntimeException { + }); + + $this->assertSame('RuntimeException@anonymous', $flattened->getClass()); + + $flattened = FlattenException::create(new \Exception(sprintf('Class "%s" blah.', \get_class(new class() extends \RuntimeException { + })))); + + $this->assertSame('Class "RuntimeException@anonymous" blah.', $flattened->getMessage()); + } + private function createException($foo) { return new \Exception(); diff --git a/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php b/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php index 1dc2120045..60153fc5ec 100644 --- a/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php +++ b/vendor/symfony/debug/Tests/FatalErrorHandler/UndefinedFunctionFatalErrorHandlerTest.php @@ -26,7 +26,7 @@ class UndefinedFunctionFatalErrorHandlerTest extends TestCase $exception = $handler->handleError($error, new FatalErrorException('', 0, $error['type'], $error['file'], $error['line'])); $this->assertInstanceOf('Symfony\Component\Debug\Exception\UndefinedFunctionException', $exception); - // class names are case insensitive and PHP/HHVM do not return the same + // class names are case insensitive and PHP do not return the same $this->assertSame(strtolower($translatedMessage), strtolower($exception->getMessage())); $this->assertSame($error['type'], $exception->getSeverity()); $this->assertSame($error['file'], $exception->getFile()); diff --git a/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php b/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php index dff9517d0a..4eecb6d3f1 100644 --- a/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php +++ b/vendor/symfony/debug/Tests/Fixtures/AnnotatedClass.php @@ -5,7 +5,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures; class AnnotatedClass { /** - * @deprecated since version 3.4. + * @deprecated */ public function deprecatedMethod() { diff --git a/vendor/symfony/debug/Tests/Fixtures/ClassWithAnnotatedParameters.php b/vendor/symfony/debug/Tests/Fixtures/ClassWithAnnotatedParameters.php new file mode 100644 index 0000000000..d6eec9aa69 --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/ClassWithAnnotatedParameters.php @@ -0,0 +1,34 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +class ClassWithAnnotatedParameters +{ + /** + * @param string $foo this is a foo parameter + */ + public function fooMethod(string $foo) + { + } + + /** + * @param string $bar parameter not implemented yet + */ + public function barMethod(/* string $bar = null */) + { + } + + /** + * @param Quz $quz parameter not implemented yet + */ + public function quzMethod(/* Quz $quz = null */) + { + } + + /** + * @param true $yes + */ + public function isSymfony() + { + } +} diff --git a/vendor/symfony/debug/Tests/Fixtures/FinalClass.php b/vendor/symfony/debug/Tests/Fixtures/FinalClass.php index 2cf26b19e4..f4c69b8532 100644 --- a/vendor/symfony/debug/Tests/Fixtures/FinalClass.php +++ b/vendor/symfony/debug/Tests/Fixtures/FinalClass.php @@ -3,7 +3,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures; /** - * @final since version 3.3. + * @final */ class FinalClass { diff --git a/vendor/symfony/debug/Tests/Fixtures/FinalMethod.php b/vendor/symfony/debug/Tests/Fixtures/FinalMethod.php index 98a47524c4..03e47e8a7a 100644 --- a/vendor/symfony/debug/Tests/Fixtures/FinalMethod.php +++ b/vendor/symfony/debug/Tests/Fixtures/FinalMethod.php @@ -5,7 +5,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures; class FinalMethod { /** - * @final since version 3.3. + * @final */ public function finalMethod() { diff --git a/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php b/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php new file mode 100644 index 0000000000..54abd68efa --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/InterfaceWithAnnotatedParameters.php @@ -0,0 +1,14 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +/** + * Ensures a deprecation is triggered when a new parameter is not declared in child classes. + */ +interface InterfaceWithAnnotatedParameters +{ + /** + * @param bool $matrix + */ + public function whereAmI(); +} diff --git a/vendor/symfony/debug/Tests/Fixtures/InternalClass.php b/vendor/symfony/debug/Tests/Fixtures/InternalClass.php index 119842c260..30efe79b33 100644 --- a/vendor/symfony/debug/Tests/Fixtures/InternalClass.php +++ b/vendor/symfony/debug/Tests/Fixtures/InternalClass.php @@ -3,7 +3,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures; /** - * @internal since version 3.4. + * @internal */ class InternalClass { diff --git a/vendor/symfony/debug/Tests/Fixtures/InternalTrait2.php b/vendor/symfony/debug/Tests/Fixtures/InternalTrait2.php index 05f18e83e4..e4cbe12aec 100644 --- a/vendor/symfony/debug/Tests/Fixtures/InternalTrait2.php +++ b/vendor/symfony/debug/Tests/Fixtures/InternalTrait2.php @@ -8,7 +8,7 @@ namespace Symfony\Component\Debug\Tests\Fixtures; trait InternalTrait2 { /** - * @internal since version 3.4 + * @internal */ public function internalMethod() { diff --git a/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php b/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php new file mode 100644 index 0000000000..20358e96de --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/SubClassWithAnnotatedParameters.php @@ -0,0 +1,24 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +class SubClassWithAnnotatedParameters extends ClassWithAnnotatedParameters implements InterfaceWithAnnotatedParameters +{ + use TraitWithAnnotatedParameters; + + public function fooMethod(string $foo) + { + } + + public function barMethod($bar = null) + { + } + + public function quzMethod() + { + } + + public function whereAmI() + { + } +} diff --git a/vendor/symfony/debug/Tests/Fixtures/TraitWithAnnotatedParameters.php b/vendor/symfony/debug/Tests/Fixtures/TraitWithAnnotatedParameters.php new file mode 100644 index 0000000000..5eb5fbf84b --- /dev/null +++ b/vendor/symfony/debug/Tests/Fixtures/TraitWithAnnotatedParameters.php @@ -0,0 +1,13 @@ +<?php + +namespace Symfony\Component\Debug\Tests\Fixtures; + +trait TraitWithAnnotatedParameters +{ + /** + * `@param` annotations in traits are not parsed. + */ + public function isSymfony() + { + } +} diff --git a/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt b/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt index 26b3abf4d7..53839c4899 100644 --- a/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt +++ b/vendor/symfony/debug/Tests/phpt/debug_class_loader.phpt @@ -23,5 +23,5 @@ class_exists(ExtendedFinalMethod::class); ?> --EXPECTF-- -The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final since version 3.3. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod". +The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod". The "Symfony\Component\Debug\Tests\Fixtures\FinalMethod::finalMethod2()" method is considered final. It may change without further notice as of its next major version. You should not extend it from "Symfony\Component\Debug\Tests\Fixtures\ExtendedFinalMethod". diff --git a/vendor/symfony/debug/composer.json b/vendor/symfony/debug/composer.json index f98a5d07b5..45799e2e60 100644 --- a/vendor/symfony/debug/composer.json +++ b/vendor/symfony/debug/composer.json @@ -16,14 +16,14 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", + "php": "^7.1.3", "psr/log": "~1.0" }, "conflict": { - "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + "symfony/http-kernel": "<3.4" }, "require-dev": { - "symfony/http-kernel": "~2.8|~3.0|~4.0" + "symfony/http-kernel": "~3.4|~4.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Debug\\": "" }, @@ -34,7 +34,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } } } diff --git a/vendor/symfony/debug/phpunit.xml.dist b/vendor/symfony/debug/phpunit.xml.dist index 12e58612bc..a51bbff935 100644 --- a/vendor/symfony/debug/phpunit.xml.dist +++ b/vendor/symfony/debug/phpunit.xml.dist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" diff --git a/vendor/symfony/event-dispatcher/CHANGELOG.md b/vendor/symfony/event-dispatcher/CHANGELOG.md index c6aa5389ac..b581d31433 100644 --- a/vendor/symfony/event-dispatcher/CHANGELOG.md +++ b/vendor/symfony/event-dispatcher/CHANGELOG.md @@ -1,6 +1,19 @@ CHANGELOG ========= +4.1.0 +----- + + * added support for invokable event listeners tagged with `kernel.event_listener` by default + * The `TraceableEventDispatcher::getOrphanedEvents()` method has been added. + * The `TraceableEventDispatcherInterface` has been deprecated. + +4.0.0 +----- + + * removed the `ContainerAwareEventDispatcher` class + * added the `reset()` method to the `TraceableEventDispatcherInterface` + 3.4.0 ----- diff --git a/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php b/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php deleted file mode 100644 index cd44a31c1d..0000000000 --- a/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php +++ /dev/null @@ -1,197 +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; - -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Lazily loads listeners and subscribers from the dependency injection - * container. - * - * @author Fabien Potencier <fabien@symfony.com> - * @author Bernhard Schussek <bschussek@gmail.com> - * @author Jordan Alliot <jordan.alliot@gmail.com> - * - * @deprecated since 3.3, to be removed in 4.0. Use EventDispatcher with closure factories instead. - */ -class ContainerAwareEventDispatcher extends EventDispatcher -{ - private $container; - - /** - * The service IDs of the event listeners and subscribers. - */ - private $listenerIds = array(); - - /** - * The services registered as listeners. - */ - private $listeners = array(); - - public function __construct(ContainerInterface $container) - { - $this->container = $container; - - $class = \get_class($this); - if ($this instanceof \PHPUnit_Framework_MockObject_MockObject || $this instanceof \Prophecy\Doubler\DoubleInterface) { - $class = get_parent_class($class); - } - if (__CLASS__ !== $class) { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED); - } - } - - /** - * Adds a service as event listener. - * - * @param string $eventName Event for which the listener is added - * @param array $callback The service ID of the listener service & the method - * name that has to be called - * @param int $priority The higher this value, the earlier an event listener - * will be triggered in the chain. - * Defaults to 0. - * - * @throws \InvalidArgumentException - */ - public function addListenerService($eventName, $callback, $priority = 0) - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED); - - if (!\is_array($callback) || 2 !== \count($callback)) { - throw new \InvalidArgumentException('Expected an array("service", "method") argument'); - } - - $this->listenerIds[$eventName][] = array($callback[0], $callback[1], $priority); - } - - public function removeListener($eventName, $listener) - { - $this->lazyLoad($eventName); - - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as $i => list($serviceId, $method)) { - $key = $serviceId.'.'.$method; - if (isset($this->listeners[$eventName][$key]) && $listener === array($this->listeners[$eventName][$key], $method)) { - unset($this->listeners[$eventName][$key]); - if (empty($this->listeners[$eventName])) { - unset($this->listeners[$eventName]); - } - unset($this->listenerIds[$eventName][$i]); - if (empty($this->listenerIds[$eventName])) { - unset($this->listenerIds[$eventName]); - } - } - } - } - - parent::removeListener($eventName, $listener); - } - - /** - * {@inheritdoc} - */ - public function hasListeners($eventName = null) - { - if (null === $eventName) { - return $this->listenerIds || $this->listeners || parent::hasListeners(); - } - - if (isset($this->listenerIds[$eventName])) { - return true; - } - - return parent::hasListeners($eventName); - } - - /** - * {@inheritdoc} - */ - public function getListeners($eventName = null) - { - if (null === $eventName) { - foreach ($this->listenerIds as $serviceEventName => $args) { - $this->lazyLoad($serviceEventName); - } - } else { - $this->lazyLoad($eventName); - } - - return parent::getListeners($eventName); - } - - /** - * {@inheritdoc} - */ - public function getListenerPriority($eventName, $listener) - { - $this->lazyLoad($eventName); - - return parent::getListenerPriority($eventName, $listener); - } - - /** - * Adds a service as event subscriber. - * - * @param string $serviceId The service ID of the subscriber service - * @param string $class The service's class name (which must implement EventSubscriberInterface) - */ - public function addSubscriberService($serviceId, $class) - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.', __CLASS__), E_USER_DEPRECATED); - - foreach ($class::getSubscribedEvents() as $eventName => $params) { - if (\is_string($params)) { - $this->listenerIds[$eventName][] = array($serviceId, $params, 0); - } elseif (\is_string($params[0])) { - $this->listenerIds[$eventName][] = array($serviceId, $params[0], isset($params[1]) ? $params[1] : 0); - } else { - foreach ($params as $listener) { - $this->listenerIds[$eventName][] = array($serviceId, $listener[0], isset($listener[1]) ? $listener[1] : 0); - } - } - } - } - - public function getContainer() - { - @trigger_error('The '.__METHOD__.'() method is deprecated since Symfony 3.3 as its class will be removed in 4.0. Inject the container or the services you need in your listeners/subscribers instead.', E_USER_DEPRECATED); - - return $this->container; - } - - /** - * Lazily loads listeners for this event from the dependency injection - * container. - * - * @param string $eventName The name of the event to dispatch. The name of - * the event is the name of the method that is - * invoked on listeners. - */ - protected function lazyLoad($eventName) - { - if (isset($this->listenerIds[$eventName])) { - foreach ($this->listenerIds[$eventName] as list($serviceId, $method, $priority)) { - $listener = $this->container->get($serviceId); - - $key = $serviceId.'.'.$method; - if (!isset($this->listeners[$eventName][$key])) { - $this->addListener($eventName, array($listener, $method), $priority); - } elseif ($this->listeners[$eventName][$key] !== $listener) { - parent::removeListener($eventName, array($this->listeners[$eventName][$key], $method)); - $this->addListener($eventName, array($listener, $method), $priority); - } - - $this->listeners[$eventName][$key] = $listener; - } - } - } -} diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php index e5d59402cf..083bd39e96 100644 --- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php @@ -32,6 +32,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface private $called; private $dispatcher; private $wrappedListeners; + private $orphanedEvents; public function __construct(EventDispatcherInterface $dispatcher, Stopwatch $stopwatch, LoggerInterface $logger = null) { @@ -40,6 +41,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface $this->logger = $logger; $this->called = array(); $this->wrappedListeners = array(); + $this->orphanedEvents = array(); } /** @@ -207,9 +209,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface return $notCalled; } + public function getOrphanedEvents(): array + { + return $this->orphanedEvents; + } + public function reset() { $this->called = array(); + $this->orphanedEvents = array(); } /** @@ -222,7 +230,7 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface */ public function __call($method, $arguments) { - return \call_user_func_array(array($this->dispatcher, $method), $arguments); + return $this->dispatcher->{$method}(...$arguments); } /** @@ -247,9 +255,15 @@ class TraceableEventDispatcher implements TraceableEventDispatcherInterface private function preProcess($eventName) { + if (!$this->dispatcher->hasListeners($eventName)) { + $this->orphanedEvents[] = $eventName; + + return; + } + foreach ($this->dispatcher->getListeners($eventName) as $listener) { $priority = $this->getListenerPriority($eventName, $listener); - $wrappedListener = new WrappedListener($listener, null, $this->stopwatch, $this); + $wrappedListener = new WrappedListener($listener instanceof WrappedListener ? $listener->getWrappedListener() : $listener, null, $this->stopwatch, $this); $this->wrappedListeners[$eventName][] = $wrappedListener; $this->dispatcher->removeListener($eventName, $listener); $this->dispatcher->addListener($eventName, $wrappedListener, $priority); diff --git a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php index f0212753be..cd4d7470af 100644 --- a/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php +++ b/vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcherInterface.php @@ -12,13 +12,14 @@ namespace Symfony\Component\EventDispatcher\Debug; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\Service\ResetInterface; /** - * @author Fabien Potencier <fabien@symfony.com> + * @deprecated since Symfony 4.1 * - * @method reset() Resets the trace. + * @author Fabien Potencier <fabien@symfony.com> */ -interface TraceableEventDispatcherInterface extends EventDispatcherInterface +interface TraceableEventDispatcherInterface extends EventDispatcherInterface, ResetInterface { /** * Gets the called listeners. diff --git a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php index 2d8126a65d..d49f69de72 100644 --- a/vendor/symfony/event-dispatcher/Debug/WrappedListener.php +++ b/vendor/symfony/event-dispatcher/Debug/WrappedListener.php @@ -34,7 +34,6 @@ class WrappedListener public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) { $this->listener = $listener; - $this->name = $name; $this->stopwatch = $stopwatch; $this->dispatcher = $dispatcher; $this->called = false; @@ -44,7 +43,15 @@ class WrappedListener $this->name = \is_object($listener[0]) ? \get_class($listener[0]) : $listener[0]; $this->pretty = $this->name.'::'.$listener[1]; } elseif ($listener instanceof \Closure) { - $this->pretty = $this->name = 'closure'; + $r = new \ReflectionFunction($listener); + if (false !== strpos($r->name, '{closure}')) { + $this->pretty = $this->name = 'closure'; + } elseif ($class = $r->getClosureScopeClass()) { + $this->name = $class->name; + $this->pretty = $this->name.'::'.$r->name; + } else { + $this->pretty = $this->name = $r->name; + } } elseif (\is_string($listener)) { $this->pretty = $this->name = $listener; } else { diff --git a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php index a6fcde33ad..4c8db4c695 100644 --- a/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php +++ b/vendor/symfony/event-dispatcher/DependencyInjection/RegisterListenersPass.php @@ -31,12 +31,7 @@ class RegisterListenersPass implements CompilerPassInterface private $hotPathEvents = array(); private $hotPathTagName; - /** - * @param string $dispatcherService Service name of the event dispatcher in processed container - * @param string $listenerTag Tag name used for listener - * @param string $subscriberTag Tag name used for subscribers - */ - public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber') + public function __construct(string $dispatcherService = 'event_dispatcher', string $listenerTag = 'kernel.event_listener', string $subscriberTag = 'kernel.event_subscriber') { $this->dispatcherService = $dispatcherService; $this->listenerTag = $listenerTag; @@ -73,6 +68,10 @@ class RegisterListenersPass implements CompilerPassInterface '/[^a-z0-9]/i', ), function ($matches) { return strtoupper($matches[0]); }, $event['event']); $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']); + + if (null !== ($class = $container->getDefinition($id)->getClass()) && ($r = $container->getReflectionClass($class, false)) && !$r->hasMethod($event['method']) && $r->hasMethod('__invoke')) { + $event['method'] = '__invoke'; + } } $definition->addMethodCall('addListener', array($event['event'], array(new ServiceClosureArgument(new Reference($id)), $event['method']), $priority)); diff --git a/vendor/symfony/event-dispatcher/GenericEvent.php b/vendor/symfony/event-dispatcher/GenericEvent.php index 95c99408de..f0be7e18ff 100644 --- a/vendor/symfony/event-dispatcher/GenericEvent.php +++ b/vendor/symfony/event-dispatcher/GenericEvent.php @@ -38,7 +38,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate /** * Getter for subject property. * - * @return mixed $subject The observer subject + * @return mixed The observer subject */ public function getSubject() { diff --git a/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php index 9997a7b0ec..6d377d11fe 100644 --- a/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php +++ b/vendor/symfony/event-dispatcher/Tests/AbstractEventDispatcherTest.php @@ -426,7 +426,7 @@ class TestEventSubscriberWithPriorities implements EventSubscriberInterface return array( 'pre.foo' => array('preFoo', 10), 'post.foo' => array('postFoo'), - ); + ); } } diff --git a/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php deleted file mode 100644 index 9d5eecc547..0000000000 --- a/vendor/symfony/event-dispatcher/Tests/ContainerAwareEventDispatcherTest.php +++ /dev/null @@ -1,210 +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 Symfony\Component\DependencyInjection\Container; -use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher; -use Symfony\Component\EventDispatcher\Event; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; - -/** - * @group legacy - */ -class ContainerAwareEventDispatcherTest extends AbstractEventDispatcherTest -{ - protected function createEventDispatcher() - { - $container = new Container(); - - return new ContainerAwareEventDispatcher($container); - } - - public function testAddAListenerService() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $dispatcher->dispatch('onEvent', $event); - } - - public function testAddASubscriberService() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\SubscriberService')->getMock(); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $service - ->expects($this->once()) - ->method('onEventWithPriority') - ->with($event) - ; - - $service - ->expects($this->once()) - ->method('onEventNested') - ->with($event) - ; - - $container = new Container(); - $container->set('service.subscriber', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addSubscriberService('service.subscriber', 'Symfony\Component\EventDispatcher\Tests\SubscriberService'); - - $dispatcher->dispatch('onEvent', $event); - $dispatcher->dispatch('onEventWithPriority', $event); - $dispatcher->dispatch('onEventNested', $event); - } - - public function testPreventDuplicateListenerService() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 5); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent'), 10); - - $dispatcher->dispatch('onEvent', $event); - } - - public function testHasListenersOnLazyLoad() - { - $event = new Event(); - - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $service - ->expects($this->once()) - ->method('onEvent') - ->with($event) - ; - - $this->assertTrue($dispatcher->hasListeners()); - - if ($dispatcher->hasListeners('onEvent')) { - $dispatcher->dispatch('onEvent'); - } - } - - public function testGetListenersOnLazyLoad() - { - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $listeners = $dispatcher->getListeners(); - - $this->assertArrayHasKey('onEvent', $listeners); - - $this->assertCount(1, $dispatcher->getListeners('onEvent')); - } - - public function testRemoveAfterDispatch() - { - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $dispatcher->dispatch('onEvent', new Event()); - $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); - $this->assertFalse($dispatcher->hasListeners('onEvent')); - } - - public function testRemoveBeforeDispatch() - { - $service = $this->getMockBuilder('Symfony\Component\EventDispatcher\Tests\Service')->getMock(); - - $container = new Container(); - $container->set('service.listener', $service); - - $dispatcher = new ContainerAwareEventDispatcher($container); - $dispatcher->addListenerService('onEvent', array('service.listener', 'onEvent')); - - $dispatcher->removeListener('onEvent', array($container->get('service.listener'), 'onEvent')); - $this->assertFalse($dispatcher->hasListeners('onEvent')); - } -} - -class Service -{ - public function onEvent(Event $e) - { - } -} - -class SubscriberService implements EventSubscriberInterface -{ - public static function getSubscribedEvents() - { - return array( - 'onEvent' => 'onEvent', - 'onEventWithPriority' => array('onEventWithPriority', 10), - 'onEventNested' => array(array('onEventNested')), - ); - } - - public function onEvent(Event $e) - { - } - - public function onEventWithPriority(Event $e) - { - } - - public function onEventNested(Event $e) - { - } -} diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php index d7c5ce18cc..b5c53528a7 100644 --- a/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/vendor/symfony/event-dispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -153,6 +153,31 @@ class TraceableEventDispatcherTest extends TestCase $this->assertCount(2, $dispatcher->getCalledListeners()); } + public function testItReturnsNoOrphanedEventsWhenCreated() + { + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $events = $tdispatcher->getOrphanedEvents(); + $this->assertEmpty($events); + } + + public function testItReturnsOrphanedEventsAfterDispatch() + { + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $tdispatcher->dispatch('foo'); + $events = $tdispatcher->getOrphanedEvents(); + $this->assertCount(1, $events); + $this->assertEquals(array('foo'), $events); + } + + public function testItDoesNotReturnHandledEvents() + { + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $tdispatcher->addListener('foo', function () {}); + $tdispatcher->dispatch('foo'); + $events = $tdispatcher->getOrphanedEvents(); + $this->assertEmpty($events); + } + public function testLogger() { $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); @@ -246,6 +271,17 @@ class TraceableEventDispatcherTest extends TestCase $this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed'); } + + public function testClearOrphanedEvents() + { + $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch()); + $tdispatcher->dispatch('foo'); + $events = $tdispatcher->getOrphanedEvents(); + $this->assertCount(1, $events); + $tdispatcher->reset(); + $events = $tdispatcher->getOrphanedEvents(); + $this->assertCount(0, $events); + } } class EventSubscriber implements EventSubscriberInterface diff --git a/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php b/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.php new file mode 100644 index 0000000000..f743f148d2 --- /dev/null +++ b/vendor/symfony/event-dispatcher/Tests/Debug/WrappedListenerTest.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\EventDispatcher\Tests\Debug; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\Debug\WrappedListener; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\Stopwatch\Stopwatch; + +class WrappedListenerTest extends TestCase +{ + /** + * @dataProvider provideListenersToDescribe + */ + public function testListenerDescription(callable $listener, $expected) + { + $wrappedListener = new WrappedListener($listener, null, $this->getMockBuilder(Stopwatch::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock()); + + $this->assertStringMatchesFormat($expected, $wrappedListener->getPretty()); + } + + public function provideListenersToDescribe() + { + $listeners = array( + array(new FooListener(), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::__invoke'), + array(array(new FooListener(), 'listen'), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen'), + array(array('Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'listenStatic'), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listenStatic'), + array('var_dump', 'var_dump'), + array(function () {}, 'closure'), + ); + + if (\PHP_VERSION_ID >= 70100) { + $listeners[] = array(\Closure::fromCallable(array(new FooListener(), 'listen')), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listen'); + $listeners[] = array(\Closure::fromCallable(array('Symfony\Component\EventDispatcher\Tests\Debug\FooListener', 'listenStatic')), 'Symfony\Component\EventDispatcher\Tests\Debug\FooListener::listenStatic'); + $listeners[] = array(\Closure::fromCallable(function () {}), 'closure'); + } + + return $listeners; + } +} + +class FooListener +{ + public function listen() + { + } + + public function __invoke() + { + } + + public static function listenStatic() + { + } +} diff --git a/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php b/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php index c1b49f75b8..a359bd7ec5 100644 --- a/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php +++ b/vendor/symfony/event-dispatcher/Tests/DependencyInjection/RegisterListenersPassTest.php @@ -141,6 +141,47 @@ class RegisterListenersPassTest extends TestCase $registerListenersPass = new RegisterListenersPass(); $registerListenersPass->process($container); } + + public function testInvokableEventListener() + { + $container = new ContainerBuilder(); + $container->register('foo', \stdClass::class)->addTag('kernel.event_listener', array('event' => 'foo.bar')); + $container->register('bar', InvokableListenerService::class)->addTag('kernel.event_listener', array('event' => 'foo.bar')); + $container->register('baz', InvokableListenerService::class)->addTag('kernel.event_listener', array('event' => 'event')); + $container->register('event_dispatcher', \stdClass::class); + + $registerListenersPass = new RegisterListenersPass(); + $registerListenersPass->process($container); + + $definition = $container->getDefinition('event_dispatcher'); + $expectedCalls = array( + array( + 'addListener', + array( + 'foo.bar', + array(new ServiceClosureArgument(new Reference('foo')), 'onFooBar'), + 0, + ), + ), + array( + 'addListener', + array( + 'foo.bar', + array(new ServiceClosureArgument(new Reference('bar')), '__invoke'), + 0, + ), + ), + array( + 'addListener', + array( + 'event', + array(new ServiceClosureArgument(new Reference('baz')), 'onEvent'), + 0, + ), + ), + ); + $this->assertEquals($expectedCalls, $definition->getMethodCalls()); + } } class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface @@ -152,3 +193,14 @@ class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubsc ); } } + +class InvokableListenerService +{ + public function __invoke() + { + } + + public function onEvent() + { + } +} diff --git a/vendor/symfony/event-dispatcher/composer.json b/vendor/symfony/event-dispatcher/composer.json index 75b881b917..6c75dfbb00 100644 --- a/vendor/symfony/event-dispatcher/composer.json +++ b/vendor/symfony/event-dispatcher/composer.json @@ -16,17 +16,18 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8" + "php": "^7.1.3", + "symfony/contracts": "^1.0" }, "require-dev": { - "symfony/dependency-injection": "~3.3|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", + "symfony/dependency-injection": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/config": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0", "psr/log": "~1.0" }, "conflict": { - "symfony/dependency-injection": "<3.3" + "symfony/dependency-injection": "<3.4" }, "suggest": { "symfony/dependency-injection": "", @@ -41,7 +42,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } } } diff --git a/vendor/symfony/event-dispatcher/phpunit.xml.dist b/vendor/symfony/event-dispatcher/phpunit.xml.dist index b3ad1bdf5a..f2eb1692cd 100644 --- a/vendor/symfony/event-dispatcher/phpunit.xml.dist +++ b/vendor/symfony/event-dispatcher/phpunit.xml.dist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" diff --git a/vendor/symfony/expression-language/CHANGELOG.md b/vendor/symfony/expression-language/CHANGELOG.md index d00d17c776..6c50b2ea42 100644 --- a/vendor/symfony/expression-language/CHANGELOG.md +++ b/vendor/symfony/expression-language/CHANGELOG.md @@ -1,6 +1,14 @@ CHANGELOG ========= +4.0.0 +----- + + * the first argument of the `ExpressionLanguage` constructor must be an instance + of `CacheItemPoolInterface` + * removed the `ArrayParserCache` and `ParserCacheAdapter` classes + * removed the `ParserCacheInterface` + 2.6.0 ----- diff --git a/vendor/symfony/expression-language/Compiler.php b/vendor/symfony/expression-language/Compiler.php index acfb6184a4..23222d40e9 100644 --- a/vendor/symfony/expression-language/Compiler.php +++ b/vendor/symfony/expression-language/Compiler.php @@ -11,12 +11,14 @@ namespace Symfony\Component\ExpressionLanguage; +use Symfony\Contracts\Service\ResetInterface; + /** * Compiles a node to PHP code. * * @author Fabien Potencier <fabien@symfony.com> */ -class Compiler +class Compiler implements ResetInterface { private $source; private $functions; diff --git a/vendor/symfony/expression-language/Expression.php b/vendor/symfony/expression-language/Expression.php index ac656cce03..59d0e2a6a5 100644 --- a/vendor/symfony/expression-language/Expression.php +++ b/vendor/symfony/expression-language/Expression.php @@ -20,12 +20,9 @@ class Expression { protected $expression; - /** - * @param string $expression An expression - */ - public function __construct($expression) + public function __construct(string $expression) { - $this->expression = (string) $expression; + $this->expression = $expression; } /** diff --git a/vendor/symfony/expression-language/ExpressionFunction.php b/vendor/symfony/expression-language/ExpressionFunction.php index 77c88f66db..2bc91e8d03 100644 --- a/vendor/symfony/expression-language/ExpressionFunction.php +++ b/vendor/symfony/expression-language/ExpressionFunction.php @@ -39,7 +39,7 @@ class ExpressionFunction * @param callable $compiler A callable able to compile the function * @param callable $evaluator A callable able to evaluate the function */ - public function __construct($name, callable $compiler, callable $evaluator) + public function __construct(string $name, callable $compiler, callable $evaluator) { $this->name = $name; $this->compiler = $compiler; @@ -90,9 +90,7 @@ class ExpressionFunction }; $evaluator = function () use ($phpFunctionName) { - $args = \func_get_args(); - - return \call_user_func_array($phpFunctionName, array_splice($args, 1)); + return $phpFunctionName(...\array_slice(\func_get_args(), 1)); }; return new self($expressionFunctionName ?: end($parts), $compiler, $evaluator); diff --git a/vendor/symfony/expression-language/ExpressionLanguage.php b/vendor/symfony/expression-language/ExpressionLanguage.php index 20e8386f41..851fe00157 100644 --- a/vendor/symfony/expression-language/ExpressionLanguage.php +++ b/vendor/symfony/expression-language/ExpressionLanguage.php @@ -13,8 +13,6 @@ namespace Symfony\Component\ExpressionLanguage; use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; -use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter; -use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface; /** * Allows to compile and evaluate expressions written in your own DSL. @@ -34,17 +32,8 @@ class ExpressionLanguage * @param CacheItemPoolInterface $cache * @param ExpressionFunctionProviderInterface[] $providers */ - public function __construct($cache = null, array $providers = array()) + public function __construct(CacheItemPoolInterface $cache = null, array $providers = array()) { - if (null !== $cache) { - if ($cache instanceof ParserCacheInterface) { - @trigger_error(sprintf('Passing an instance of %s as constructor argument for %s is deprecated as of 3.2 and will be removed in 4.0. Pass an instance of %s instead.', ParserCacheInterface::class, self::class, CacheItemPoolInterface::class), E_USER_DEPRECATED); - $cache = new ParserCacheAdapter($cache); - } elseif (!$cache instanceof CacheItemPoolInterface) { - throw new \InvalidArgumentException(sprintf('Cache argument has to implement %s.', CacheItemPoolInterface::class)); - } - } - $this->cache = $cache ?: new ArrayAdapter(); $this->registerFunctions(); foreach ($providers as $provider) { @@ -149,7 +138,7 @@ class ExpressionLanguage $this->addFunction(ExpressionFunction::fromPhp('constant')); } - private function getLexer() + private function getLexer(): Lexer { if (null === $this->lexer) { $this->lexer = new Lexer(); @@ -158,7 +147,7 @@ class ExpressionLanguage return $this->lexer; } - private function getParser() + private function getParser(): Parser { if (null === $this->parser) { $this->parser = new Parser($this->functions); @@ -167,7 +156,7 @@ class ExpressionLanguage return $this->parser; } - private function getCompiler() + private function getCompiler(): Compiler { if (null === $this->compiler) { $this->compiler = new Compiler($this->functions); diff --git a/vendor/symfony/expression-language/Node/BinaryNode.php b/vendor/symfony/expression-language/Node/BinaryNode.php index f1755daee4..48c6548fa8 100644 --- a/vendor/symfony/expression-language/Node/BinaryNode.php +++ b/vendor/symfony/expression-language/Node/BinaryNode.php @@ -33,7 +33,7 @@ class BinaryNode extends Node 'not in' => '!in_array', ); - public function __construct($operator, Node $left, Node $right) + public function __construct(string $operator, Node $left, Node $right) { parent::__construct( array('left' => $left, 'right' => $right), diff --git a/vendor/symfony/expression-language/Node/ConstantNode.php b/vendor/symfony/expression-language/Node/ConstantNode.php index 53c3290b3a..de2c48f10d 100644 --- a/vendor/symfony/expression-language/Node/ConstantNode.php +++ b/vendor/symfony/expression-language/Node/ConstantNode.php @@ -22,7 +22,7 @@ class ConstantNode extends Node { private $isIdentifier; - public function __construct($value, $isIdentifier = false) + public function __construct($value, bool $isIdentifier = false) { $this->isIdentifier = $isIdentifier; parent::__construct( diff --git a/vendor/symfony/expression-language/Node/FunctionNode.php b/vendor/symfony/expression-language/Node/FunctionNode.php index ca479b3d5c..fd24e1300f 100644 --- a/vendor/symfony/expression-language/Node/FunctionNode.php +++ b/vendor/symfony/expression-language/Node/FunctionNode.php @@ -20,7 +20,7 @@ use Symfony\Component\ExpressionLanguage\Compiler; */ class FunctionNode extends Node { - public function __construct($name, Node $arguments) + public function __construct(string $name, Node $arguments) { parent::__construct( array('arguments' => $arguments), @@ -37,7 +37,7 @@ class FunctionNode extends Node $function = $compiler->getFunction($this->attributes['name']); - $compiler->raw(\call_user_func_array($function['compiler'], $arguments)); + $compiler->raw($function['compiler'](...$arguments)); } public function evaluate($functions, $values) @@ -47,7 +47,7 @@ class FunctionNode extends Node $arguments[] = $node->evaluate($functions, $values); } - return \call_user_func_array($functions[$this->attributes['name']]['evaluator'], $arguments); + return $functions[$this->attributes['name']]['evaluator'](...$arguments); } public function toArray() diff --git a/vendor/symfony/expression-language/Node/GetAttrNode.php b/vendor/symfony/expression-language/Node/GetAttrNode.php index f76ce175e8..86c5a405f0 100644 --- a/vendor/symfony/expression-language/Node/GetAttrNode.php +++ b/vendor/symfony/expression-language/Node/GetAttrNode.php @@ -24,7 +24,7 @@ class GetAttrNode extends Node const METHOD_CALL = 2; const ARRAY_CALL = 3; - public function __construct(Node $node, Node $attribute, ArrayNode $arguments, $type) + public function __construct(Node $node, Node $attribute, ArrayNode $arguments, int $type) { parent::__construct( array('node' => $node, 'attribute' => $attribute, 'arguments' => $arguments), @@ -86,7 +86,7 @@ class GetAttrNode extends Node throw new \RuntimeException(sprintf('Unable to call method "%s" of object "%s".', $this->nodes['attribute']->attributes['value'], \get_class($obj))); } - return \call_user_func_array($toCall, $this->nodes['arguments']->evaluate($functions, $values)); + return $toCall(...array_values($this->nodes['arguments']->evaluate($functions, $values))); case self::ARRAY_CALL: $array = $this->nodes['node']->evaluate($functions, $values); diff --git a/vendor/symfony/expression-language/Node/NameNode.php b/vendor/symfony/expression-language/Node/NameNode.php index 9e1462f2c6..c084bd4793 100644 --- a/vendor/symfony/expression-language/Node/NameNode.php +++ b/vendor/symfony/expression-language/Node/NameNode.php @@ -20,7 +20,7 @@ use Symfony\Component\ExpressionLanguage\Compiler; */ class NameNode extends Node { - public function __construct($name) + public function __construct(string $name) { parent::__construct( array(), diff --git a/vendor/symfony/expression-language/Node/UnaryNode.php b/vendor/symfony/expression-language/Node/UnaryNode.php index 583103217a..4a18e83a5d 100644 --- a/vendor/symfony/expression-language/Node/UnaryNode.php +++ b/vendor/symfony/expression-language/Node/UnaryNode.php @@ -27,7 +27,7 @@ class UnaryNode extends Node '-' => '-', ); - public function __construct($operator, Node $node) + public function __construct(string $operator, Node $node) { parent::__construct( array('node' => $node), @@ -59,7 +59,7 @@ class UnaryNode extends Node return $value; } - public function toArray() + public function toArray(): array { return array('(', $this->attributes['operator'].' ', $this->nodes['node'], ')'); } diff --git a/vendor/symfony/expression-language/ParsedExpression.php b/vendor/symfony/expression-language/ParsedExpression.php index a5603fc3ca..2e2bf374e3 100644 --- a/vendor/symfony/expression-language/ParsedExpression.php +++ b/vendor/symfony/expression-language/ParsedExpression.php @@ -26,7 +26,7 @@ class ParsedExpression extends Expression * @param string $expression An expression * @param Node $nodes A Node representing the expression */ - public function __construct($expression, Node $nodes) + public function __construct(string $expression, Node $nodes) { parent::__construct($expression); diff --git a/vendor/symfony/expression-language/ParserCache/ArrayParserCache.php b/vendor/symfony/expression-language/ParserCache/ArrayParserCache.php deleted file mode 100644 index 124962505d..0000000000 --- a/vendor/symfony/expression-language/ParserCache/ArrayParserCache.php +++ /dev/null @@ -1,42 +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\ExpressionLanguage\ParserCache; - -@trigger_error('The '.__NAMESPACE__.'\ArrayParserCache class is deprecated since Symfony 3.2 and will be removed in 4.0. Use the Symfony\Component\Cache\Adapter\ArrayAdapter class instead.', E_USER_DEPRECATED); - -use Symfony\Component\ExpressionLanguage\ParsedExpression; - -/** - * @author Adrien Brault <adrien.brault@gmail.com> - * - * @deprecated ArrayParserCache class is deprecated since version 3.2 and will be removed in 4.0. Use the Symfony\Component\Cache\Adapter\ArrayAdapter class instead. - */ -class ArrayParserCache implements ParserCacheInterface -{ - private $cache = array(); - - /** - * {@inheritdoc} - */ - public function fetch($key) - { - return isset($this->cache[$key]) ? $this->cache[$key] : null; - } - - /** - * {@inheritdoc} - */ - public function save($key, ParsedExpression $expression) - { - $this->cache[$key] = $expression; - } -} diff --git a/vendor/symfony/expression-language/ParserCache/ParserCacheAdapter.php b/vendor/symfony/expression-language/ParserCache/ParserCacheAdapter.php deleted file mode 100644 index a3e227d0a5..0000000000 --- a/vendor/symfony/expression-language/ParserCache/ParserCacheAdapter.php +++ /dev/null @@ -1,120 +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\ExpressionLanguage\ParserCache; - -use Psr\Cache\CacheItemInterface; -use Psr\Cache\CacheItemPoolInterface; -use Symfony\Component\Cache\CacheItem; - -/** - * @author Alexandre GESLIN <alexandre@gesl.in> - * - * @internal and will be removed in Symfony 4.0. - */ -class ParserCacheAdapter implements CacheItemPoolInterface -{ - private $pool; - private $createCacheItem; - - public function __construct(ParserCacheInterface $pool) - { - $this->pool = $pool; - - $this->createCacheItem = \Closure::bind( - function ($key, $value, $isHit) { - $item = new CacheItem(); - $item->key = $key; - $item->value = $value; - $item->isHit = $isHit; - - return $item; - }, - null, - CacheItem::class - ); - } - - /** - * {@inheritdoc} - */ - public function getItem($key) - { - $value = $this->pool->fetch($key); - $f = $this->createCacheItem; - - return $f($key, $value, null !== $value); - } - - /** - * {@inheritdoc} - */ - public function save(CacheItemInterface $item) - { - $this->pool->save($item->getKey(), $item->get()); - } - - /** - * {@inheritdoc} - */ - public function getItems(array $keys = array()) - { - throw new \BadMethodCallException('Not implemented'); - } - - /** - * {@inheritdoc} - */ - public function hasItem($key) - { - throw new \BadMethodCallException('Not implemented'); - } - - /** - * {@inheritdoc} - */ - public function clear() - { - throw new \BadMethodCallException('Not implemented'); - } - - /** - * {@inheritdoc} - */ - public function deleteItem($key) - { - throw new \BadMethodCallException('Not implemented'); - } - - /** - * {@inheritdoc} - */ - public function deleteItems(array $keys) - { - throw new \BadMethodCallException('Not implemented'); - } - - /** - * {@inheritdoc} - */ - public function saveDeferred(CacheItemInterface $item) - { - throw new \BadMethodCallException('Not implemented'); - } - - /** - * {@inheritdoc} - */ - public function commit() - { - throw new \BadMethodCallException('Not implemented'); - } -} diff --git a/vendor/symfony/expression-language/ParserCache/ParserCacheInterface.php b/vendor/symfony/expression-language/ParserCache/ParserCacheInterface.php deleted file mode 100644 index ed66b21bf2..0000000000 --- a/vendor/symfony/expression-language/ParserCache/ParserCacheInterface.php +++ /dev/null @@ -1,41 +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\ExpressionLanguage\ParserCache; - -@trigger_error('The '.__NAMESPACE__.'\ParserCacheInterface interface is deprecated since Symfony 3.2 and will be removed in 4.0. Use Psr\Cache\CacheItemPoolInterface instead.', E_USER_DEPRECATED); - -use Symfony\Component\ExpressionLanguage\ParsedExpression; - -/** - * @author Adrien Brault <adrien.brault@gmail.com> - * - * @deprecated since version 3.2, to be removed in 4.0. Use Psr\Cache\CacheItemPoolInterface instead. - */ -interface ParserCacheInterface -{ - /** - * Saves an expression in the cache. - * - * @param string $key The cache key - * @param ParsedExpression $expression A ParsedExpression instance to store in the cache - */ - public function save($key, ParsedExpression $expression); - - /** - * Fetches an expression from the cache. - * - * @param string $key The cache key - * - * @return ParsedExpression|null - */ - public function fetch($key); -} diff --git a/vendor/symfony/expression-language/SerializedParsedExpression.php b/vendor/symfony/expression-language/SerializedParsedExpression.php index dd763f75b5..a1f838c030 100644 --- a/vendor/symfony/expression-language/SerializedParsedExpression.php +++ b/vendor/symfony/expression-language/SerializedParsedExpression.php @@ -24,9 +24,9 @@ class SerializedParsedExpression extends ParsedExpression * @param string $expression An expression * @param string $nodes The serialized nodes for the expression */ - public function __construct($expression, $nodes) + public function __construct(string $expression, string $nodes) { - $this->expression = (string) $expression; + $this->expression = $expression; $this->nodes = $nodes; } diff --git a/vendor/symfony/expression-language/SyntaxError.php b/vendor/symfony/expression-language/SyntaxError.php index 12348e6830..d3313b8321 100644 --- a/vendor/symfony/expression-language/SyntaxError.php +++ b/vendor/symfony/expression-language/SyntaxError.php @@ -13,7 +13,7 @@ namespace Symfony\Component\ExpressionLanguage; class SyntaxError extends \LogicException { - public function __construct($message, $cursor = 0, $expression = '', $subject = null, array $proposals = null) + public function __construct(string $message, int $cursor = 0, string $expression = '', string $subject = null, array $proposals = null) { $message = sprintf('%s around position %d', $message, $cursor); if ($expression) { diff --git a/vendor/symfony/expression-language/Tests/ExpressionLanguageTest.php b/vendor/symfony/expression-language/Tests/ExpressionLanguageTest.php index a1e5b7cc7d..15a26d5f3f 100644 --- a/vendor/symfony/expression-language/Tests/ExpressionLanguageTest.php +++ b/vendor/symfony/expression-language/Tests/ExpressionLanguageTest.php @@ -63,47 +63,6 @@ class ExpressionLanguageTest extends TestCase $this->assertSame($savedParsedExpression, $parsedExpression); } - /** - * @group legacy - */ - public function testCachedParseWithDeprecatedParserCacheInterface() - { - $cacheMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - - $cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock(); - $savedParsedExpression = null; - $expressionLanguage = new ExpressionLanguage($cacheMock); - - $cacheMock - ->expects($this->exactly(1)) - ->method('fetch') - ->with('1%20%2B%201%2F%2F') - ->willReturn($savedParsedExpression) - ; - - $cacheMock - ->expects($this->exactly(1)) - ->method('save') - ->with('1%20%2B%201%2F%2F', $this->isInstanceOf(ParsedExpression::class)) - ->will($this->returnCallback(function ($key, $expression) use (&$savedParsedExpression) { - $savedParsedExpression = $expression; - })) - ; - - $parsedExpression = $expressionLanguage->parse('1 + 1', array()); - $this->assertSame($savedParsedExpression, $parsedExpression); - } - - /** - * @expectedException \InvalidArgumentException - * @expectedExceptionMessage Cache argument has to implement Psr\Cache\CacheItemPoolInterface. - */ - public function testWrongCacheImplementation() - { - $cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemSpoolInterface')->getMock(); - $expressionLanguage = new ExpressionLanguage($cacheMock); - } - public function testConstantFunction() { $expressionLanguage = new ExpressionLanguage(); diff --git a/vendor/symfony/expression-language/Tests/ParserCache/ParserCacheAdapterTest.php b/vendor/symfony/expression-language/Tests/ParserCache/ParserCacheAdapterTest.php deleted file mode 100644 index 20fbe80244..0000000000 --- a/vendor/symfony/expression-language/Tests/ParserCache/ParserCacheAdapterTest.php +++ /dev/null @@ -1,140 +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\ExpressionLanguage\Tests; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\ExpressionLanguage\Node\Node; -use Symfony\Component\ExpressionLanguage\ParsedExpression; -use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheAdapter; - -/** - * @group legacy - */ -class ParserCacheAdapterTest extends TestCase -{ - public function testGetItem() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - - $key = 'key'; - $value = 'value'; - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - - $poolMock - ->expects($this->once()) - ->method('fetch') - ->with($key) - ->willReturn($value) - ; - - $cacheItem = $parserCacheAdapter->getItem($key); - - $this->assertEquals($cacheItem->get(), $value); - $this->assertEquals($cacheItem->isHit(), true); - } - - public function testSave() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock(); - $key = 'key'; - $value = new ParsedExpression('1 + 1', new Node(array(), array())); - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - - $poolMock - ->expects($this->once()) - ->method('save') - ->with($key, $value) - ; - - $cacheItemMock - ->expects($this->once()) - ->method('getKey') - ->willReturn($key) - ; - - $cacheItemMock - ->expects($this->once()) - ->method('get') - ->willReturn($value) - ; - - $cacheItem = $parserCacheAdapter->save($cacheItemMock); - } - - public function testGetItems() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->getItems(); - } - - public function testHasItem() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $key = 'key'; - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->hasItem($key); - } - - public function testClear() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->clear(); - } - - public function testDeleteItem() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $key = 'key'; - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->deleteItem($key); - } - - public function testDeleteItems() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $keys = array('key'); - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->deleteItems($keys); - } - - public function testSaveDeferred() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock(); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->saveDeferred($cacheItemMock); - } - - public function testCommit() - { - $poolMock = $this->getMockBuilder('Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface')->getMock(); - $parserCacheAdapter = new ParserCacheAdapter($poolMock); - $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}(\BadMethodCallException::class); - - $parserCacheAdapter->commit(); - } -} diff --git a/vendor/symfony/expression-language/Token.php b/vendor/symfony/expression-language/Token.php index 4517335bbc..40bb75587e 100644 --- a/vendor/symfony/expression-language/Token.php +++ b/vendor/symfony/expression-language/Token.php @@ -34,7 +34,7 @@ class Token * @param string|int|float|null $value The token value * @param int $cursor The cursor position in the source */ - public function __construct($type, $value, $cursor) + public function __construct(string $type, $value, ?int $cursor) { $this->type = $type; $this->value = $value; diff --git a/vendor/symfony/expression-language/TokenStream.php b/vendor/symfony/expression-language/TokenStream.php index 9096b183ff..919add6b90 100644 --- a/vendor/symfony/expression-language/TokenStream.php +++ b/vendor/symfony/expression-language/TokenStream.php @@ -24,11 +24,7 @@ class TokenStream private $position = 0; private $expression; - /** - * @param array $tokens An array of tokens - * @param string $expression - */ - public function __construct(array $tokens, $expression = '') + public function __construct(array $tokens, string $expression = '') { $this->tokens = $tokens; $this->current = $tokens[0]; diff --git a/vendor/symfony/expression-language/composer.json b/vendor/symfony/expression-language/composer.json index 5f662ffd38..2e699629e8 100644 --- a/vendor/symfony/expression-language/composer.json +++ b/vendor/symfony/expression-language/composer.json @@ -16,8 +16,9 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/cache": "~3.1|~4.0" + "php": "^7.1.3", + "symfony/cache": "~3.4|~4.0", + "symfony/contracts": "^1.0" }, "autoload": { "psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" }, @@ -28,7 +29,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } } } diff --git a/vendor/symfony/expression-language/phpunit.xml.dist b/vendor/symfony/expression-language/phpunit.xml.dist index 517322fb4f..ae84dcd944 100644 --- a/vendor/symfony/expression-language/phpunit.xml.dist +++ b/vendor/symfony/expression-language/phpunit.xml.dist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" diff --git a/vendor/symfony/http-foundation/AcceptHeader.php b/vendor/symfony/http-foundation/AcceptHeader.php index d1740266b7..c702371f81 100644 --- a/vendor/symfony/http-foundation/AcceptHeader.php +++ b/vendor/symfony/http-foundation/AcceptHeader.php @@ -52,12 +52,17 @@ class AcceptHeader { $index = 0; - return new self(array_map(function ($itemValue) use (&$index) { - $item = AcceptHeaderItem::fromString($itemValue); + $parts = HeaderUtils::split((string) $headerValue, ',;='); + + return new self(array_map(function ($subParts) use (&$index) { + $part = array_shift($subParts); + $attributes = HeaderUtils::combine($subParts); + + $item = new AcceptHeaderItem($part[0], $attributes); $item->setIndex($index++); return $item; - }, preg_split('/\s*(?:,*("[^"]+"),*|,*(\'[^\']+\'),*|,+)\s*/', $headerValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE))); + }, $parts)); } /** @@ -91,7 +96,7 @@ class AcceptHeader */ public function get($value) { - return isset($this->items[$value]) ? $this->items[$value] : null; + return $this->items[$value] ?? $this->items[explode('/', $value)[0].'/*'] ?? $this->items['*/*'] ?? $this->items['*'] ?? null; } /** diff --git a/vendor/symfony/http-foundation/AcceptHeaderItem.php b/vendor/symfony/http-foundation/AcceptHeaderItem.php index c9506574de..2aaf59579f 100644 --- a/vendor/symfony/http-foundation/AcceptHeaderItem.php +++ b/vendor/symfony/http-foundation/AcceptHeaderItem.php @@ -23,11 +23,7 @@ class AcceptHeaderItem private $index = 0; private $attributes = array(); - /** - * @param string $value - * @param array $attributes - */ - public function __construct($value, array $attributes = array()) + public function __construct(string $value, array $attributes = array()) { $this->value = $value; foreach ($attributes as $name => $value) { @@ -44,24 +40,12 @@ class AcceptHeaderItem */ public static function fromString($itemValue) { - $bits = preg_split('/\s*(?:;*("[^"]+");*|;*(\'[^\']+\');*|;+)\s*/', $itemValue, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); - $value = array_shift($bits); - $attributes = array(); + $parts = HeaderUtils::split($itemValue, ';='); - $lastNullAttribute = null; - foreach ($bits as $bit) { - if (($start = substr($bit, 0, 1)) === ($end = substr($bit, -1)) && ('"' === $start || '\'' === $start)) { - $attributes[$lastNullAttribute] = substr($bit, 1, -1); - } elseif ('=' === $end) { - $lastNullAttribute = $bit = substr($bit, 0, -1); - $attributes[$bit] = null; - } else { - $parts = explode('=', $bit); - $attributes[$parts[0]] = isset($parts[1]) && \strlen($parts[1]) > 0 ? $parts[1] : ''; - } - } + $part = array_shift($parts); + $attributes = HeaderUtils::combine($parts); - return new self(($start = substr($value, 0, 1)) === ($end = substr($value, -1)) && ('"' === $start || '\'' === $start) ? substr($value, 1, -1) : $value, $attributes); + return new self($part[0], $attributes); } /** @@ -73,9 +57,7 @@ class AcceptHeaderItem { $string = $this->value.($this->quality < 1 ? ';q='.$this->quality : ''); if (\count($this->attributes) > 0) { - $string .= ';'.implode(';', array_map(function ($name, $value) { - return sprintf(preg_match('/[,;=]/', $value) ? '%s="%s"' : '%s=%s', $name, $value); - }, array_keys($this->attributes), $this->attributes)); + $string .= '; '.HeaderUtils::toString($this->attributes, ';'); } return $string; diff --git a/vendor/symfony/http-foundation/BinaryFileResponse.php b/vendor/symfony/http-foundation/BinaryFileResponse.php index 97023278e0..07ef800508 100644 --- a/vendor/symfony/http-foundation/BinaryFileResponse.php +++ b/vendor/symfony/http-foundation/BinaryFileResponse.php @@ -44,7 +44,7 @@ class BinaryFileResponse extends Response * @param bool $autoEtag Whether the ETag header should be automatically set * @param bool $autoLastModified Whether the Last-Modified header should be automatically set */ - public function __construct($file, $status = 200, $headers = array(), $public = true, $contentDisposition = null, $autoEtag = false, $autoLastModified = true) + public function __construct($file, int $status = 200, array $headers = array(), bool $public = true, string $contentDisposition = null, bool $autoEtag = false, bool $autoLastModified = true) { parent::__construct(null, $status, $headers); @@ -218,17 +218,12 @@ class BinaryFileResponse extends Response if ('x-accel-redirect' === strtolower($type)) { // Do X-Accel-Mapping substitutions. // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect - foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) { - $mapping = explode('=', $mapping, 2); - - if (2 === \count($mapping)) { - $pathPrefix = trim($mapping[0]); - $location = trim($mapping[1]); - - if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix) { - $path = $location.substr($path, \strlen($pathPrefix)); - break; - } + $parts = HeaderUtils::split($request->headers->get('X-Accel-Mapping', ''), ',='); + foreach ($parts as $part) { + list($pathPrefix, $location) = $part; + if (substr($path, 0, \strlen($pathPrefix)) === $pathPrefix) { + $path = $location.substr($path, \strlen($pathPrefix)); + break; } } } @@ -350,7 +345,7 @@ class BinaryFileResponse extends Response * * @return $this */ - public function deleteFileAfterSend($shouldDelete) + public function deleteFileAfterSend($shouldDelete = true) { $this->deleteFileAfterSend = $shouldDelete; diff --git a/vendor/symfony/http-foundation/CHANGELOG.md b/vendor/symfony/http-foundation/CHANGELOG.md index 97b279df1f..55eed3f7eb 100644 --- a/vendor/symfony/http-foundation/CHANGELOG.md +++ b/vendor/symfony/http-foundation/CHANGELOG.md @@ -1,12 +1,58 @@ CHANGELOG ========= -3.4.14 ------- +4.2.0 +----- + + * the default value of the "$secure" and "$samesite" arguments of Cookie's constructor + will respectively change from "false" to "null" and from "null" to "lax" in Symfony + 5.0, you should define their values explicitly or use "Cookie::create()" instead. + * added `matchPort()` in RequestMatcher + +4.1.3 +----- * [BC BREAK] Support for the IIS-only `X_ORIGINAL_URL` and `X_REWRITE_URL` HTTP headers has been dropped for security reasons. +4.1.0 +----- + + * Query string normalization uses `parse_str()` instead of custom parsing logic. + * Passing the file size to the constructor of the `UploadedFile` class is deprecated. + * The `getClientSize()` method of the `UploadedFile` class is deprecated. Use `getSize()` instead. + * added `RedisSessionHandler` to use Redis as a session storage + * The `get()` method of the `AcceptHeader` class now takes into account the + `*` and `*/*` default values (if they are present in the Accept HTTP header) + when looking for items. + * deprecated `Request::getSession()` when no session has been set. Use `Request::hasSession()` instead. + * added `CannotWriteFileException`, `ExtensionFileException`, `FormSizeFileException`, + `IniSizeFileException`, `NoFileException`, `NoTmpDirFileException`, `PartialFileException` to + handle failed `UploadedFile`. + * added `MigratingSessionHandler` for migrating between two session handlers without losing sessions + * added `HeaderUtils`. + +4.0.0 +----- + + * the `Request::setTrustedHeaderName()` and `Request::getTrustedHeaderName()` + methods have been removed + * the `Request::HEADER_CLIENT_IP` constant has been removed, use + `Request::HEADER_X_FORWARDED_FOR` instead + * the `Request::HEADER_CLIENT_HOST` constant has been removed, use + `Request::HEADER_X_FORWARDED_HOST` instead + * the `Request::HEADER_CLIENT_PROTO` constant has been removed, use + `Request::HEADER_X_FORWARDED_PROTO` instead + * the `Request::HEADER_CLIENT_PORT` constant has been removed, use + `Request::HEADER_X_FORWARDED_PORT` instead + * checking for cacheable HTTP methods using the `Request::isMethodSafe()` + method (by not passing `false` as its argument) is not supported anymore and + throws a `\BadMethodCallException` + * the `WriteCheckSessionHandler`, `NativeSessionHandler` and `NativeProxy` classes have been removed + * setting session save handlers that do not implement `\SessionHandlerInterface` in + `NativeSessionStorage::setSaveHandler()` is not supported anymore and throws a + `\TypeError` + 3.4.0 ----- diff --git a/vendor/symfony/http-foundation/Cookie.php b/vendor/symfony/http-foundation/Cookie.php index c38aa409da..7aab318ccd 100644 --- a/vendor/symfony/http-foundation/Cookie.php +++ b/vendor/symfony/http-foundation/Cookie.php @@ -27,6 +27,7 @@ class Cookie protected $httpOnly; private $raw; private $sameSite; + private $secureDefault = false; const SAMESITE_LAX = 'lax'; const SAMESITE_STRICT = 'strict'; @@ -50,34 +51,25 @@ class Cookie 'raw' => !$decode, 'samesite' => null, ); - foreach (explode(';', $cookie) as $part) { - if (false === strpos($part, '=')) { - $key = trim($part); - $value = true; - } else { - list($key, $value) = explode('=', trim($part), 2); - $key = trim($key); - $value = trim($value); - } - if (!isset($data['name'])) { - $data['name'] = $decode ? urldecode($key) : $key; - $data['value'] = true === $value ? null : ($decode ? urldecode($value) : $value); - continue; - } - switch ($key = strtolower($key)) { - case 'name': - case 'value': - break; - case 'max-age': - $data['expires'] = time() + (int) $value; - break; - default: - $data[$key] = $value; - break; - } + + $parts = HeaderUtils::split($cookie, ';='); + $part = array_shift($parts); + + $name = $decode ? urldecode($part[0]) : $part[0]; + $value = isset($part[1]) ? ($decode ? urldecode($part[1]) : $part[1]) : null; + + $data = HeaderUtils::combine($parts) + $data; + + if (isset($data['max-age'])) { + $data['expires'] = time() + (int) $data['max-age']; } - return new static($data['name'], $data['value'], $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']); + return new static($name, $value, $data['expires'], $data['path'], $data['domain'], $data['secure'], $data['httponly'], $data['raw'], $data['samesite']); + } + + public static function create(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, bool $secure = null, bool $httpOnly = true, bool $raw = false, ?string $sameSite = self::SAMESITE_LAX): self + { + return new self($name, $value, $expire, $path, $domain, $secure, $httpOnly, $raw, $sameSite); } /** @@ -86,15 +78,19 @@ class Cookie * @param int|string|\DateTimeInterface $expire The time the cookie expires * @param string $path The path on the server in which the cookie will be available on * @param string|null $domain The domain that the cookie is available to - * @param bool $secure Whether the cookie should only be transmitted over a secure HTTPS connection from the client + * @param bool|null $secure Whether the client should send back the cookie only over HTTPS or null to auto-enable this when the request is already using HTTPS * @param bool $httpOnly Whether the cookie will be made accessible only through the HTTP protocol * @param bool $raw Whether the cookie value should be sent with no url encoding * @param string|null $sameSite Whether the cookie will be available for cross-site requests * * @throws \InvalidArgumentException */ - public function __construct($name, $value = null, $expire = 0, $path = '/', $domain = null, $secure = false, $httpOnly = true, $raw = false, $sameSite = null) + public function __construct(string $name, string $value = null, $expire = 0, ?string $path = '/', string $domain = null, ?bool $secure = false, bool $httpOnly = true, bool $raw = false, string $sameSite = null) { + if (9 > \func_num_args()) { + @trigger_error(sprintf('The default value of the "$secure" and "$samesite" arguments of "%s"\'s constructor will respectively change from "false" to "null" and from "null" to "lax" in Symfony 5.0, you should define their values explicitly or use "Cookie::create()" instead.', __METHOD__), E_USER_DEPRECATED); + } + // from PHP source code if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name)); @@ -120,11 +116,13 @@ class Cookie $this->domain = $domain; $this->expire = 0 < $expire ? (int) $expire : 0; $this->path = empty($path) ? '/' : $path; - $this->secure = (bool) $secure; - $this->httpOnly = (bool) $httpOnly; - $this->raw = (bool) $raw; + $this->secure = $secure; + $this->httpOnly = $httpOnly; + $this->raw = $raw; - if (null !== $sameSite) { + if ('' === $sameSite) { + $sameSite = null; + } elseif (null !== $sameSite) { $sameSite = strtolower($sameSite); } @@ -246,7 +244,7 @@ class Cookie */ public function isSecure() { - return $this->secure; + return $this->secure ?? $this->secureDefault; } /** @@ -288,4 +286,12 @@ class Cookie { return $this->sameSite; } + + /** + * @param bool $default The default value of the "secure" flag when it is set to null + */ + public function setSecureDefault(bool $default): void + { + $this->secureDefault = $default; + } } diff --git a/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php b/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php index 3b8e41d4a2..c25c3629bb 100644 --- a/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php +++ b/vendor/symfony/http-foundation/File/Exception/AccessDeniedException.php @@ -21,7 +21,7 @@ class AccessDeniedException extends FileException /** * @param string $path The path to the accessed file */ - public function __construct($path) + public function __construct(string $path) { parent::__construct(sprintf('The file %s could not be accessed', $path)); } diff --git a/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php b/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.php new file mode 100644 index 0000000000..c49f53a6cf --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/CannotWriteFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_CANT_WRITE error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class CannotWriteFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php b/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.php new file mode 100644 index 0000000000..ed83499c00 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/ExtensionFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_EXTENSION error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class ExtensionFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php b/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php index bfcc37ec66..0f1f3f951d 100644 --- a/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php +++ b/vendor/symfony/http-foundation/File/Exception/FileNotFoundException.php @@ -21,7 +21,7 @@ class FileNotFoundException extends FileException /** * @param string $path The path to the file that was not found */ - public function __construct($path) + public function __construct(string $path) { parent::__construct(sprintf('The file "%s" does not exist', $path)); } diff --git a/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php b/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.php new file mode 100644 index 0000000000..8741be0884 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/FormSizeFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_FORM_SIZE error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class FormSizeFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php b/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.php new file mode 100644 index 0000000000..c8fde6103a --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/IniSizeFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_INI_SIZE error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class IniSizeFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/NoFileException.php b/vendor/symfony/http-foundation/File/Exception/NoFileException.php new file mode 100644 index 0000000000..4b48cc7799 --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/NoFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_NO_FILE error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class NoFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php b/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.php new file mode 100644 index 0000000000..bdead2d91c --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/NoTmpDirFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_NO_TMP_DIR error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class NoTmpDirFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/PartialFileException.php b/vendor/symfony/http-foundation/File/Exception/PartialFileException.php new file mode 100644 index 0000000000..4641efb55a --- /dev/null +++ b/vendor/symfony/http-foundation/File/Exception/PartialFileException.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\HttpFoundation\File\Exception; + +/** + * Thrown when an UPLOAD_ERR_PARTIAL error occurred with UploadedFile. + * + * @author Florent Mata <florentmata@gmail.com> + */ +class PartialFileException extends FileException +{ +} diff --git a/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php b/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php index 62005d3b63..82b982b378 100644 --- a/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php +++ b/vendor/symfony/http-foundation/File/Exception/UnexpectedTypeException.php @@ -13,7 +13,7 @@ namespace Symfony\Component\HttpFoundation\File\Exception; class UnexpectedTypeException extends FileException { - public function __construct($value, $expectedType) + public function __construct($value, string $expectedType) { parent::__construct(sprintf('Expected argument of type %s, %s given', $expectedType, \is_object($value) ? \get_class($value) : \gettype($value))); } diff --git a/vendor/symfony/http-foundation/File/File.php b/vendor/symfony/http-foundation/File/File.php index 34220588a4..de7b080973 100644 --- a/vendor/symfony/http-foundation/File/File.php +++ b/vendor/symfony/http-foundation/File/File.php @@ -31,7 +31,7 @@ class File extends \SplFileInfo * * @throws FileNotFoundException If the given path is not a file */ - public function __construct($path, $checkPath = true) + public function __construct(string $path, bool $checkPath = true) { if ($checkPath && !is_file($path)) { throw new FileNotFoundException($path); diff --git a/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php index 34e015ee5c..313000195d 100644 --- a/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/FileBinaryMimeTypeGuesser.php @@ -31,7 +31,7 @@ class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface * * @param string $cmd The command to run to get the mime type of a file */ - public function __construct($cmd = 'file -b --mime %s 2>/dev/null') + public function __construct(string $cmd = 'file -b --mime %s 2>/dev/null') { $this->cmd = $cmd; } diff --git a/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php b/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php index bf1ee9f5db..cee9ef3f72 100644 --- a/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php +++ b/vendor/symfony/http-foundation/File/MimeType/FileinfoMimeTypeGuesser.php @@ -28,7 +28,7 @@ class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface * * @see http://www.php.net/manual/en/function.finfo-open.php */ - public function __construct($magicFile = null) + public function __construct(string $magicFile = null) { $this->magicFile = $magicFile; } diff --git a/vendor/symfony/http-foundation/File/UploadedFile.php b/vendor/symfony/http-foundation/File/UploadedFile.php index de6ce75cc9..63fa6c7302 100644 --- a/vendor/symfony/http-foundation/File/UploadedFile.php +++ b/vendor/symfony/http-foundation/File/UploadedFile.php @@ -11,8 +11,15 @@ namespace Symfony\Component\HttpFoundation\File; +use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException; +use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException; use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; +use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException; +use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException; +use Symfony\Component\HttpFoundation\File\Exception\NoFileException; +use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException; +use Symfony\Component\HttpFoundation\File\Exception\PartialFileException; use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser; /** @@ -27,7 +34,6 @@ class UploadedFile extends File private $test = false; private $originalName; private $mimeType; - private $size; private $error; /** @@ -47,7 +53,6 @@ class UploadedFile extends File * @param string $path The full temporary path to the file * @param string $originalName The original file name of the uploaded file * @param string|null $mimeType The type of the file as provided by PHP; null defaults to application/octet-stream - * @param int|null $size The file size provided by the uploader * @param int|null $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK * @param bool $test Whether the test mode is active * Local files are used in test mode hence the code should not enforce HTTP uploads @@ -55,13 +60,19 @@ class UploadedFile extends File * @throws FileException If file_uploads is disabled * @throws FileNotFoundException If the file does not exist */ - public function __construct($path, $originalName, $mimeType = null, $size = null, $error = null, $test = false) + public function __construct(string $path, string $originalName, string $mimeType = null, int $error = null, $test = false) { $this->originalName = $this->getName($originalName); $this->mimeType = $mimeType ?: 'application/octet-stream'; - $this->size = $size; + + if (4 < \func_num_args() ? !\is_bool($test) : null !== $error && @filesize($path) === $error) { + @trigger_error(sprintf('Passing a size as 4th argument to the constructor of "%s" is deprecated since Symfony 4.1.', __CLASS__), E_USER_DEPRECATED); + $error = $test; + $test = 5 < \func_num_args() ? func_get_arg(5) : false; + } + $this->error = $error ?: UPLOAD_ERR_OK; - $this->test = (bool) $test; + $this->test = $test; parent::__construct($path, UPLOAD_ERR_OK === $this->error); } @@ -141,11 +152,15 @@ class UploadedFile extends File * It is extracted from the request from which the file has been uploaded. * Then it should not be considered as a safe value. * - * @return int|null The file size + * @deprecated since Symfony 4.1, use getSize() instead. + * + * @return int|null The file sizes */ public function getClientSize() { - return $this->size; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use getSize() instead.', __METHOD__), E_USER_DEPRECATED); + + return $this->getSize(); } /** @@ -204,6 +219,23 @@ class UploadedFile extends File return $target; } + switch ($this->error) { + case UPLOAD_ERR_INI_SIZE: + throw new IniSizeFileException($this->getErrorMessage()); + case UPLOAD_ERR_FORM_SIZE: + throw new FormSizeFileException($this->getErrorMessage()); + case UPLOAD_ERR_PARTIAL: + throw new PartialFileException($this->getErrorMessage()); + case UPLOAD_ERR_NO_FILE: + throw new NoFileException($this->getErrorMessage()); + case UPLOAD_ERR_CANT_WRITE: + throw new CannotWriteFileException($this->getErrorMessage()); + case UPLOAD_ERR_NO_TMP_DIR: + throw new NoTmpDirFileException($this->getErrorMessage()); + case UPLOAD_ERR_EXTENSION: + throw new ExtensionFileException($this->getErrorMessage()); + } + throw new FileException($this->getErrorMessage()); } diff --git a/vendor/symfony/http-foundation/FileBag.php b/vendor/symfony/http-foundation/FileBag.php index c135ad6412..f37e10f204 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['size'], $file['error']); + $file = new UploadedFile($file['tmp_name'], $file['name'], $file['type'], $file['error']); } } else { $file = array_map(array($this, 'convertFileInformation'), $file); diff --git a/vendor/symfony/http-foundation/HeaderBag.php b/vendor/symfony/http-foundation/HeaderBag.php index 5445e80c8b..e1a6ae297a 100644 --- a/vendor/symfony/http-foundation/HeaderBag.php +++ b/vendor/symfony/http-foundation/HeaderBag.php @@ -46,7 +46,7 @@ class HeaderBag implements \IteratorAggregate, \Countable $max = max(array_map('strlen', array_keys($headers))) + 1; $content = ''; foreach ($headers as $name => $values) { - $name = implode('-', array_map('ucfirst', explode('-', $name))); + $name = ucwords($name, '-'); foreach ($values as $value) { $content .= sprintf("%-{$max}s %s\r\n", $name.':', $value); } @@ -294,21 +294,9 @@ class HeaderBag implements \IteratorAggregate, \Countable protected function getCacheControlHeader() { - $parts = array(); ksort($this->cacheControl); - foreach ($this->cacheControl as $key => $value) { - if (true === $value) { - $parts[] = $key; - } else { - if (preg_match('#[^a-zA-Z0-9._-]#', $value)) { - $value = '"'.$value.'"'; - } - $parts[] = "$key=$value"; - } - } - - return implode(', ', $parts); + return HeaderUtils::toString($this->cacheControl, ','); } /** @@ -320,12 +308,8 @@ class HeaderBag implements \IteratorAggregate, \Countable */ protected function parseCacheControl($header) { - $cacheControl = array(); - preg_match_all('#([a-zA-Z][a-zA-Z_-]*)\s*(?:=(?:"([^"]*)"|([^ \t",;]*)))?#', $header, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - $cacheControl[strtolower($match[1])] = isset($match[3]) ? $match[3] : (isset($match[2]) ? $match[2] : true); - } + $parts = HeaderUtils::split($header, ',='); - return $cacheControl; + return HeaderUtils::combine($parts); } } diff --git a/vendor/symfony/http-foundation/HeaderUtils.php b/vendor/symfony/http-foundation/HeaderUtils.php new file mode 100644 index 0000000000..637bc5be47 --- /dev/null +++ b/vendor/symfony/http-foundation/HeaderUtils.php @@ -0,0 +1,225 @@ +<?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; + +/** + * HTTP header utility functions. + * + * @author Christian Schmidt <github@chsc.dk> + */ +class HeaderUtils +{ + public const DISPOSITION_ATTACHMENT = 'attachment'; + public const DISPOSITION_INLINE = 'inline'; + + /** + * This class should not be instantiated. + */ + private function __construct() + { + } + + /** + * Splits an HTTP header by one or more separators. + * + * Example: + * + * HeaderUtils::split("da, en-gb;q=0.8", ",;") + * // => array(array('da'), array('en-gb', 'q=0.8')) + * + * @param string $header HTTP header value + * @param string $separators List of characters to split on, ordered by + * precedence, e.g. ",", ";=", or ",;=" + * + * @return array Nested array with as many levels as there are characters in + * $separators + */ + public static function split(string $header, string $separators): array + { + $quotedSeparators = preg_quote($separators, '/'); + + preg_match_all(' + / + (?!\s) + (?: + # quoted-string + "(?:[^"\\\\]|\\\\.)*(?:"|\\\\|$) + | + # token + [^"'.$quotedSeparators.']+ + )+ + (?<!\s) + | + # separator + \s* + (?<separator>['.$quotedSeparators.']) + \s* + /x', trim($header), $matches, PREG_SET_ORDER); + + return self::groupParts($matches, $separators); + } + + /** + * Combines an array of arrays into one associative array. + * + * Each of the nested arrays should have one or two elements. The first + * value will be used as the keys in the associative array, and the second + * will be used as the values, or true if the nested array only contains one + * element. Array keys are lowercased. + * + * Example: + * + * HeaderUtils::combine(array(array("foo", "abc"), array("bar"))) + * // => array("foo" => "abc", "bar" => true) + */ + public static function combine(array $parts): array + { + $assoc = array(); + foreach ($parts as $part) { + $name = strtolower($part[0]); + $value = $part[1] ?? true; + $assoc[$name] = $value; + } + + return $assoc; + } + + /** + * Joins an associative array into a string for use in an HTTP header. + * + * The key and value of each entry are joined with "=", and all entries + * are joined with the specified separator and an additional space (for + * readability). Values are quoted if necessary. + * + * Example: + * + * HeaderUtils::toString(array("foo" => "abc", "bar" => true, "baz" => "a b c"), ",") + * // => 'foo=abc, bar, baz="a b c"' + */ + public static function toString(array $assoc, string $separator): string + { + $parts = array(); + foreach ($assoc as $name => $value) { + if (true === $value) { + $parts[] = $name; + } else { + $parts[] = $name.'='.self::quote($value); + } + } + + return implode($separator.' ', $parts); + } + + /** + * Encodes a string as a quoted string, if necessary. + * + * If a string contains characters not allowed by the "token" construct in + * the HTTP specification, it is backslash-escaped and enclosed in quotes + * to match the "quoted-string" construct. + */ + public static function quote(string $s): string + { + if (preg_match('/^[a-z0-9!#$%&\'*.^_`|~-]+$/i', $s)) { + return $s; + } + + return '"'.addcslashes($s, '"\\"').'"'; + } + + /** + * Decodes a quoted string. + * + * If passed an unquoted string that matches the "token" construct (as + * defined in the HTTP specification), it is passed through verbatimly. + */ + public static function unquote(string $s): string + { + return preg_replace('/\\\\(.)|"/', '$1', $s); + } + + /** + * Generates a HTTP Content-Disposition field-value. + * + * @param string $disposition One of "inline" or "attachment" + * @param string $filename A unicode string + * @param string $filenameFallback A string containing only ASCII characters that + * is semantically equivalent to $filename. If the filename is already ASCII, + * it can be omitted, or just copied from $filename + * + * @return string A string suitable for use as a Content-Disposition field-value + * + * @throws \InvalidArgumentException + * + * @see RFC 6266 + */ + public static function makeDisposition(string $disposition, string $filename, string $filenameFallback = ''): string + { + if (!\in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) { + throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); + } + + if ('' === $filenameFallback) { + $filenameFallback = $filename; + } + + // filenameFallback is not ASCII. + if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) { + throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.'); + } + + // percent characters aren't safe in fallback. + if (false !== strpos($filenameFallback, '%')) { + throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.'); + } + + // path separators aren't allowed in either. + if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) { + throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.'); + } + + $params = array('filename' => $filenameFallback); + if ($filename !== $filenameFallback) { + $params['filename*'] = "utf-8''".rawurlencode($filename); + } + + return $disposition.'; '.self::toString($params, ';'); + } + + private static function groupParts(array $matches, string $separators): array + { + $separator = $separators[0]; + $partSeparators = substr($separators, 1); + + $i = 0; + $partMatches = array(); + foreach ($matches as $match) { + if (isset($match['separator']) && $match['separator'] === $separator) { + ++$i; + } else { + $partMatches[$i][] = $match; + } + } + + $parts = array(); + if ($partSeparators) { + foreach ($partMatches as $matches) { + $parts[] = self::groupParts($matches, $partSeparators); + } + } else { + foreach ($partMatches as $matches) { + $parts[] = self::unquote($matches[0][0]); + } + } + + return $parts; + } +} diff --git a/vendor/symfony/http-foundation/JsonResponse.php b/vendor/symfony/http-foundation/JsonResponse.php index d741ce099d..f10262e88e 100644 --- a/vendor/symfony/http-foundation/JsonResponse.php +++ b/vendor/symfony/http-foundation/JsonResponse.php @@ -39,7 +39,7 @@ class JsonResponse extends Response * @param array $headers An array of response headers * @param bool $json If the data is already a JSON string */ - public function __construct($data = null, $status = 200, $headers = array(), $json = false) + public function __construct($data = null, int $status = 200, array $headers = array(), bool $json = false) { parent::__construct('', $status, $headers); @@ -139,29 +139,13 @@ class JsonResponse extends Response */ public function setData($data = array()) { - if (\defined('HHVM_VERSION')) { - // HHVM does not trigger any warnings and let exceptions - // thrown from a JsonSerializable object pass through. - // If only PHP did the same... + try { $data = json_encode($data, $this->encodingOptions); - } else { - if (!interface_exists('JsonSerializable', false)) { - set_error_handler(function () { return false; }); - try { - $data = @json_encode($data, $this->encodingOptions); - } finally { - restore_error_handler(); - } - } else { - try { - $data = json_encode($data, $this->encodingOptions); - } catch (\Exception $e) { - if ('Exception' === \get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) { - throw $e->getPrevious() ?: $e; - } - throw $e; - } + } catch (\Exception $e) { + if ('Exception' === \get_class($e) && 0 === strpos($e->getMessage(), 'Failed calling ')) { + throw $e->getPrevious() ?: $e; } + throw $e; } if (JSON_ERROR_NONE !== json_last_error()) { diff --git a/vendor/symfony/http-foundation/ParameterBag.php b/vendor/symfony/http-foundation/ParameterBag.php index e3be0a9b8b..19d7ee913a 100644 --- a/vendor/symfony/http-foundation/ParameterBag.php +++ b/vendor/symfony/http-foundation/ParameterBag.php @@ -174,7 +174,7 @@ class ParameterBag implements \IteratorAggregate, \Countable * Returns the parameter value converted to boolean. * * @param string $key The parameter key - * @param mixed $default The default value if the parameter key does not exist + * @param bool $default The default value if the parameter key does not exist * * @return bool The filtered value */ diff --git a/vendor/symfony/http-foundation/RedirectResponse.php b/vendor/symfony/http-foundation/RedirectResponse.php index 01681dcdf7..11f71a0342 100644 --- a/vendor/symfony/http-foundation/RedirectResponse.php +++ b/vendor/symfony/http-foundation/RedirectResponse.php @@ -32,7 +32,7 @@ class RedirectResponse extends Response * * @see http://tools.ietf.org/html/rfc2616#section-10.3 */ - public function __construct($url, $status = 302, $headers = array()) + public function __construct(?string $url, int $status = 302, array $headers = array()) { parent::__construct('', $status, $headers); diff --git a/vendor/symfony/http-foundation/Request.php b/vendor/symfony/http-foundation/Request.php index e84e0ba6e5..51940b8de7 100644 --- a/vendor/symfony/http-foundation/Request.php +++ b/vendor/symfony/http-foundation/Request.php @@ -38,15 +38,6 @@ class Request const HEADER_X_FORWARDED_ALL = 0b11110; // All "X-Forwarded-*" headers const HEADER_X_FORWARDED_AWS_ELB = 0b11010; // AWS ELB doesn't send X-Forwarded-Host - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_IP = self::HEADER_X_FORWARDED_FOR; - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_HOST = self::HEADER_X_FORWARDED_HOST; - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_PROTO = self::HEADER_X_FORWARDED_PROTO; - /** @deprecated since version 3.3, to be removed in 4.0 */ - const HEADER_CLIENT_PORT = self::HEADER_X_FORWARDED_PORT; - const METHOD_HEAD = 'HEAD'; const METHOD_GET = 'GET'; const METHOD_POST = 'POST'; @@ -73,25 +64,6 @@ class Request */ protected static $trustedHosts = array(); - /** - * Names for headers that can be trusted when - * using trusted proxies. - * - * The FORWARDED header is the standard as of rfc7239. - * - * The other headers are non-standard, but widely used - * by popular reverse proxies (like Apache mod_proxy or Amazon EC2). - * - * @deprecated since version 3.3, to be removed in 4.0 - */ - protected static $trustedHeaders = array( - self::HEADER_FORWARDED => 'FORWARDED', - self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', - self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', - self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', - self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ); - protected static $httpMethodParameterOverride = false; /** @@ -225,15 +197,6 @@ class Request private static $trustedHeaderSet = -1; - /** @deprecated since version 3.3, to be removed in 4.0 */ - private static $trustedHeaderNames = array( - self::HEADER_FORWARDED => 'FORWARDED', - self::HEADER_CLIENT_IP => 'X_FORWARDED_FOR', - self::HEADER_CLIENT_HOST => 'X_FORWARDED_HOST', - self::HEADER_CLIENT_PROTO => 'X_FORWARDED_PROTO', - self::HEADER_CLIENT_PORT => 'X_FORWARDED_PORT', - ); - private static $forwardedParams = array( self::HEADER_X_FORWARDED_FOR => 'for', self::HEADER_X_FORWARDED_HOST => 'host', @@ -242,6 +205,23 @@ class Request ); /** + * Names for headers that can be trusted when + * using trusted proxies. + * + * The FORWARDED header is the standard as of rfc7239. + * + * The other headers are non-standard, but widely used + * by popular reverse proxies (like Apache mod_proxy or Amazon EC2). + */ + private static $trustedHeaders = array( + self::HEADER_FORWARDED => 'FORWARDED', + self::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', + self::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', + self::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', + self::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', + ); + + /** * @param array $query The GET parameters * @param array $request The POST parameters * @param array $attributes The request attributes (parameters parsed from the PATH_INFO, ...) @@ -298,20 +278,7 @@ class Request */ public static function createFromGlobals() { - // With the php's bug #66606, the php's built-in web server - // stores the Content-Type and Content-Length header values in - // HTTP_CONTENT_TYPE and HTTP_CONTENT_LENGTH fields. - $server = $_SERVER; - if ('cli-server' === \PHP_SAPI) { - if (array_key_exists('HTTP_CONTENT_LENGTH', $_SERVER)) { - $server['CONTENT_LENGTH'] = $_SERVER['HTTP_CONTENT_LENGTH']; - } - if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER)) { - $server['CONTENT_TYPE'] = $_SERVER['HTTP_CONTENT_TYPE']; - } - } - - $request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $server); + $request = self::createRequestFromFactory($_GET, $_POST, array(), $_COOKIE, $_FILES, $_SERVER); if (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded') && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), array('PUT', 'DELETE', 'PATCH')) @@ -345,7 +312,7 @@ class Request 'SERVER_NAME' => 'localhost', 'SERVER_PORT' => 80, 'HTTP_HOST' => 'localhost', - 'HTTP_USER_AGENT' => 'Symfony/3.X', + 'HTTP_USER_AGENT' => 'Symfony', 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_ACCEPT_LANGUAGE' => 'en-us,en;q=0.5', 'HTTP_ACCEPT_CHARSET' => 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', @@ -578,10 +545,13 @@ class Request $requestOrder = ini_get('request_order') ?: ini_get('variables_order'); $requestOrder = preg_replace('#[^cgp]#', '', strtolower($requestOrder)) ?: 'gp'; - $_REQUEST = array(); + $_REQUEST = array(array()); + foreach (str_split($requestOrder) as $order) { - $_REQUEST = array_merge($_REQUEST, $request[$order]); + $_REQUEST[] = $request[$order]; } + + $_REQUEST = array_merge(...$_REQUEST); } /** @@ -594,20 +564,9 @@ class Request * * @throws \InvalidArgumentException When $trustedHeaderSet is invalid */ - public static function setTrustedProxies(array $proxies/*, int $trustedHeaderSet*/) + public static function setTrustedProxies(array $proxies, int $trustedHeaderSet) { self::$trustedProxies = $proxies; - - if (2 > \func_num_args()) { - @trigger_error(sprintf('The %s() method expects a bit field of Request::HEADER_* as second argument since Symfony 3.3. Defining it will be required in 4.0. ', __METHOD__), E_USER_DEPRECATED); - - return; - } - $trustedHeaderSet = (int) func_get_arg(1); - - foreach (self::$trustedHeaderNames as $header => $name) { - self::$trustedHeaders[$header] = $header & $trustedHeaderSet ? $name : null; - } self::$trustedHeaderSet = $trustedHeaderSet; } @@ -658,78 +617,6 @@ class Request } /** - * Sets the name for trusted headers. - * - * The following header keys are supported: - * - * * Request::HEADER_CLIENT_IP: defaults to X-Forwarded-For (see getClientIp()) - * * Request::HEADER_CLIENT_HOST: defaults to X-Forwarded-Host (see getHost()) - * * Request::HEADER_CLIENT_PORT: defaults to X-Forwarded-Port (see getPort()) - * * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure()) - * * Request::HEADER_FORWARDED: defaults to Forwarded (see RFC 7239) - * - * Setting an empty value allows to disable the trusted header for the given key. - * - * @param string $key The header key - * @param string $value The header name - * - * @throws \InvalidArgumentException - * - * @deprecated since version 3.3, to be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead. - */ - public static function setTrustedHeaderName($key, $value) - { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead.', __METHOD__), E_USER_DEPRECATED); - - if ('forwarded' === $key) { - $key = self::HEADER_FORWARDED; - } elseif ('client_ip' === $key) { - $key = self::HEADER_CLIENT_IP; - } elseif ('client_host' === $key) { - $key = self::HEADER_CLIENT_HOST; - } elseif ('client_proto' === $key) { - $key = self::HEADER_CLIENT_PROTO; - } elseif ('client_port' === $key) { - $key = self::HEADER_CLIENT_PORT; - } elseif (!array_key_exists($key, self::$trustedHeaders)) { - throw new \InvalidArgumentException(sprintf('Unable to set the trusted header name for key "%s".', $key)); - } - - self::$trustedHeaders[$key] = $value; - - if (null !== $value) { - self::$trustedHeaderNames[$key] = $value; - self::$trustedHeaderSet |= $key; - } else { - self::$trustedHeaderSet &= ~$key; - } - } - - /** - * Gets the trusted proxy header name. - * - * @param string $key The header key - * - * @return string The header name - * - * @throws \InvalidArgumentException - * - * @deprecated since version 3.3, to be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead. - */ - public static function getTrustedHeaderName($key) - { - if (2 > \func_num_args() || func_get_arg(1)) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the Request::getTrustedHeaderSet() method instead.', __METHOD__), E_USER_DEPRECATED); - } - - if (!array_key_exists($key, self::$trustedHeaders)) { - throw new \InvalidArgumentException(sprintf('Unable to get the trusted header name for key "%s".', $key)); - } - - return self::$trustedHeaders[$key]; - } - - /** * Normalizes a query string. * * It builds a normalized query string, where keys/value pairs are alphabetized, @@ -745,31 +632,10 @@ class Request return ''; } - $parts = array(); - $order = array(); + parse_str($qs, $qs); + ksort($qs); - foreach (explode('&', $qs) as $param) { - if ('' === $param || '=' === $param[0]) { - // Ignore useless delimiters, e.g. "x=y&". - // Also ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway. - // PHP also does not include them when building _GET. - continue; - } - - $keyValuePair = explode('=', $param, 2); - - // GET parameters, that are submitted from a HTML form, encode spaces as "+" by default (as defined in enctype application/x-www-form-urlencoded). - // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. This is why we use urldecode and then normalize to - // RFC 3986 with rawurlencode. - $parts[] = isset($keyValuePair[1]) ? - rawurlencode(urldecode($keyValuePair[0])).'='.rawurlencode(urldecode($keyValuePair[1])) : - rawurlencode(urldecode($keyValuePair[0])); - $order[] = urldecode($keyValuePair[0]); - } - - array_multisort($order, SORT_ASC, $parts); - - return implode('&', $parts); + return http_build_query($qs, '', '&', PHP_QUERY_RFC3986); } /** @@ -836,7 +702,17 @@ class Request */ public function getSession() { - return $this->session; + $session = $this->session; + if (!$session instanceof SessionInterface && null !== $session) { + $this->setSession($session = $session()); + } + + if (null === $session) { + @trigger_error(sprintf('Calling "%s()" when no session has been set is deprecated since Symfony 4.1 and will throw an exception in 5.0. Use "hasSession()" instead.', __METHOD__), E_USER_DEPRECATED); + // throw new \BadMethodCallException('Session has not been set'); + } + + return $session; } /** @@ -848,7 +724,7 @@ class Request public function hasPreviousSession() { // the check for $this->session avoids malicious users trying to fake a session cookie with proper name - return $this->hasSession() && $this->cookies->has($this->session->getName()); + return $this->hasSession() && $this->cookies->has($this->getSession()->getName()); } /** @@ -876,6 +752,14 @@ class Request } /** + * @internal + */ + public function setSessionFactory(callable $factory) + { + $this->session = $factory; + } + + /** * Returns the client IP addresses. * * In the returned array the most trusted IP address is first, and the @@ -896,7 +780,7 @@ class Request return array($ip); } - return $this->getTrustedValues(self::HEADER_CLIENT_IP, $ip) ?: array($ip); + return $this->getTrustedValues(self::HEADER_X_FORWARDED_FOR, $ip) ?: array($ip); } /** @@ -908,10 +792,6 @@ class Request * being the original client, and each successive proxy that passed the request * adding the IP address where it received the request from. * - * If your reverse proxy uses a different header name than "X-Forwarded-For", - * ("Client-Ip" for instance), configure it via the $trustedHeaderSet - * argument of the Request::setTrustedProxies() method instead. - * * @return string|null The client IP address * * @see getClientIps() @@ -1015,17 +895,13 @@ class Request * * The "X-Forwarded-Port" header must contain the client port. * - * If your reverse proxy uses a different header name than "X-Forwarded-Port", - * configure it via via the $trustedHeaderSet argument of the - * Request::setTrustedProxies() method instead. - * * @return int|string can be a string if fetched from the server bag */ public function getPort() { - if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_PORT)) { + if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_PORT)) { $host = $host[0]; - } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) { + } elseif ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) { $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { return $this->server->get('SERVER_PORT'); @@ -1233,15 +1109,11 @@ class Request * * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http". * - * If your reverse proxy uses a different header name than "X-Forwarded-Proto" - * ("SSL_HTTPS" for instance), configure it via the $trustedHeaderSet - * argument of the Request::setTrustedProxies() method instead. - * * @return bool */ public function isSecure() { - if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_CLIENT_PROTO)) { + if ($this->isFromTrustedProxy() && $proto = $this->getTrustedValues(self::HEADER_X_FORWARDED_PROTO)) { return \in_array(strtolower($proto[0]), array('https', 'on', 'ssl', '1'), true); } @@ -1258,17 +1130,13 @@ class Request * * The "X-Forwarded-Host" header must contain the client host name. * - * If your reverse proxy uses a different header name than "X-Forwarded-Host", - * configure it via the $trustedHeaderSet argument of the - * Request::setTrustedProxies() method instead. - * * @return string * * @throws SuspiciousOperationException when the host name is invalid or not trusted */ public function getHost() { - if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_CLIENT_HOST)) { + if ($this->isFromTrustedProxy() && $host = $this->getTrustedValues(self::HEADER_X_FORWARDED_HOST)) { $host = $host[0]; } elseif (!$host = $this->headers->get('HOST')) { if (!$host = $this->server->get('SERVER_NAME')) { @@ -1419,7 +1287,7 @@ class Request { $canonicalMimeType = null; if (false !== $pos = strpos($mimeType, ';')) { - $canonicalMimeType = substr($mimeType, 0, $pos); + $canonicalMimeType = trim(substr($mimeType, 0, $pos)); } if (null === static::$formats) { @@ -1561,11 +1429,8 @@ class Request public function isMethodSafe(/* $andCacheable = true */) { if (!\func_num_args() || func_get_arg(0)) { - // This deprecation should be turned into a BadMethodCallException in 4.0 (without adding the argument in the signature) - // then setting $andCacheable to false should be deprecated in 4.1 - @trigger_error('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead.', E_USER_DEPRECATED); - - return \in_array($this->getMethod(), array('GET', 'HEAD')); + // setting $andCacheable to false should be deprecated in 4.1 + throw new \BadMethodCallException('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is not supported.'); } return \in_array($this->getMethod(), array('GET', 'HEAD', 'OPTIONS', 'TRACE')); @@ -1586,7 +1451,7 @@ class Request * * @see https://tools.ietf.org/html/rfc7231#section-4.2.3 * - * @return bool + * @return bool True for GET and HEAD, false otherwise */ public function isMethodCacheable() { @@ -1629,9 +1494,6 @@ class Request public function getContent($asResource = false) { $currentContentIsResource = \is_resource($this->content); - if (\PHP_VERSION_ID < 50600 && false === $this->content) { - throw new \LogicException('getContent() can only be called once when using the resource return type and PHP below 5.6.'); - } if (true === $asResource) { if ($currentContentIsResource) { @@ -1836,10 +1698,16 @@ class Request $this->server->remove('IIS_WasUrlRewritten'); } elseif ($this->server->has('REQUEST_URI')) { $requestUri = $this->server->get('REQUEST_URI'); + // HTTP proxy reqs setup request URI with scheme and host [and port] + the URL path, only use URL path - $schemeAndHttpHost = $this->getSchemeAndHttpHost(); - if (0 === strpos($requestUri, $schemeAndHttpHost)) { - $requestUri = substr($requestUri, \strlen($schemeAndHttpHost)); + $uriComponents = parse_url($requestUri); + + if (isset($uriComponents['path'])) { + $requestUri = $uriComponents['path']; + } + + if (isset($uriComponents['query'])) { + $requestUri .= '?'.$uriComponents['query']; } } elseif ($this->server->has('ORIG_PATH_INFO')) { // IIS 5.0, PHP as CGI @@ -2003,12 +1871,7 @@ class Request ); } - /** - * Sets the default PHP locale. - * - * @param string $locale - */ - private function setPhpDefaultLocale($locale) + private function setPhpDefaultLocale(string $locale) { // if either the class Locale doesn't exist, or an exception is thrown when // setting the default locale, the intl module is not installed, and @@ -2025,12 +1888,9 @@ class Request * Returns the prefix as encoded in the string when the string starts with * the given prefix, false otherwise. * - * @param string $string The urlencoded string - * @param string $prefix The prefix not encoded - * * @return string|false The prefix as it is encoded in $string, or false */ - private function getUrlencodedPrefix($string, $prefix) + private function getUrlencodedPrefix(string $string, string $prefix) { if (0 !== strpos(rawurldecode($string), $prefix)) { return false; @@ -2078,22 +1938,28 @@ class Request $clientValues = array(); $forwardedValues = array(); - if (self::$trustedHeaders[$type] && $this->headers->has(self::$trustedHeaders[$type])) { + if ((self::$trustedHeaderSet & $type) && $this->headers->has(self::$trustedHeaders[$type])) { foreach (explode(',', $this->headers->get(self::$trustedHeaders[$type])) as $v) { - $clientValues[] = (self::HEADER_CLIENT_PORT === $type ? '0.0.0.0:' : '').trim($v); + $clientValues[] = (self::HEADER_X_FORWARDED_PORT === $type ? '0.0.0.0:' : '').trim($v); } } - if (self::$trustedHeaders[self::HEADER_FORWARDED] && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) { - $forwardedValues = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); - $forwardedValues = preg_match_all(sprintf('{(?:%s)="?([a-zA-Z0-9\.:_\-/\[\]]*+)}', self::$forwardedParams[$type]), $forwardedValues, $matches) ? $matches[1] : array(); - if (self::HEADER_CLIENT_PORT === $type) { - foreach ($forwardedValues as $k => $v) { + if ((self::$trustedHeaderSet & self::HEADER_FORWARDED) && $this->headers->has(self::$trustedHeaders[self::HEADER_FORWARDED])) { + $forwarded = $this->headers->get(self::$trustedHeaders[self::HEADER_FORWARDED]); + $parts = HeaderUtils::split($forwarded, ',;='); + $forwardedValues = array(); + $param = self::$forwardedParams[$type]; + foreach ($parts as $subParts) { + if (null === $v = HeaderUtils::combine($subParts)[$param] ?? null) { + continue; + } + if (self::HEADER_X_FORWARDED_PORT === $type) { if (']' === substr($v, -1) || false === $v = strrchr($v, ':')) { $v = $this->isSecure() ? ':443' : ':80'; } - $forwardedValues[$k] = '0.0.0.0'.$v; + $v = '0.0.0.0'.$v; } + $forwardedValues[] = $v; } } diff --git a/vendor/symfony/http-foundation/RequestMatcher.php b/vendor/symfony/http-foundation/RequestMatcher.php index 6b4cef147d..ab9434f43f 100644 --- a/vendor/symfony/http-foundation/RequestMatcher.php +++ b/vendor/symfony/http-foundation/RequestMatcher.php @@ -29,6 +29,11 @@ class RequestMatcher implements RequestMatcherInterface private $host; /** + * @var int|null + */ + private $port; + + /** * @var string[] */ private $methods = array(); @@ -56,13 +61,14 @@ class RequestMatcher implements RequestMatcherInterface * @param array $attributes * @param string|string[]|null $schemes */ - public function __construct($path = null, $host = null, $methods = null, $ips = null, array $attributes = array(), $schemes = null) + public function __construct(string $path = null, string $host = null, $methods = null, $ips = null, array $attributes = array(), $schemes = null, int $port = null) { $this->matchPath($path); $this->matchHost($host); $this->matchMethod($methods); $this->matchIps($ips); $this->matchScheme($schemes); + $this->matchPort($port); foreach ($attributes as $k => $v) { $this->matchAttribute($k, $v); @@ -90,6 +96,16 @@ class RequestMatcher implements RequestMatcherInterface } /** + * Adds a check for the the URL port. + * + * @param int|null $port The port number to connect to + */ + public function matchPort(int $port = null) + { + $this->port = $port; + } + + /** * Adds a check for the URL path info. * * @param string|null $regexp A Regexp @@ -167,6 +183,10 @@ class RequestMatcher implements RequestMatcherInterface return false; } + if (null !== $this->port && 0 < $this->port && $request->getPort() !== $this->port) { + return false; + } + if (IpUtils::checkIp($request->getClientIp(), $this->ips)) { return true; } diff --git a/vendor/symfony/http-foundation/Response.php b/vendor/symfony/http-foundation/Response.php index 832260a51e..7c96212603 100644 --- a/vendor/symfony/http-foundation/Response.php +++ b/vendor/symfony/http-foundation/Response.php @@ -194,13 +194,9 @@ class Response ); /** - * @param mixed $content The response content, see setContent() - * @param int $status The response status code - * @param array $headers An array of response headers - * * @throws \InvalidArgumentException When the HTTP status code is not valid */ - public function __construct($content = '', $status = 200, $headers = array()) + public function __construct($content = '', int $status = 200, array $headers = array()) { $this->headers = new ResponseHeaderBag($headers); $this->setContent($content); @@ -317,6 +313,12 @@ class Response $this->ensureIEOverSSLCompatibility($request); + if ($request->isSecure()) { + foreach ($headers->getCookies() as $cookie) { + $cookie->setSecureDefault(true); + } + } + return $this; } @@ -334,8 +336,9 @@ class Response // headers foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) { + $replace = 0 === strcasecmp($name, 'Content-Type'); foreach ($values as $value) { - header($name.': '.$value, false, $this->statusCode); + header($name.': '.$value, $replace, $this->statusCode); } } @@ -416,13 +419,11 @@ class Response /** * Sets the HTTP protocol version (1.0 or 1.1). * - * @param string $version The HTTP protocol version - * * @return $this * - * @final since version 3.2 + * @final */ - public function setProtocolVersion($version) + public function setProtocolVersion(string $version) { $this->version = $version; @@ -432,11 +433,9 @@ class Response /** * Gets the HTTP protocol version. * - * @return string The HTTP protocol version - * - * @final since version 3.2 + * @final */ - public function getProtocolVersion() + public function getProtocolVersion(): string { return $this->version; } @@ -447,18 +446,15 @@ class Response * If the status text is null it will be automatically populated for the known * status codes and left empty otherwise. * - * @param int $code HTTP status code - * @param mixed $text HTTP status text - * * @return $this * * @throws \InvalidArgumentException When the HTTP status code is not valid * - * @final since version 3.2 + * @final */ - public function setStatusCode($code, $text = null) + public function setStatusCode(int $code, $text = null) { - $this->statusCode = $code = (int) $code; + $this->statusCode = $code; if ($this->isInvalid()) { throw new \InvalidArgumentException(sprintf('The HTTP status code "%s" is not valid.', $code)); } @@ -483,11 +479,9 @@ class Response /** * Retrieves the status code for the current web response. * - * @return int Status code - * - * @final since version 3.2 + * @final */ - public function getStatusCode() + public function getStatusCode(): int { return $this->statusCode; } @@ -495,13 +489,11 @@ class Response /** * Sets the response charset. * - * @param string $charset Character set - * * @return $this * - * @final since version 3.2 + * @final */ - public function setCharset($charset) + public function setCharset(string $charset) { $this->charset = $charset; @@ -511,11 +503,9 @@ class Response /** * Retrieves the response charset. * - * @return string Character set - * - * @final since version 3.2 + * @final */ - public function getCharset() + public function getCharset(): ?string { return $this->charset; } @@ -535,11 +525,9 @@ class Response * can be reused by a cache with heuristic expiration unless otherwise indicated" * (https://tools.ietf.org/html/rfc7231#section-6.1) * - * @return bool true if the response is worth caching, false otherwise - * - * @final since version 3.3 + * @final */ - public function isCacheable() + public function isCacheable(): bool { if (!\in_array($this->statusCode, array(200, 203, 300, 301, 302, 404, 410))) { return false; @@ -559,11 +547,9 @@ class Response * origin. A response is considered fresh when it includes a Cache-Control/max-age * indicator or Expires header and the calculated age is less than the freshness lifetime. * - * @return bool true if the response is fresh, false otherwise - * - * @final since version 3.3 + * @final */ - public function isFresh() + public function isFresh(): bool { return $this->getTtl() > 0; } @@ -572,11 +558,9 @@ class Response * Returns true if the response includes headers that can be used to validate * the response with the origin server using a conditional GET request. * - * @return bool true if the response is validateable, false otherwise - * - * @final since version 3.3 + * @final */ - public function isValidateable() + public function isValidateable(): bool { return $this->headers->has('Last-Modified') || $this->headers->has('ETag'); } @@ -588,7 +572,7 @@ class Response * * @return $this * - * @final since version 3.2 + * @final */ public function setPrivate() { @@ -605,7 +589,7 @@ class Response * * @return $this * - * @final since version 3.2 + * @final */ public function setPublic() { @@ -618,13 +602,11 @@ class Response /** * Marks the response as "immutable". * - * @param bool $immutable enables or disables the immutable directive - * * @return $this * * @final */ - public function setImmutable($immutable = true) + public function setImmutable(bool $immutable = true) { if ($immutable) { $this->headers->addCacheControlDirective('immutable'); @@ -638,11 +620,9 @@ class Response /** * Returns true if the response is marked as "immutable". * - * @return bool returns true if the response is marked as "immutable"; otherwise false - * * @final */ - public function isImmutable() + public function isImmutable(): bool { return $this->headers->hasCacheControlDirective('immutable'); } @@ -655,11 +635,9 @@ class Response * When present, the TTL of the response should not be overridden to be * greater than the value provided by the origin. * - * @return bool true if the response must be revalidated by a cache, false otherwise - * - * @final since version 3.3 + * @final */ - public function mustRevalidate() + public function mustRevalidate(): bool { return $this->headers->hasCacheControlDirective('must-revalidate') || $this->headers->hasCacheControlDirective('proxy-revalidate'); } @@ -667,13 +645,11 @@ class Response /** * Returns the Date header as a DateTime instance. * - * @return \DateTime A \DateTime instance - * * @throws \RuntimeException When the header is not parseable * - * @final since version 3.2 + * @final */ - public function getDate() + public function getDate(): ?\DateTimeInterface { return $this->headers->getDate('Date'); } @@ -683,24 +659,26 @@ class Response * * @return $this * - * @final since version 3.2 + * @final */ - public function setDate(\DateTime $date) + public function setDate(\DateTimeInterface $date) { - $date->setTimezone(new \DateTimeZone('UTC')); + if ($date instanceof \DateTime) { + $date = \DateTimeImmutable::createFromMutable($date); + } + + $date = $date->setTimezone(new \DateTimeZone('UTC')); $this->headers->set('Date', $date->format('D, d M Y H:i:s').' GMT'); return $this; } /** - * Returns the age of the response. - * - * @return int The age of the response in seconds + * Returns the age of the response in seconds. * - * @final since version 3.2 + * @final */ - public function getAge() + public function getAge(): int { if (null !== $age = $this->headers->get('Age')) { return (int) $age; @@ -727,17 +705,15 @@ class Response /** * Returns the value of the Expires header as a DateTime instance. * - * @return \DateTime|null A DateTime instance or null if the header does not exist - * - * @final since version 3.2 + * @final */ - public function getExpires() + public function getExpires(): ?\DateTimeInterface { try { return $this->headers->getDate('Expires'); } catch (\RuntimeException $e) { // according to RFC 2616 invalid date formats (e.g. "0" and "-1") must be treated as in the past - return \DateTime::createFromFormat(DATE_RFC2822, 'Sat, 01 Jan 00 00:00:00 +0000'); + return \DateTime::createFromFormat('U', time() - 172800); } } @@ -746,22 +722,25 @@ class Response * * Passing null as value will remove the header. * - * @param \DateTime|null $date A \DateTime instance or null to remove the header - * * @return $this * - * @final since version 3.2 + * @final */ - public function setExpires(\DateTime $date = null) + public function setExpires(\DateTimeInterface $date = null) { if (null === $date) { $this->headers->remove('Expires'); - } else { - $date = clone $date; - $date->setTimezone(new \DateTimeZone('UTC')); - $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); + + return $this; } + if ($date instanceof \DateTime) { + $date = \DateTimeImmutable::createFromMutable($date); + } + + $date = $date->setTimezone(new \DateTimeZone('UTC')); + $this->headers->set('Expires', $date->format('D, d M Y H:i:s').' GMT'); + return $this; } @@ -772,11 +751,9 @@ class Response * First, it checks for a s-maxage directive, then a max-age directive, and then it falls * back on an expires header. It returns null when no maximum age can be established. * - * @return int|null Number of seconds - * - * @final since version 3.2 + * @final */ - public function getMaxAge() + public function getMaxAge(): ?int { if ($this->headers->hasCacheControlDirective('s-maxage')) { return (int) $this->headers->getCacheControlDirective('s-maxage'); @@ -787,8 +764,10 @@ class Response } if (null !== $this->getExpires()) { - return $this->getExpires()->format('U') - $this->getDate()->format('U'); + return (int) ($this->getExpires()->format('U') - $this->getDate()->format('U')); } + + return null; } /** @@ -796,13 +775,11 @@ class Response * * This methods sets the Cache-Control max-age directive. * - * @param int $value Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setMaxAge($value) + public function setMaxAge(int $value) { $this->headers->addCacheControlDirective('max-age', $value); @@ -814,13 +791,11 @@ class Response * * This methods sets the Cache-Control s-maxage directive. * - * @param int $value Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setSharedMaxAge($value) + public function setSharedMaxAge(int $value) { $this->setPublic(); $this->headers->addCacheControlDirective('s-maxage', $value); @@ -836,29 +811,25 @@ class Response * When the responses TTL is <= 0, the response may not be served from cache without first * revalidating with the origin. * - * @return int|null The TTL in seconds - * - * @final since version 3.2 + * @final */ - public function getTtl() + public function getTtl(): ?int { - if (null !== $maxAge = $this->getMaxAge()) { - return $maxAge - $this->getAge(); - } + $maxAge = $this->getMaxAge(); + + return null !== $maxAge ? $maxAge - $this->getAge() : null; } /** - * Sets the response's time-to-live for shared caches. + * Sets the response's time-to-live for shared caches in seconds. * * This method adjusts the Cache-Control/s-maxage directive. * - * @param int $seconds Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setTtl($seconds) + public function setTtl(int $seconds) { $this->setSharedMaxAge($this->getAge() + $seconds); @@ -866,17 +837,15 @@ class Response } /** - * Sets the response's time-to-live for private/client caches. + * Sets the response's time-to-live for private/client caches in seconds. * * This method adjusts the Cache-Control/max-age directive. * - * @param int $seconds Number of seconds - * * @return $this * - * @final since version 3.2 + * @final */ - public function setClientTtl($seconds) + public function setClientTtl(int $seconds) { $this->setMaxAge($this->getAge() + $seconds); @@ -886,13 +855,11 @@ class Response /** * Returns the Last-Modified HTTP header as a DateTime instance. * - * @return \DateTime|null A DateTime instance or null if the header does not exist - * * @throws \RuntimeException When the HTTP header is not parseable * - * @final since version 3.2 + * @final */ - public function getLastModified() + public function getLastModified(): ?\DateTimeInterface { return $this->headers->getDate('Last-Modified'); } @@ -902,33 +869,34 @@ class Response * * Passing null as value will remove the header. * - * @param \DateTime|null $date A \DateTime instance or null to remove the header - * * @return $this * - * @final since version 3.2 + * @final */ - public function setLastModified(\DateTime $date = null) + public function setLastModified(\DateTimeInterface $date = null) { if (null === $date) { $this->headers->remove('Last-Modified'); - } else { - $date = clone $date; - $date->setTimezone(new \DateTimeZone('UTC')); - $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); + + return $this; } + if ($date instanceof \DateTime) { + $date = \DateTimeImmutable::createFromMutable($date); + } + + $date = $date->setTimezone(new \DateTimeZone('UTC')); + $this->headers->set('Last-Modified', $date->format('D, d M Y H:i:s').' GMT'); + return $this; } /** * Returns the literal value of the ETag HTTP header. * - * @return string|null The ETag HTTP header or null if it does not exist - * - * @final since version 3.2 + * @final */ - public function getEtag() + public function getEtag(): ?string { return $this->headers->get('ETag'); } @@ -941,9 +909,9 @@ class Response * * @return $this * - * @final since version 3.2 + * @final */ - public function setEtag($etag = null, $weak = false) + public function setEtag(string $etag = null, bool $weak = false) { if (null === $etag) { $this->headers->remove('Etag'); @@ -963,13 +931,11 @@ class Response * * Available options are: etag, last_modified, max_age, s_maxage, private, public and immutable. * - * @param array $options An array of cache options - * * @return $this * * @throws \InvalidArgumentException * - * @final since version 3.3 + * @final */ public function setCache(array $options) { @@ -1026,7 +992,7 @@ class Response * * @see http://tools.ietf.org/html/rfc2616#section-10.3.5 * - * @final since version 3.3 + * @final */ public function setNotModified() { @@ -1044,11 +1010,9 @@ class Response /** * Returns true if the response includes a Vary header. * - * @return bool true if the response includes a Vary header, false otherwise - * - * @final since version 3.2 + * @final */ - public function hasVary() + public function hasVary(): bool { return null !== $this->headers->get('Vary'); } @@ -1056,11 +1020,9 @@ class Response /** * Returns an array of header names given in the Vary header. * - * @return array An array of Vary names - * - * @final since version 3.2 + * @final */ - public function getVary() + public function getVary(): array { if (!$vary = $this->headers->get('Vary', null, false)) { return array(); @@ -1082,9 +1044,9 @@ class Response * * @return $this * - * @final since version 3.2 + * @final */ - public function setVary($headers, $replace = true) + public function setVary($headers, bool $replace = true) { $this->headers->set('Vary', $headers, $replace); @@ -1100,9 +1062,9 @@ class Response * * @return bool true if the Response validators match the Request, false otherwise * - * @final since version 3.3 + * @final */ - public function isNotModified(Request $request) + public function isNotModified(Request $request): bool { if (!$request->isMethodCacheable()) { return false; @@ -1130,13 +1092,11 @@ class Response /** * Is response invalid? * - * @return bool - * * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html * - * @final since version 3.2 + * @final */ - public function isInvalid() + public function isInvalid(): bool { return $this->statusCode < 100 || $this->statusCode >= 600; } @@ -1144,11 +1104,9 @@ class Response /** * Is response informative? * - * @return bool - * - * @final since version 3.3 + * @final */ - public function isInformational() + public function isInformational(): bool { return $this->statusCode >= 100 && $this->statusCode < 200; } @@ -1156,11 +1114,9 @@ class Response /** * Is response successful? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isSuccessful() + public function isSuccessful(): bool { return $this->statusCode >= 200 && $this->statusCode < 300; } @@ -1168,11 +1124,9 @@ class Response /** * Is the response a redirect? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isRedirection() + public function isRedirection(): bool { return $this->statusCode >= 300 && $this->statusCode < 400; } @@ -1180,11 +1134,9 @@ class Response /** * Is there a client error? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isClientError() + public function isClientError(): bool { return $this->statusCode >= 400 && $this->statusCode < 500; } @@ -1192,11 +1144,9 @@ class Response /** * Was there a server side error? * - * @return bool - * - * @final since version 3.3 + * @final */ - public function isServerError() + public function isServerError(): bool { return $this->statusCode >= 500 && $this->statusCode < 600; } @@ -1204,11 +1154,9 @@ class Response /** * Is the response OK? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isOk() + public function isOk(): bool { return 200 === $this->statusCode; } @@ -1216,11 +1164,9 @@ class Response /** * Is the response forbidden? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isForbidden() + public function isForbidden(): bool { return 403 === $this->statusCode; } @@ -1228,11 +1174,9 @@ class Response /** * Is the response a not found error? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isNotFound() + public function isNotFound(): bool { return 404 === $this->statusCode; } @@ -1240,13 +1184,9 @@ class Response /** * Is the response a redirect of some form? * - * @param string $location - * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isRedirect($location = null) + public function isRedirect(string $location = null): bool { return \in_array($this->statusCode, array(201, 301, 302, 303, 307, 308)) && (null === $location ?: $location == $this->headers->get('Location')); } @@ -1254,11 +1194,9 @@ class Response /** * Is the response empty? * - * @return bool - * - * @final since version 3.2 + * @final */ - public function isEmpty() + public function isEmpty(): bool { return \in_array($this->statusCode, array(204, 304)); } @@ -1268,17 +1206,13 @@ class Response * * Resulting level can be greater than target level if a non-removable buffer has been encountered. * - * @param int $targetLevel The target output buffering level - * @param bool $flush Whether to flush or clean the buffers - * - * @final since version 3.3 + * @final */ - public static function closeOutputBuffers($targetLevel, $flush) + public static function closeOutputBuffers(int $targetLevel, bool $flush) { $status = ob_get_status(true); $level = \count($status); - // PHP_OUTPUT_HANDLER_* are not defined on HHVM 3.3 - $flags = \defined('PHP_OUTPUT_HANDLER_REMOVABLE') ? PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE) : -1; + $flags = PHP_OUTPUT_HANDLER_REMOVABLE | ($flush ? PHP_OUTPUT_HANDLER_FLUSHABLE : PHP_OUTPUT_HANDLER_CLEANABLE); while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) { if ($flush) { @@ -1294,7 +1228,7 @@ class Response * * @see http://support.microsoft.com/kb/323308 * - * @final since version 3.3 + * @final */ protected function ensureIEOverSSLCompatibility(Request $request) { diff --git a/vendor/symfony/http-foundation/ResponseHeaderBag.php b/vendor/symfony/http-foundation/ResponseHeaderBag.php index 00cff7af08..1141e8d987 100644 --- a/vendor/symfony/http-foundation/ResponseHeaderBag.php +++ b/vendor/symfony/http-foundation/ResponseHeaderBag.php @@ -247,56 +247,15 @@ class ResponseHeaderBag extends HeaderBag */ public function clearCookie($name, $path = '/', $domain = null, $secure = false, $httpOnly = true) { - $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly)); + $this->setCookie(new Cookie($name, null, 1, $path, $domain, $secure, $httpOnly, false, null)); } /** - * Generates a HTTP Content-Disposition field-value. - * - * @param string $disposition One of "inline" or "attachment" - * @param string $filename A unicode string - * @param string $filenameFallback A string containing only ASCII characters that - * is semantically equivalent to $filename. If the filename is already ASCII, - * it can be omitted, or just copied from $filename - * - * @return string A string suitable for use as a Content-Disposition field-value - * - * @throws \InvalidArgumentException - * - * @see RFC 6266 + * @see HeaderUtils::makeDisposition() */ public function makeDisposition($disposition, $filename, $filenameFallback = '') { - if (!\in_array($disposition, array(self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE))) { - throw new \InvalidArgumentException(sprintf('The disposition must be either "%s" or "%s".', self::DISPOSITION_ATTACHMENT, self::DISPOSITION_INLINE)); - } - - if ('' == $filenameFallback) { - $filenameFallback = $filename; - } - - // filenameFallback is not ASCII. - if (!preg_match('/^[\x20-\x7e]*$/', $filenameFallback)) { - throw new \InvalidArgumentException('The filename fallback must only contain ASCII characters.'); - } - - // percent characters aren't safe in fallback. - if (false !== strpos($filenameFallback, '%')) { - throw new \InvalidArgumentException('The filename fallback cannot contain the "%" character.'); - } - - // path separators aren't allowed in either. - if (false !== strpos($filename, '/') || false !== strpos($filename, '\\') || false !== strpos($filenameFallback, '/') || false !== strpos($filenameFallback, '\\')) { - throw new \InvalidArgumentException('The filename and the fallback cannot contain the "/" and "\\" characters.'); - } - - $output = sprintf('%s; filename="%s"', $disposition, str_replace('"', '\\"', $filenameFallback)); - - if ($filename !== $filenameFallback) { - $output .= sprintf("; filename*=utf-8''%s", rawurlencode($filename)); - } - - return $output; + return HeaderUtils::makeDisposition((string) $disposition, (string) $filename, (string) $filenameFallback); } /** diff --git a/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php b/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php index fc5fb14101..82577b804e 100644 --- a/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php +++ b/vendor/symfony/http-foundation/Session/Attribute/AttributeBag.php @@ -24,7 +24,7 @@ class AttributeBag implements AttributeBagInterface, \IteratorAggregate, \Counta /** * @param string $storageKey The key used to store attributes in the session */ - public function __construct($storageKey = '_sf2_attributes') + public function __construct(string $storageKey = '_sf2_attributes') { $this->storageKey = $storageKey; } diff --git a/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php b/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php index 2f1e01a971..50cd740d95 100644 --- a/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php +++ b/vendor/symfony/http-foundation/Session/Attribute/NamespacedAttributeBag.php @@ -25,7 +25,7 @@ class NamespacedAttributeBag extends AttributeBag * @param string $storageKey Session storage key * @param string $namespaceCharacter Namespace character to use in keys */ - public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/') + public function __construct(string $storageKey = '_sf2_attributes', string $namespaceCharacter = '/') { $this->namespaceCharacter = $namespaceCharacter; parent::__construct($storageKey); diff --git a/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php b/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php index 77521c2478..ef23457b41 100644 --- a/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php +++ b/vendor/symfony/http-foundation/Session/Flash/AutoExpireFlashBag.php @@ -25,7 +25,7 @@ class AutoExpireFlashBag implements FlashBagInterface /** * @param string $storageKey The key used to store flashes in the session */ - public function __construct($storageKey = '_symfony_flashes') + public function __construct(string $storageKey = '_symfony_flashes') { $this->storageKey = $storageKey; } diff --git a/vendor/symfony/http-foundation/Session/Flash/FlashBag.php b/vendor/symfony/http-foundation/Session/Flash/FlashBag.php index 12fb740c52..44ddb96330 100644 --- a/vendor/symfony/http-foundation/Session/Flash/FlashBag.php +++ b/vendor/symfony/http-foundation/Session/Flash/FlashBag.php @@ -25,7 +25,7 @@ class FlashBag implements FlashBagInterface /** * @param string $storageKey The key used to store flashes in the session */ - public function __construct($storageKey = '_symfony_flashes') + public function __construct(string $storageKey = '_symfony_flashes') { $this->storageKey = $storageKey; } diff --git a/vendor/symfony/http-foundation/Session/SessionUtils.php b/vendor/symfony/http-foundation/Session/SessionUtils.php new file mode 100644 index 0000000000..91737c39ac --- /dev/null +++ b/vendor/symfony/http-foundation/Session/SessionUtils.php @@ -0,0 +1,59 @@ +<?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\Session; + +/** + * Session utility functions. + * + * @author Nicolas Grekas <p@tchwork.com> + * @author Rémon van de Kamp <rpkamp@gmail.com> + * + * @internal + */ +final class SessionUtils +{ + /** + * Finds the session header amongst the headers that are to be sent, removes it, and returns + * it so the caller can process it further. + */ + public static function popSessionCookie(string $sessionName, string $sessionId): ?string + { + $sessionCookie = null; + $sessionCookiePrefix = sprintf(' %s=', urlencode($sessionName)); + $sessionCookieWithId = sprintf('%s%s;', $sessionCookiePrefix, urlencode($sessionId)); + $otherCookies = array(); + foreach (headers_list() as $h) { + if (0 !== stripos($h, 'Set-Cookie:')) { + continue; + } + if (11 === strpos($h, $sessionCookiePrefix, 11)) { + $sessionCookie = $h; + + if (11 !== strpos($h, $sessionCookieWithId, 11)) { + $otherCookies[] = $h; + } + } else { + $otherCookies[] = $h; + } + } + if (null === $sessionCookie) { + return null; + } + + header_remove('Set-Cookie'); + foreach ($otherCookies as $h) { + header($h, false); + } + + return $sessionCookie; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php index 5b5c1d8170..95f110332a 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/AbstractSessionHandler.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; +use Symfony\Component\HttpFoundation\Session\SessionUtils; + /** * This abstract session handler provides a generic implementation * of the PHP 7.0 SessionUpdateTimestampHandlerInterface, @@ -91,9 +93,6 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess $data = $this->doRead($sessionId); $this->newSessionId = '' === $data ? $sessionId : null; - if (\PHP_VERSION_ID < 70000) { - $this->prefetchData = $data; - } return $data; } @@ -103,14 +102,6 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess */ public function write($sessionId, $data) { - if (\PHP_VERSION_ID < 70000 && $this->prefetchData) { - $readData = $this->prefetchData; - $this->prefetchData = null; - - if ($readData === $data) { - return $this->updateTimestamp($sessionId, $data); - } - } if (null === $this->igbinaryEmptyData) { // see https://github.com/igbinary/igbinary/issues/146 $this->igbinaryEmptyData = \function_exists('igbinary_serialize') ? igbinary_serialize(array()) : ''; @@ -128,38 +119,19 @@ abstract class AbstractSessionHandler implements \SessionHandlerInterface, \Sess */ public function destroy($sessionId) { - if (\PHP_VERSION_ID < 70000) { - $this->prefetchData = null; - } - if (!headers_sent() && ini_get('session.use_cookies')) { + if (!headers_sent() && filter_var(ini_get('session.use_cookies'), FILTER_VALIDATE_BOOLEAN)) { if (!$this->sessionName) { throw new \LogicException(sprintf('Session name cannot be empty, did you forget to call "parent::open()" in "%s"?.', \get_class($this))); } - $sessionCookie = sprintf(' %s=', urlencode($this->sessionName)); - $sessionCookieWithId = sprintf('%s%s;', $sessionCookie, urlencode($sessionId)); - $sessionCookieFound = false; - $otherCookies = array(); - foreach (headers_list() as $h) { - if (0 !== stripos($h, 'Set-Cookie:')) { - continue; - } - if (11 === strpos($h, $sessionCookie, 11)) { - $sessionCookieFound = true; - - if (11 !== strpos($h, $sessionCookieWithId, 11)) { - $otherCookies[] = $h; - } + $cookie = SessionUtils::popSessionCookie($this->sessionName, $sessionId); + if (null === $cookie) { + if (\PHP_VERSION_ID < 70300) { + setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), filter_var(ini_get('session.cookie_secure'), FILTER_VALIDATE_BOOLEAN), filter_var(ini_get('session.cookie_httponly'), FILTER_VALIDATE_BOOLEAN)); } else { - $otherCookies[] = $h; - } - } - if ($sessionCookieFound) { - header_remove('Set-Cookie'); - foreach ($otherCookies as $h) { - header($h, false); + $params = session_get_cookie_params(); + unset($params['lifetime']); + setcookie($this->sessionName, '', $params); } - } else { - setcookie($this->sessionName, '', 0, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly')); } } diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php deleted file mode 100644 index 1b12c92189..0000000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/MemcacheSessionHandler.php +++ /dev/null @@ -1,118 +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\HttpFoundation\Session\Storage\Handler; - -@trigger_error(sprintf('The class %s is deprecated since Symfony 3.4 and will be removed in 4.0. Use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler instead.', MemcacheSessionHandler::class), E_USER_DEPRECATED); - -/** - * @author Drak <drak@zikula.org> - * - * @deprecated since version 3.4, to be removed in 4.0. Use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcachedSessionHandler instead. - */ -class MemcacheSessionHandler implements \SessionHandlerInterface -{ - private $memcache; - - /** - * @var int Time to live in seconds - */ - private $ttl; - - /** - * @var string Key prefix for shared environments - */ - private $prefix; - - /** - * Constructor. - * - * List of available options: - * * prefix: The prefix to use for the memcache keys in order to avoid collision - * * expiretime: The time to live in seconds - * - * @param \Memcache $memcache A \Memcache instance - * @param array $options An associative array of Memcache options - * - * @throws \InvalidArgumentException When unsupported options are passed - */ - public function __construct(\Memcache $memcache, array $options = array()) - { - if ($diff = array_diff(array_keys($options), array('prefix', 'expiretime'))) { - throw new \InvalidArgumentException(sprintf('The following options are not supported "%s"', implode(', ', $diff))); - } - - $this->memcache = $memcache; - $this->ttl = isset($options['expiretime']) ? (int) $options['expiretime'] : 86400; - $this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sf2s'; - } - - /** - * {@inheritdoc} - */ - public function open($savePath, $sessionName) - { - return true; - } - - /** - * {@inheritdoc} - */ - public function close() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function read($sessionId) - { - return $this->memcache->get($this->prefix.$sessionId) ?: ''; - } - - /** - * {@inheritdoc} - */ - public function write($sessionId, $data) - { - return $this->memcache->set($this->prefix.$sessionId, $data, 0, time() + $this->ttl); - } - - /** - * {@inheritdoc} - */ - public function destroy($sessionId) - { - $this->memcache->delete($this->prefix.$sessionId); - - return true; - } - - /** - * {@inheritdoc} - */ - public function gc($maxlifetime) - { - // not required here because memcache will auto expire the records anyhow. - return true; - } - - /** - * Return a Memcache instance. - * - * @return \Memcache - */ - protected function getMemcache() - { - return $this->memcache; - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php new file mode 100644 index 0000000000..5293d2448a --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/MigratingSessionHandler.php @@ -0,0 +1,124 @@ +<?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\Session\Storage\Handler; + +/** + * Migrating session handler for migrating from one handler to another. It reads + * from the current handler and writes both the current and new ones. + * + * It ignores errors from the new handler. + * + * @author Ross Motley <ross.motley@amara.com> + * @author Oliver Radwell <oliver.radwell@amara.com> + */ +class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface +{ + private $currentHandler; + private $writeOnlyHandler; + + public function __construct(\SessionHandlerInterface $currentHandler, \SessionHandlerInterface $writeOnlyHandler) + { + if (!$currentHandler instanceof \SessionUpdateTimestampHandlerInterface) { + $currentHandler = new StrictSessionHandler($currentHandler); + } + if (!$writeOnlyHandler instanceof \SessionUpdateTimestampHandlerInterface) { + $writeOnlyHandler = new StrictSessionHandler($writeOnlyHandler); + } + + $this->currentHandler = $currentHandler; + $this->writeOnlyHandler = $writeOnlyHandler; + } + + /** + * {@inheritdoc} + */ + public function close() + { + $result = $this->currentHandler->close(); + $this->writeOnlyHandler->close(); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function destroy($sessionId) + { + $result = $this->currentHandler->destroy($sessionId); + $this->writeOnlyHandler->destroy($sessionId); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function gc($maxlifetime) + { + $result = $this->currentHandler->gc($maxlifetime); + $this->writeOnlyHandler->gc($maxlifetime); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function open($savePath, $sessionName) + { + $result = $this->currentHandler->open($savePath, $sessionName); + $this->writeOnlyHandler->open($savePath, $sessionName); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function read($sessionId) + { + // No reading from new handler until switch-over + return $this->currentHandler->read($sessionId); + } + + /** + * {@inheritdoc} + */ + public function write($sessionId, $sessionData) + { + $result = $this->currentHandler->write($sessionId, $sessionData); + $this->writeOnlyHandler->write($sessionId, $sessionData); + + return $result; + } + + /** + * {@inheritdoc} + */ + public function validateId($sessionId) + { + // No reading from new handler until switch-over + return $this->currentHandler->validateId($sessionId); + } + + /** + * {@inheritdoc} + */ + public function updateTimestamp($sessionId, $sessionData) + { + $result = $this->currentHandler->updateTimestamp($sessionId, $sessionData); + $this->writeOnlyHandler->updateTimestamp($sessionId, $sessionData); + + return $result; + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php index 7d3fa218a2..853b0bc723 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/MongoDbSessionHandler.php @@ -24,7 +24,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler private $mongo; /** - * @var \MongoCollection + * @var \MongoDB\Collection */ private $collection; @@ -64,19 +64,10 @@ class MongoDbSessionHandler extends AbstractSessionHandler * @param \MongoDB\Client $mongo A MongoDB\Client instance * @param array $options An associative array of field options * - * @throws \InvalidArgumentException When MongoClient or Mongo instance not provided * @throws \InvalidArgumentException When "database" or "collection" not provided */ - public function __construct($mongo, array $options) + public function __construct(\MongoDB\Client $mongo, array $options) { - if ($mongo instanceof \MongoClient || $mongo instanceof \Mongo) { - @trigger_error(sprintf('Using %s with the legacy mongo extension is deprecated as of 3.4 and will be removed in 4.0. Use it with the mongodb/mongodb package and ext-mongodb instead.', __CLASS__), E_USER_DEPRECATED); - } - - if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { - throw new \InvalidArgumentException('MongoClient or Mongo instance required'); - } - if (!isset($options['database']) || !isset($options['collection'])) { throw new \InvalidArgumentException('You must provide the "database" and "collection" option for MongoDBSessionHandler'); } @@ -104,9 +95,7 @@ class MongoDbSessionHandler extends AbstractSessionHandler */ protected function doDestroy($sessionId) { - $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove'; - - $this->getCollection()->$methodName(array( + $this->getCollection()->deleteOne(array( $this->options['id_field'] => $sessionId, )); @@ -118,10 +107,8 @@ class MongoDbSessionHandler extends AbstractSessionHandler */ public function gc($maxlifetime) { - $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteMany' : 'remove'; - - $this->getCollection()->$methodName(array( - $this->options['expiry_field'] => array('$lt' => $this->createDateTime()), + $this->getCollection()->deleteMany(array( + $this->options['expiry_field'] => array('$lt' => new \MongoDB\BSON\UTCDateTime()), )); return true; @@ -132,28 +119,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler */ protected function doWrite($sessionId, $data) { - $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime')); + $expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000); $fields = array( - $this->options['time_field'] => $this->createDateTime(), + $this->options['time_field'] => new \MongoDB\BSON\UTCDateTime(), $this->options['expiry_field'] => $expiry, + $this->options['data_field'] => new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY), ); - $options = array('upsert' => true); - - if ($this->mongo instanceof \MongoDB\Client) { - $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY); - } else { - $fields[$this->options['data_field']] = new \MongoBinData($data, \MongoBinData::BYTE_ARRAY); - $options['multiple'] = false; - } - - $methodName = $this->mongo instanceof \MongoDB\Client ? 'updateOne' : 'update'; - - $this->getCollection()->$methodName( + $this->getCollection()->updateOne( array($this->options['id_field'] => $sessionId), array('$set' => $fields), - $options + array('upsert' => true) ); return true; @@ -164,23 +141,14 @@ class MongoDbSessionHandler extends AbstractSessionHandler */ public function updateTimestamp($sessionId, $data) { - $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime')); + $expiry = new \MongoDB\BSON\UTCDateTime((time() + (int) ini_get('session.gc_maxlifetime')) * 1000); - if ($this->mongo instanceof \MongoDB\Client) { - $methodName = 'updateOne'; - $options = array(); - } else { - $methodName = 'update'; - $options = array('multiple' => false); - } - - $this->getCollection()->$methodName( + $this->getCollection()->updateOne( array($this->options['id_field'] => $sessionId), array('$set' => array( - $this->options['time_field'] => $this->createDateTime(), + $this->options['time_field'] => new \MongoDB\BSON\UTCDateTime(), $this->options['expiry_field'] => $expiry, - )), - $options + )) ); return true; @@ -193,24 +161,18 @@ class MongoDbSessionHandler extends AbstractSessionHandler { $dbData = $this->getCollection()->findOne(array( $this->options['id_field'] => $sessionId, - $this->options['expiry_field'] => array('$gte' => $this->createDateTime()), + $this->options['expiry_field'] => array('$gte' => new \MongoDB\BSON\UTCDateTime()), )); if (null === $dbData) { return ''; } - if ($dbData[$this->options['data_field']] instanceof \MongoDB\BSON\Binary) { - return $dbData[$this->options['data_field']]->getData(); - } - - return $dbData[$this->options['data_field']]->bin; + return $dbData[$this->options['data_field']]->getData(); } /** - * Return a "MongoCollection" instance. - * - * @return \MongoCollection + * @return \MongoDB\Collection */ private function getCollection() { @@ -222,34 +184,10 @@ class MongoDbSessionHandler extends AbstractSessionHandler } /** - * Return a Mongo instance. - * - * @return \Mongo|\MongoClient|\MongoDB\Client + * @return \MongoDB\Client */ protected function getMongo() { return $this->mongo; } - - /** - * Create a date object using the class appropriate for the current mongo connection. - * - * Return an instance of a MongoDate or \MongoDB\BSON\UTCDateTime - * - * @param int $seconds An integer representing UTC seconds since Jan 1 1970. Defaults to now. - * - * @return \MongoDate|\MongoDB\BSON\UTCDateTime - */ - private function createDateTime($seconds = null) - { - if (null === $seconds) { - $seconds = time(); - } - - if ($this->mongo instanceof \MongoDB\Client) { - return new \MongoDB\BSON\UTCDateTime($seconds * 1000); - } - - return new \MongoDate($seconds); - } } diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php index 4e9704bd58..f962965a82 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/NativeFileSessionHandler.php @@ -16,7 +16,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage\Handler; * * @author Drak <drak@zikula.org> */ -class NativeFileSessionHandler extends NativeSessionHandler +class NativeFileSessionHandler extends \SessionHandler { /** * @param string $savePath Path of directory to save session files @@ -28,7 +28,7 @@ class NativeFileSessionHandler extends NativeSessionHandler * @throws \InvalidArgumentException On invalid $savePath * @throws \RuntimeException When failing to create the save directory */ - public function __construct($savePath = null) + public function __construct(string $savePath = null) { if (null === $savePath) { $savePath = ini_get('session.save_path'); diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php deleted file mode 100644 index 9be4528aeb..0000000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/NativeSessionHandler.php +++ /dev/null @@ -1,24 +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\HttpFoundation\Session\Storage\Handler; - -/** - * @deprecated since version 3.4, to be removed in 4.0. Use \SessionHandler instead. - * @see http://php.net/sessionhandler - */ -class NativeSessionHandler extends \SessionHandler -{ - public function __construct() - { - @trigger_error('The '.__NAMESPACE__.'\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead.', E_USER_DEPRECATED); - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php index c5f0527f9c..1bb647ef42 100644 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/PdoSessionHandler.php @@ -637,7 +637,7 @@ class PdoSessionHandler extends AbstractSessionHandler throw new \RuntimeException('Failed to read session: INSERT reported a duplicate id but next SELECT did not return any data.'); } - if (!ini_get('session.use_strict_mode') && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { + if (!filter_var(ini_get('session.use_strict_mode'), FILTER_VALIDATE_BOOLEAN) && self::LOCK_TRANSACTIONAL === $this->lockMode && 'sqlite' !== $this->driver) { // In strict mode, session fixation is not possible: new sessions always start with a unique // random id, so that concurrency is not possible and this code path can be skipped. // Exclusive-reading of non-existent rows does not block, so we need to do an insert to block @@ -668,8 +668,6 @@ class PdoSessionHandler extends AbstractSessionHandler /** * Executes an application-level lock on the database. * - * @param string $sessionId Session ID - * * @return \PDOStatement The statement that needs to be executed later to release the lock * * @throws \DomainException When an unsupported PDO driver is used @@ -678,7 +676,7 @@ class PdoSessionHandler extends AbstractSessionHandler * - for oci using DBMS_LOCK.REQUEST * - for sqlsrv using sp_getapplock with LockOwner = Session */ - private function doAdvisoryLock($sessionId) + private function doAdvisoryLock(string $sessionId) { switch ($this->driver) { case 'mysql': @@ -733,12 +731,8 @@ class PdoSessionHandler extends AbstractSessionHandler * Encodes the first 4 (when PHP_INT_SIZE == 4) or 8 characters of the string as an integer. * * Keep in mind, PHP integers are signed. - * - * @param string $string - * - * @return int */ - private function convertStringToInt($string) + private function convertStringToInt(string $string): int { if (4 === \PHP_INT_SIZE) { return (\ord($string[3]) << 24) + (\ord($string[2]) << 16) + (\ord($string[1]) << 8) + \ord($string[0]); @@ -753,11 +747,9 @@ class PdoSessionHandler extends AbstractSessionHandler /** * Return a locking or nonlocking SQL query to read session information. * - * @return string The SQL string - * * @throws \DomainException When an unsupported PDO driver is used */ - private function getSelectSql() + private function getSelectSql(): string { if (self::LOCK_TRANSACTIONAL === $this->lockMode) { $this->beginTransaction(); @@ -848,14 +840,8 @@ class PdoSessionHandler extends AbstractSessionHandler /** * Returns a merge/upsert (i.e. insert or update) statement when supported by the database for writing session data. - * - * @param string $sessionId Session ID - * @param string $data Encoded session data - * @param int $maxlifetime session.gc_maxlifetime - * - * @return \PDOStatement|null The merge statement or null when not supported */ - private function getMergeStatement($sessionId, $data, $maxlifetime) + private function getMergeStatement(string $sessionId, string $data, int $maxlifetime): ?\PDOStatement { switch (true) { case 'mysql' === $this->driver: diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php new file mode 100644 index 0000000000..9c08ddcc01 --- /dev/null +++ b/vendor/symfony/http-foundation/Session/Storage/Handler/RedisSessionHandler.php @@ -0,0 +1,114 @@ +<?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\Session\Storage\Handler; + +use Predis\Response\ErrorInterface; +use Symfony\Component\Cache\Traits\RedisClusterProxy; +use Symfony\Component\Cache\Traits\RedisProxy; + +/** + * Redis based session storage handler based on the Redis class + * provided by the PHP redis extension. + * + * @author Dalibor Karlović <dalibor@flexolabs.io> + */ +class RedisSessionHandler extends AbstractSessionHandler +{ + private $redis; + + /** + * @var string Key prefix for shared environments + */ + private $prefix; + + /** + * List of available options: + * * prefix: The prefix to use for the keys in order to avoid collision on the Redis server. + * + * @param \Redis|\RedisArray|\RedisCluster|\Predis\Client|RedisProxy $redis + * @param array $options An associative array of options + * + * @throws \InvalidArgumentException When unsupported client or options are passed + */ + public function __construct($redis, array $options = array()) + { + if ( + !$redis instanceof \Redis && + !$redis instanceof \RedisArray && + !$redis instanceof \RedisCluster && + !$redis instanceof \Predis\Client && + !$redis instanceof RedisProxy && + !$redis instanceof RedisClusterProxy + ) { + throw new \InvalidArgumentException(sprintf('%s() expects parameter 1 to be Redis, RedisArray, RedisCluster or Predis\Client, %s given', __METHOD__, \is_object($redis) ? \get_class($redis) : \gettype($redis))); + } + + if ($diff = array_diff(array_keys($options), array('prefix'))) { + throw new \InvalidArgumentException(sprintf('The following options are not supported "%s"', implode(', ', $diff))); + } + + $this->redis = $redis; + $this->prefix = $options['prefix'] ?? 'sf_s'; + } + + /** + * {@inheritdoc} + */ + protected function doRead($sessionId): string + { + return $this->redis->get($this->prefix.$sessionId) ?: ''; + } + + /** + * {@inheritdoc} + */ + protected function doWrite($sessionId, $data): bool + { + $result = $this->redis->setEx($this->prefix.$sessionId, (int) ini_get('session.gc_maxlifetime'), $data); + + return $result && !$result instanceof ErrorInterface; + } + + /** + * {@inheritdoc} + */ + protected function doDestroy($sessionId): bool + { + $this->redis->del($this->prefix.$sessionId); + + return true; + } + + /** + * {@inheritdoc} + */ + public function close(): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function gc($maxlifetime): bool + { + return true; + } + + /** + * {@inheritdoc} + */ + public function updateTimestamp($sessionId, $data) + { + return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ini_get('session.gc_maxlifetime')); + } +} diff --git a/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php b/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php deleted file mode 100644 index 127e47f210..0000000000 --- a/vendor/symfony/http-foundation/Session/Storage/Handler/WriteCheckSessionHandler.php +++ /dev/null @@ -1,92 +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\HttpFoundation\Session\Storage\Handler; - -/** - * Wraps another SessionHandlerInterface to only write the session when it has been modified. - * - * @author Adrien Brault <adrien.brault@gmail.com> - * - * @deprecated since version 3.4, to be removed in 4.0. Implement `SessionUpdateTimestampHandlerInterface` or extend `AbstractSessionHandler` instead. - */ -class WriteCheckSessionHandler implements \SessionHandlerInterface -{ - private $wrappedSessionHandler; - - /** - * @var array sessionId => session - */ - private $readSessions; - - public function __construct(\SessionHandlerInterface $wrappedSessionHandler) - { - @trigger_error(sprintf('The %s class is deprecated since Symfony 3.4 and will be removed in 4.0. Implement `SessionUpdateTimestampHandlerInterface` or extend `AbstractSessionHandler` instead.', self::class), E_USER_DEPRECATED); - - $this->wrappedSessionHandler = $wrappedSessionHandler; - } - - /** - * {@inheritdoc} - */ - public function close() - { - return $this->wrappedSessionHandler->close(); - } - - /** - * {@inheritdoc} - */ - public function destroy($sessionId) - { - return $this->wrappedSessionHandler->destroy($sessionId); - } - - /** - * {@inheritdoc} - */ - public function gc($maxlifetime) - { - return $this->wrappedSessionHandler->gc($maxlifetime); - } - - /** - * {@inheritdoc} - */ - public function open($savePath, $sessionName) - { - return $this->wrappedSessionHandler->open($savePath, $sessionName); - } - - /** - * {@inheritdoc} - */ - public function read($sessionId) - { - $session = $this->wrappedSessionHandler->read($sessionId); - - $this->readSessions[$sessionId] = $session; - - return $session; - } - - /** - * {@inheritdoc} - */ - public function write($sessionId, $data) - { - if (isset($this->readSessions[$sessionId]) && $data === $this->readSessions[$sessionId]) { - return true; - } - - return $this->wrappedSessionHandler->write($sessionId, $data); - } -} diff --git a/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php b/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php index 6f59af4869..ea0d5ecb51 100644 --- a/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php +++ b/vendor/symfony/http-foundation/Session/Storage/MetadataBag.php @@ -57,7 +57,7 @@ class MetadataBag implements SessionBagInterface * @param string $storageKey The key used to store bag in the session * @param int $updateThreshold The time to wait between two UPDATED updates */ - public function __construct($storageKey = '_sf2_meta', $updateThreshold = 0) + public function __construct(string $storageKey = '_sf2_meta', int $updateThreshold = 0) { $this->storageKey = $storageKey; $this->updateThreshold = $updateThreshold; diff --git a/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php index 027f4efffc..47cac39854 100644 --- a/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/MockArraySessionStorage.php @@ -62,11 +62,7 @@ class MockArraySessionStorage implements SessionStorageInterface */ protected $bags = array(); - /** - * @param string $name Session name - * @param MetadataBag $metaBag MetadataBag instance - */ - public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null) + public function __construct(string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { $this->name = $name; $this->setMetadataBag($metaBag); diff --git a/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php index 14f427007b..732f92abf9 100644 --- a/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/MockFileSessionStorage.php @@ -31,7 +31,7 @@ class MockFileSessionStorage extends MockArraySessionStorage * @param string $name Session name * @param MetadataBag $metaBag MetadataBag instance */ - public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null) + public function __construct(string $savePath = null, string $name = 'MOCKSESSID', MetadataBag $metaBag = null) { if (null === $savePath) { $savePath = sys_get_temp_dir(); diff --git a/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php b/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php index 1ec5c7ff4e..156a0d4555 100644 --- a/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php +++ b/vendor/symfony/http-foundation/Session/Storage/NativeSessionStorage.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpFoundation\Session\Storage; use Symfony\Component\HttpFoundation\Session\SessionBagInterface; +use Symfony\Component\HttpFoundation\Session\SessionUtils; use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy; use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy; @@ -49,6 +50,11 @@ class NativeSessionStorage implements SessionStorageInterface protected $metadataBag; /** + * @var string|null + */ + private $emulateSameSite; + + /** * Depending on how you want the storage driver to behave you probably * want to override this constructor entirely. * @@ -67,13 +73,10 @@ class NativeSessionStorage implements SessionStorageInterface * cookie_lifetime, "0" * cookie_path, "/" * cookie_secure, "" - * entropy_file, "" - * entropy_length, "0" + * cookie_samesite, null * gc_divisor, "100" * gc_maxlifetime, "1440" * gc_probability, "1" - * hash_bits_per_character, "4" - * hash_function, "0" * lazy_write, "1" * name, "PHPSESSID" * referer_check, "" @@ -105,6 +108,7 @@ class NativeSessionStorage implements SessionStorageInterface 'cache_expire' => 0, 'use_cookies' => 1, 'lazy_write' => 1, + 'use_strict_mode' => 1, ); session_register_shutdown(); @@ -137,7 +141,7 @@ class NativeSessionStorage implements SessionStorageInterface throw new \RuntimeException('Failed to start the session: already started by PHP.'); } - if (ini_get('session.use_cookies') && headers_sent($file, $line)) { + if (filter_var(ini_get('session.use_cookies'), FILTER_VALIDATE_BOOLEAN) && headers_sent($file, $line)) { throw new \RuntimeException(sprintf('Failed to start the session because headers have already been sent by "%s" at line %d.', $file, $line)); } @@ -146,6 +150,13 @@ class NativeSessionStorage implements SessionStorageInterface throw new \RuntimeException('Failed to start the session'); } + if (null !== $this->emulateSameSite) { + $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id()); + if (null !== $originalCookie) { + header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite)); + } + } + $this->loadSession(); return true; @@ -211,6 +222,13 @@ class NativeSessionStorage implements SessionStorageInterface // @see https://bugs.php.net/bug.php?id=70013 $this->loadSession(); + if (null !== $this->emulateSameSite) { + $originalCookie = SessionUtils::popSessionCookie(session_name(), session_id()); + if (null !== $originalCookie) { + header(sprintf('%s; SameSite=%s', $originalCookie, $this->emulateSameSite)); + } + } + return $isRegenerated; } @@ -343,10 +361,9 @@ class NativeSessionStorage implements SessionStorageInterface $validOptions = array_flip(array( 'cache_expire', 'cache_limiter', 'cookie_domain', 'cookie_httponly', - 'cookie_lifetime', 'cookie_path', 'cookie_secure', - 'entropy_file', 'entropy_length', 'gc_divisor', - 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character', - 'hash_function', 'lazy_write', 'name', 'referer_check', + 'cookie_lifetime', 'cookie_path', 'cookie_secure', 'cookie_samesite', + 'gc_divisor', 'gc_maxlifetime', 'gc_probability', + 'lazy_write', 'name', 'referer_check', 'serialize_handler', 'use_strict_mode', 'use_cookies', 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled', 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name', @@ -356,6 +373,12 @@ class NativeSessionStorage implements SessionStorageInterface foreach ($options as $key => $value) { if (isset($validOptions[$key])) { + if ('cookie_samesite' === $key && \PHP_VERSION_ID < 70300) { + // PHP < 7.3 does not support same_site cookies. We will emulate it in + // the start() method instead. + $this->emulateSameSite = $value; + continue; + } ini_set('url_rewriter.tags' !== $key ? 'session.'.$key : $key, $value); } } diff --git a/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php b/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php deleted file mode 100644 index 082eed143e..0000000000 --- a/vendor/symfony/http-foundation/Session/Storage/Proxy/NativeProxy.php +++ /dev/null @@ -1,40 +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\HttpFoundation\Session\Storage\Proxy; - -@trigger_error('The '.__NAMESPACE__.'\NativeProxy class is deprecated since Symfony 3.4 and will be removed in 4.0. Use your session handler implementation directly.', E_USER_DEPRECATED); - -/** - * This proxy is built-in session handlers in PHP 5.3.x. - * - * @deprecated since version 3.4, to be removed in 4.0. Use your session handler implementation directly. - * - * @author Drak <drak@zikula.org> - */ -class NativeProxy extends AbstractProxy -{ - public function __construct() - { - // this makes an educated guess as to what the handler is since it should already be set. - $this->saveHandlerName = ini_get('session.save_handler'); - } - - /** - * Returns true if this handler wraps an internal PHP session save handler using \SessionHandler. - * - * @return bool False - */ - public function isWrapper() - { - return false; - } -} diff --git a/vendor/symfony/http-foundation/StreamedResponse.php b/vendor/symfony/http-foundation/StreamedResponse.php index 3a55d5d2b9..06d053eadd 100644 --- a/vendor/symfony/http-foundation/StreamedResponse.php +++ b/vendor/symfony/http-foundation/StreamedResponse.php @@ -35,7 +35,7 @@ class StreamedResponse extends Response * @param int $status The response status code * @param array $headers An array of response headers */ - public function __construct(callable $callback = null, $status = 200, $headers = array()) + public function __construct(callable $callback = null, int $status = 200, array $headers = array()) { parent::__construct(null, $status, $headers); diff --git a/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php b/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php index cb43bb3516..1a660247c8 100644 --- a/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php +++ b/vendor/symfony/http-foundation/Tests/AcceptHeaderItemTest.php @@ -66,7 +66,7 @@ class AcceptHeaderItemTest extends TestCase ), array( 'text/plain', array('charset' => 'utf-8', 'param' => 'this;should,not=matter', 'footnotes' => 'true'), - 'text/plain;charset=utf-8;param="this;should,not=matter";footnotes=true', + 'text/plain; charset=utf-8; param="this;should,not=matter"; footnotes=true', ), ); } diff --git a/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php b/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php index 9929eac28e..1ac6103e0d 100644 --- a/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php +++ b/vendor/symfony/http-foundation/Tests/AcceptHeaderTest.php @@ -100,4 +100,31 @@ class AcceptHeaderTest extends TestCase 'order matters when q is equal2' => array('*;q=0.3,utf-8;q=0.7,ISO-8859-1;q=0.7', array('utf-8', 'ISO-8859-1', '*')), ); } + + /** + * @dataProvider provideDefaultValueData + */ + public function testDefaultValue($acceptHeader, $value, $expectedQuality) + { + $header = AcceptHeader::fromString($acceptHeader); + $this->assertSame($expectedQuality, $header->get($value)->getQuality()); + } + + public function provideDefaultValueData() + { + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, *;q=0.3', 'text/xml', 0.3); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', 'text/xml', 0.3); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', 'text/html', 1.0); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', 'text/plain', 0.5); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*;q=0.3', '*', 0.3); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*', '*', 1.0); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*', 'text/xml', 1.0); + yield array('text/plain;q=0.5, text/html, text/x-dvi;q=0.8, */*', 'text/*', 1.0); + yield array('text/plain;q=0.5, text/html, text/*;q=0.8, */*', 'text/*', 0.8); + yield array('text/plain;q=0.5, text/html, text/*;q=0.8, */*', 'text/html', 1.0); + yield array('text/plain;q=0.5, text/html, text/*;q=0.8, */*', 'text/x-dvi', 0.8); + yield array('*;q=0.3, ISO-8859-1;q=0.7, utf-8;q=0.7', '*', 0.3); + yield array('*;q=0.3, ISO-8859-1;q=0.7, utf-8;q=0.7', 'utf-8', 0.7); + yield array('*;q=0.3, ISO-8859-1;q=0.7, utf-8;q=0.7', 'SHIFT_JIS', 0.3); + } } diff --git a/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php b/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php index d21791f000..6bf04e16b7 100644 --- a/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php +++ b/vendor/symfony/http-foundation/Tests/BinaryFileResponseTest.php @@ -32,7 +32,7 @@ class BinaryFileResponseTest extends ResponseTestCase $response = BinaryFileResponse::create($file, 404, array(), true, ResponseHeaderBag::DISPOSITION_INLINE); $this->assertEquals(404, $response->getStatusCode()); $this->assertFalse($response->headers->has('ETag')); - $this->assertEquals('inline; filename="README.md"', $response->headers->get('Content-Disposition')); + $this->assertEquals('inline; filename=README.md', $response->headers->get('Content-Disposition')); } public function testConstructWithNonAsciiFilename() @@ -66,7 +66,7 @@ class BinaryFileResponseTest extends ResponseTestCase $response = new BinaryFileResponse(__FILE__); $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, 'föö.html'); - $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition')); + $this->assertSame('attachment; filename=f__.html; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition')); } public function testSetContentDispositionGeneratesSafeFallbackFilenameForWronglyEncodedFilename() @@ -77,7 +77,7 @@ class BinaryFileResponseTest extends ResponseTestCase $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $iso88591EncodedFilename); // the parameter filename* is invalid in this case (rawurldecode('f%F6%F6') does not provide a UTF-8 string but an ISO-8859-1 encoded one) - $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition')); + $this->assertSame('attachment; filename=f__.html; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition')); } /** @@ -337,7 +337,8 @@ class BinaryFileResponseTest extends ResponseTestCase { return array( array('/var/www/var/www/files/foo.txt', '/var/www/=/files/', '/files/var/www/files/foo.txt'), - array('/home/foo/bar.txt', '/var/www/=/files/,/home/foo/=/baz/', '/baz/bar.txt'), + array('/home/Foo/bar.txt', '/var/www/=/files/,/home/Foo/=/baz/', '/baz/bar.txt'), + array('/home/Foo/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', '/baz/bar.txt'), ); } diff --git a/vendor/symfony/http-foundation/Tests/CookieTest.php b/vendor/symfony/http-foundation/Tests/CookieTest.php index 14c45c9a6c..44981dff8b 100644 --- a/vendor/symfony/http-foundation/Tests/CookieTest.php +++ b/vendor/symfony/http-foundation/Tests/CookieTest.php @@ -45,7 +45,7 @@ class CookieTest extends TestCase */ public function testInstantiationThrowsExceptionIfCookieNameContainsInvalidCharacters($name) { - new Cookie($name); + Cookie::create($name); } /** @@ -53,12 +53,12 @@ class CookieTest extends TestCase */ public function testInvalidExpiration() { - new Cookie('MyCookie', 'foo', 'bar'); + Cookie::create('MyCookie', 'foo', 'bar'); } public function testNegativeExpirationIsNotPossible() { - $cookie = new Cookie('foo', 'bar', -100); + $cookie = Cookie::create('foo', 'bar', -100); $this->assertSame(0, $cookie->getExpiresTime()); } @@ -66,32 +66,32 @@ class CookieTest extends TestCase public function testGetValue() { $value = 'MyValue'; - $cookie = new Cookie('MyCookie', $value); + $cookie = Cookie::create('MyCookie', $value); $this->assertSame($value, $cookie->getValue(), '->getValue() returns the proper value'); } public function testGetPath() { - $cookie = new Cookie('foo', 'bar'); + $cookie = Cookie::create('foo', 'bar'); $this->assertSame('/', $cookie->getPath(), '->getPath() returns / as the default path'); } public function testGetExpiresTime() { - $cookie = new Cookie('foo', 'bar'); + $cookie = Cookie::create('foo', 'bar'); $this->assertEquals(0, $cookie->getExpiresTime(), '->getExpiresTime() returns the default expire date'); - $cookie = new Cookie('foo', 'bar', $expire = time() + 3600); + $cookie = Cookie::create('foo', 'bar', $expire = time() + 3600); $this->assertEquals($expire, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); } public function testGetExpiresTimeIsCastToInt() { - $cookie = new Cookie('foo', 'bar', 3600.9); + $cookie = Cookie::create('foo', 'bar', 3600.9); $this->assertSame(3600, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date as an integer'); } @@ -99,18 +99,15 @@ class CookieTest extends TestCase public function testConstructorWithDateTime() { $expire = new \DateTime(); - $cookie = new Cookie('foo', 'bar', $expire); + $cookie = Cookie::create('foo', 'bar', $expire); $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); } - /** - * @requires PHP 5.5 - */ public function testConstructorWithDateTimeImmutable() { $expire = new \DateTimeImmutable(); - $cookie = new Cookie('foo', 'bar', $expire); + $cookie = Cookie::create('foo', 'bar', $expire); $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); } @@ -118,7 +115,7 @@ class CookieTest extends TestCase public function testGetExpiresTimeWithStringValue() { $value = '+1 day'; - $cookie = new Cookie('foo', 'bar', $value); + $cookie = Cookie::create('foo', 'bar', $value); $expire = strtotime($value); $this->assertEquals($expire, $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date', 1); @@ -126,96 +123,99 @@ class CookieTest extends TestCase public function testGetDomain() { - $cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com'); + $cookie = Cookie::create('foo', 'bar', 0, '/', '.myfoodomain.com'); $this->assertEquals('.myfoodomain.com', $cookie->getDomain(), '->getDomain() returns the domain name on which the cookie is valid'); } public function testIsSecure() { - $cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com', true); + $cookie = Cookie::create('foo', 'bar', 0, '/', '.myfoodomain.com', true); $this->assertTrue($cookie->isSecure(), '->isSecure() returns whether the cookie is transmitted over HTTPS'); } public function testIsHttpOnly() { - $cookie = new Cookie('foo', 'bar', 0, '/', '.myfoodomain.com', false, true); + $cookie = Cookie::create('foo', 'bar', 0, '/', '.myfoodomain.com', false, true); $this->assertTrue($cookie->isHttpOnly(), '->isHttpOnly() returns whether the cookie is only transmitted over HTTP'); } public function testCookieIsNotCleared() { - $cookie = new Cookie('foo', 'bar', time() + 3600 * 24); + $cookie = Cookie::create('foo', 'bar', time() + 3600 * 24); $this->assertFalse($cookie->isCleared(), '->isCleared() returns false if the cookie did not expire yet'); } public function testCookieIsCleared() { - $cookie = new Cookie('foo', 'bar', time() - 20); + $cookie = Cookie::create('foo', 'bar', time() - 20); $this->assertTrue($cookie->isCleared(), '->isCleared() returns true if the cookie has expired'); - $cookie = new Cookie('foo', 'bar'); + $cookie = Cookie::create('foo', 'bar'); $this->assertFalse($cookie->isCleared()); - $cookie = new Cookie('foo', 'bar', 0); + $cookie = Cookie::create('foo', 'bar'); $this->assertFalse($cookie->isCleared()); - $cookie = new Cookie('foo', 'bar', -1); + $cookie = Cookie::create('foo', 'bar', -1); $this->assertFalse($cookie->isCleared()); } public function testToString() { - $cookie = new Cookie('foo', 'bar', $expire = strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true); + $cookie = Cookie::create('foo', 'bar', $expire = strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true, true, false, null); $this->assertEquals('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() returns string representation of the cookie'); - $cookie = new Cookie('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true); + $cookie = Cookie::create('foo', 'bar with white spaces', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true, true, false, null); $this->assertEquals('foo=bar%20with%20white%20spaces; expires=Fri, 20-May-2011 15:25:52 GMT; Max-Age=0; path=/; domain=.myfoodomain.com; secure; httponly', (string) $cookie, '->__toString() encodes the value of the cookie according to RFC 3986 (white space = %20)'); - $cookie = new Cookie('foo', null, 1, '/admin/', '.myfoodomain.com'); + $cookie = Cookie::create('foo', null, 1, '/admin/', '.myfoodomain.com', false, true, false, null); $this->assertEquals('foo=deleted; expires='.gmdate('D, d-M-Y H:i:s T', $expire = time() - 31536001).'; Max-Age=0; path=/admin/; domain=.myfoodomain.com; httponly', (string) $cookie, '->__toString() returns string representation of a cleared cookie if value is NULL'); - $cookie = new Cookie('foo', 'bar', 0, '/', ''); - $this->assertEquals('foo=bar; path=/; httponly', (string) $cookie); + $cookie = Cookie::create('foo', 'bar'); + $this->assertEquals('foo=bar; path=/; httponly; samesite=lax', (string) $cookie); } public function testRawCookie() { - $cookie = new Cookie('foo', 'b a r', 0, '/', null, false, false); + $cookie = Cookie::create('foo', 'b a r', 0, '/', null, false, false, false, null); $this->assertFalse($cookie->isRaw()); $this->assertEquals('foo=b%20a%20r; path=/', (string) $cookie); - $cookie = new Cookie('foo', 'b+a+r', 0, '/', null, false, false, true); + $cookie = Cookie::create('foo', 'b+a+r', 0, '/', null, false, false, true, null); $this->assertTrue($cookie->isRaw()); $this->assertEquals('foo=b+a+r; path=/', (string) $cookie); } public function testGetMaxAge() { - $cookie = new Cookie('foo', 'bar'); + $cookie = Cookie::create('foo', 'bar'); $this->assertEquals(0, $cookie->getMaxAge()); - $cookie = new Cookie('foo', 'bar', $expire = time() + 100); + $cookie = Cookie::create('foo', 'bar', $expire = time() + 100); $this->assertEquals($expire - time(), $cookie->getMaxAge()); - $cookie = new Cookie('foo', 'bar', $expire = time() - 100); + $cookie = Cookie::create('foo', 'bar', $expire = time() - 100); $this->assertEquals(0, $cookie->getMaxAge()); } public function testFromString() { $cookie = Cookie::fromString('foo=bar; expires=Fri, 20-May-2011 15:25:52 GMT; path=/; domain=.myfoodomain.com; secure; httponly'); - $this->assertEquals(new Cookie('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true, true, true), $cookie); + $this->assertEquals(Cookie::create('foo', 'bar', strtotime('Fri, 20-May-2011 15:25:52 GMT'), '/', '.myfoodomain.com', true, true, true, null), $cookie); $cookie = Cookie::fromString('foo=bar', true); - $this->assertEquals(new Cookie('foo', 'bar', 0, '/', null, false, false), $cookie); + $this->assertEquals(Cookie::create('foo', 'bar', 0, '/', null, false, false, false, null), $cookie); + + $cookie = Cookie::fromString('foo', true); + $this->assertEquals(Cookie::create('foo', null, 0, '/', null, false, false, false, null), $cookie); } public function testFromStringWithHttpOnly() @@ -227,9 +227,27 @@ class CookieTest extends TestCase $this->assertFalse($cookie->isHttpOnly()); } - public function testSameSiteAttributeIsCaseInsensitive() + public function testSameSiteAttribute() { $cookie = new Cookie('foo', 'bar', 0, '/', null, false, true, false, 'Lax'); $this->assertEquals('lax', $cookie->getSameSite()); + + $cookie = new Cookie('foo', 'bar', 0, '/', null, false, true, false, ''); + $this->assertNull($cookie->getSameSite()); + } + + public function testSetSecureDefault() + { + $cookie = Cookie::create('foo', 'bar'); + + $this->assertFalse($cookie->isSecure()); + + $cookie->setSecureDefault(true); + + $this->assertTrue($cookie->isSecure()); + + $cookie->setSecureDefault(false); + + $this->assertFalse($cookie->isSecure()); } } diff --git a/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php b/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php index 1a88d48350..6a0b550d79 100644 --- a/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php +++ b/vendor/symfony/http-foundation/Tests/File/UploadedFileTest.php @@ -12,6 +12,14 @@ namespace Symfony\Component\HttpFoundation\Tests\File; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\File\Exception\CannotWriteFileException; +use Symfony\Component\HttpFoundation\File\Exception\ExtensionFileException; +use Symfony\Component\HttpFoundation\File\Exception\FileException; +use Symfony\Component\HttpFoundation\File\Exception\FormSizeFileException; +use Symfony\Component\HttpFoundation\File\Exception\IniSizeFileException; +use Symfony\Component\HttpFoundation\File\Exception\NoFileException; +use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException; +use Symfony\Component\HttpFoundation\File\Exception\PartialFileException; use Symfony\Component\HttpFoundation\File\UploadedFile; class UploadedFileTest extends TestCase @@ -40,7 +48,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', null, - filesize(__DIR__.'/Fixtures/test.gif'), UPLOAD_ERR_OK ); @@ -57,7 +64,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/.unknownextension', 'original.gif', null, - filesize(__DIR__.'/Fixtures/.unknownextension'), UPLOAD_ERR_OK ); @@ -70,7 +76,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), null ); @@ -83,7 +88,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', 'image/jpeg', - filesize(__DIR__.'/Fixtures/test.gif'), null ); @@ -96,7 +100,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), null ); @@ -109,7 +112,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), null ); @@ -122,7 +124,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), null ); @@ -138,13 +139,60 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), UPLOAD_ERR_OK ); $movedFile = $file->move(__DIR__.'/Fixtures/directory'); } + public function failedUploadedFile() + { + foreach (array(UPLOAD_ERR_INI_SIZE, UPLOAD_ERR_FORM_SIZE, UPLOAD_ERR_PARTIAL, UPLOAD_ERR_NO_FILE, UPLOAD_ERR_CANT_WRITE, UPLOAD_ERR_NO_TMP_DIR, UPLOAD_ERR_EXTENSION, -1) as $error) { + yield array(new UploadedFile( + __DIR__.'/Fixtures/test.gif', + 'original.gif', + 'image/gif', + $error + )); + } + } + + /** + * @dataProvider failedUploadedFile + */ + public function testMoveFailed(UploadedFile $file) + { + switch ($file->getError()) { + case UPLOAD_ERR_INI_SIZE: + $exceptionClass = IniSizeFileException::class; + break; + case UPLOAD_ERR_FORM_SIZE: + $exceptionClass = FormSizeFileException::class; + break; + case UPLOAD_ERR_PARTIAL: + $exceptionClass = PartialFileException::class; + break; + case UPLOAD_ERR_NO_FILE: + $exceptionClass = NoFileException::class; + break; + case UPLOAD_ERR_CANT_WRITE: + $exceptionClass = CannotWriteFileException::class; + break; + case UPLOAD_ERR_NO_TMP_DIR: + $exceptionClass = NoTmpDirFileException::class; + break; + case UPLOAD_ERR_EXTENSION: + $exceptionClass = ExtensionFileException::class; + break; + default: + $exceptionClass = FileException::class; + } + + $this->expectException($exceptionClass); + + $file->move(__DIR__.'/Fixtures/directory'); + } + public function testMoveLocalFileIsAllowedInTestMode() { $path = __DIR__.'/Fixtures/test.copy.gif'; @@ -158,7 +206,6 @@ class UploadedFileTest extends TestCase $path, 'original.gif', 'image/gif', - filesize($path), UPLOAD_ERR_OK, true ); @@ -177,9 +224,7 @@ class UploadedFileTest extends TestCase $file = new UploadedFile( __DIR__.'/Fixtures/test.gif', '../../original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null + 'image/gif' ); $this->assertEquals('original.gif', $file->getClientOriginalName()); @@ -190,9 +235,7 @@ class UploadedFileTest extends TestCase $file = new UploadedFile( __DIR__.'/Fixtures/test.gif', 'original.gif', - 'image/gif', - filesize(__DIR__.'/Fixtures/test.gif'), - null + 'image/gif' ); $this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize()); @@ -206,12 +249,45 @@ class UploadedFileTest extends TestCase $this->assertEquals(filesize(__DIR__.'/Fixtures/test'), $file->getSize()); } - public function testGetExtension() + /** + * @group legacy + * @expectedDeprecation Passing a size as 4th argument to the constructor of "Symfony\Component\HttpFoundation\File\UploadedFile" is deprecated since Symfony 4.1. + */ + public function testConstructDeprecatedSize() { $file = new UploadedFile( __DIR__.'/Fixtures/test.gif', 'original.gif', - null + 'image/gif', + filesize(__DIR__.'/Fixtures/test.gif'), + UPLOAD_ERR_OK, + false + ); + + $this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize()); + } + + /** + * @group legacy + * @expectedDeprecation Passing a size as 4th argument to the constructor of "Symfony\Component\HttpFoundation\File\UploadedFile" is deprecated since Symfony 4.1. + */ + public function testConstructDeprecatedSizeWhenPassingOnlyThe4Needed() + { + $file = new UploadedFile( + __DIR__.'/Fixtures/test.gif', + 'original.gif', + 'image/gif', + filesize(__DIR__.'/Fixtures/test.gif') + ); + + $this->assertEquals(filesize(__DIR__.'/Fixtures/test.gif'), $file->getSize()); + } + + public function testGetExtension() + { + $file = new UploadedFile( + __DIR__.'/Fixtures/test.gif', + 'original.gif' ); $this->assertEquals('gif', $file->getExtension()); @@ -223,7 +299,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', null, - filesize(__DIR__.'/Fixtures/test.gif'), UPLOAD_ERR_OK, true ); @@ -240,7 +315,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', null, - filesize(__DIR__.'/Fixtures/test.gif'), $error ); @@ -264,7 +338,6 @@ class UploadedFileTest extends TestCase __DIR__.'/Fixtures/test.gif', 'original.gif', null, - filesize(__DIR__.'/Fixtures/test.gif'), UPLOAD_ERR_OK ); diff --git a/vendor/symfony/http-foundation/Tests/FileBagTest.php b/vendor/symfony/http-foundation/Tests/FileBagTest.php index b1bbba0d3f..06136e2097 100644 --- a/vendor/symfony/http-foundation/Tests/FileBagTest.php +++ b/vendor/symfony/http-foundation/Tests/FileBagTest.php @@ -34,14 +34,14 @@ class FileBagTest extends TestCase public function testShouldConvertsUploadedFiles() { $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); + $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain'); $bag = new FileBag(array('file' => array( 'name' => basename($tmpFile), 'type' => 'text/plain', 'tmp_name' => $tmpFile, 'error' => 0, - 'size' => 100, + 'size' => null, ))); $this->assertEquals($file, $bag->get('file')); @@ -89,7 +89,7 @@ class FileBagTest extends TestCase public function testShouldConvertUploadedFilesWithPhpBug() { $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); + $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain'); $bag = new FileBag(array( 'child' => array( @@ -106,7 +106,7 @@ class FileBagTest extends TestCase 'file' => 0, ), 'size' => array( - 'file' => 100, + 'file' => null, ), ), )); @@ -118,7 +118,7 @@ class FileBagTest extends TestCase public function testShouldConvertNestedUploadedFilesWithPhpBug() { $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); + $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain'); $bag = new FileBag(array( 'child' => array( @@ -135,7 +135,7 @@ class FileBagTest extends TestCase 'sub' => array('file' => 0), ), 'size' => array( - 'sub' => array('file' => 100), + 'sub' => array('file' => null), ), ), )); @@ -147,7 +147,7 @@ class FileBagTest extends TestCase public function testShouldNotConvertNestedUploadedFiles() { $tmpFile = $this->createTempFile(); - $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain', 100, 0); + $file = new UploadedFile($tmpFile, basename($tmpFile), 'text/plain'); $bag = new FileBag(array('image' => array('file' => $file))); $files = $bag->all(); @@ -156,7 +156,10 @@ class FileBagTest extends TestCase protected function createTempFile() { - return tempnam(sys_get_temp_dir().'/form_test', 'FormTest'); + $tempFile = tempnam(sys_get_temp_dir().'/form_test', 'FormTest'); + file_put_contents($tempFile, '1'); + + return $tempFile; } protected function setUp() diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc index f9c40a9a3c..0bdf9e4b75 100644 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc +++ b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/common.inc @@ -22,7 +22,7 @@ error_reporting(-1); ini_set('html_errors', 0); ini_set('display_errors', 1); -if (ini_get('xdebug.default_enable')) { +if (filter_var(ini_get('xdebug.default_enable'), FILTER_VALIDATE_BOOLEAN)) { xdebug_disable(); } diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php index 8775a5ccee..e18ce52523 100644 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php +++ b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_max_age.php @@ -4,7 +4,7 @@ use Symfony\Component\HttpFoundation\Cookie; $r = require __DIR__.'/common.inc'; -$r->headers->setCookie(new Cookie('foo', 'bar', 253402310800, '', null, false, false)); +$r->headers->setCookie(new Cookie('foo', 'bar', 253402310800, '', null, false, false, false, null)); $r->sendHeaders(); setcookie('foo2', 'bar', 253402310800, '/'); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php index 2ca5b59f1a..00c022d953 100644 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php +++ b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php @@ -6,7 +6,7 @@ $r = require __DIR__.'/common.inc'; $str = '?*():@&+$/%#[]'; -$r->headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true)); +$r->headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true, null)); $r->sendHeaders(); setrawcookie($str, $str, 0, '/', null, false, false); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php index 05b9af30d5..c0363b829d 100644 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php +++ b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/cookie_urlencode.php @@ -6,7 +6,7 @@ $r = require __DIR__.'/common.inc'; $str = '?*():@&+$/%#[]'; -$r->headers->setCookie(new Cookie($str, $str, 0, '', null, false, false)); +$r->headers->setCookie(new Cookie($str, $str, 0, '', null, false, false, false, null)); $r->sendHeaders(); setcookie($str, $str, 0, '/'); diff --git a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php index 3fe1571845..0afaaa8a57 100644 --- a/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php +++ b/vendor/symfony/http-foundation/Tests/Fixtures/response-functional/invalid_cookie_name.php @@ -5,7 +5,7 @@ use Symfony\Component\HttpFoundation\Cookie; $r = require __DIR__.'/common.inc'; try { - $r->headers->setCookie(new Cookie('Hello + world', 'hodor')); + $r->headers->setCookie(Cookie::create('Hello + world', 'hodor')); } catch (\InvalidArgumentException $e) { echo $e->getMessage(); } diff --git a/vendor/symfony/http-foundation/Tests/HeaderUtilsTest.php b/vendor/symfony/http-foundation/Tests/HeaderUtilsTest.php new file mode 100644 index 0000000000..15efdf9234 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/HeaderUtilsTest.php @@ -0,0 +1,134 @@ +<?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\HeaderUtils; + +class HeaderUtilsTest extends TestCase +{ + public function testSplit() + { + $this->assertSame(array('foo=123', 'bar'), HeaderUtils::split('foo=123,bar', ',')); + $this->assertSame(array('foo=123', 'bar'), HeaderUtils::split('foo=123, bar', ',')); + $this->assertSame(array(array('foo=123', 'bar')), HeaderUtils::split('foo=123; bar', ',;')); + $this->assertSame(array(array('foo=123'), array('bar')), HeaderUtils::split('foo=123, bar', ',;')); + $this->assertSame(array('foo', '123, bar'), HeaderUtils::split('foo=123, bar', '=')); + $this->assertSame(array('foo', '123, bar'), HeaderUtils::split(' foo = 123, bar ', '=')); + $this->assertSame(array(array('foo', '123'), array('bar')), HeaderUtils::split('foo=123, bar', ',=')); + $this->assertSame(array(array(array('foo', '123')), array(array('bar'), array('foo', '456'))), HeaderUtils::split('foo=123, bar; foo=456', ',;=')); + $this->assertSame(array(array(array('foo', 'a,b;c=d'))), HeaderUtils::split('foo="a,b;c=d"', ',;=')); + + $this->assertSame(array('foo', 'bar'), HeaderUtils::split('foo,,,, bar', ',')); + $this->assertSame(array('foo', 'bar'), HeaderUtils::split(',foo, bar,', ',')); + $this->assertSame(array('foo', 'bar'), HeaderUtils::split(' , foo, bar, ', ',')); + $this->assertSame(array('foo bar'), HeaderUtils::split('foo "bar"', ',')); + $this->assertSame(array('foo bar'), HeaderUtils::split('"foo" bar', ',')); + $this->assertSame(array('foo bar'), HeaderUtils::split('"foo" "bar"', ',')); + + // These are not a valid header values. We test that they parse anyway, + // and that both the valid and invalid parts are returned. + $this->assertSame(array(), HeaderUtils::split('', ',')); + $this->assertSame(array(), HeaderUtils::split(',,,', ',')); + $this->assertSame(array('foo', 'bar', 'baz'), HeaderUtils::split('foo, "bar", "baz', ',')); + $this->assertSame(array('foo', 'bar, baz'), HeaderUtils::split('foo, "bar, baz', ',')); + $this->assertSame(array('foo', 'bar, baz\\'), HeaderUtils::split('foo, "bar, baz\\', ',')); + $this->assertSame(array('foo', 'bar, baz\\'), HeaderUtils::split('foo, "bar, baz\\\\', ',')); + } + + public function testCombine() + { + $this->assertSame(array('foo' => '123'), HeaderUtils::combine(array(array('foo', '123')))); + $this->assertSame(array('foo' => true), HeaderUtils::combine(array(array('foo')))); + $this->assertSame(array('foo' => true), HeaderUtils::combine(array(array('Foo')))); + $this->assertSame(array('foo' => '123', 'bar' => true), HeaderUtils::combine(array(array('foo', '123'), array('bar')))); + } + + public function testToString() + { + $this->assertSame('foo', HeaderUtils::toString(array('foo' => true), ',')); + $this->assertSame('foo; bar', HeaderUtils::toString(array('foo' => true, 'bar' => true), ';')); + $this->assertSame('foo=123', HeaderUtils::toString(array('foo' => '123'), ',')); + $this->assertSame('foo="1 2 3"', HeaderUtils::toString(array('foo' => '1 2 3'), ',')); + $this->assertSame('foo="1 2 3", bar', HeaderUtils::toString(array('foo' => '1 2 3', 'bar' => true), ',')); + } + + public function testQuote() + { + $this->assertSame('foo', HeaderUtils::quote('foo')); + $this->assertSame('az09!#$%&\'*.^_`|~-', HeaderUtils::quote('az09!#$%&\'*.^_`|~-')); + $this->assertSame('"foo bar"', HeaderUtils::quote('foo bar')); + $this->assertSame('"foo [bar]"', HeaderUtils::quote('foo [bar]')); + $this->assertSame('"foo \"bar\""', HeaderUtils::quote('foo "bar"')); + $this->assertSame('"foo \\\\ bar"', HeaderUtils::quote('foo \\ bar')); + } + + public function testUnquote() + { + $this->assertEquals('foo', HeaderUtils::unquote('foo')); + $this->assertEquals('az09!#$%&\'*.^_`|~-', HeaderUtils::unquote('az09!#$%&\'*.^_`|~-')); + $this->assertEquals('foo bar', HeaderUtils::unquote('"foo bar"')); + $this->assertEquals('foo [bar]', HeaderUtils::unquote('"foo [bar]"')); + $this->assertEquals('foo "bar"', HeaderUtils::unquote('"foo \"bar\""')); + $this->assertEquals('foo "bar"', HeaderUtils::unquote('"foo \"\b\a\r\""')); + $this->assertEquals('foo \\ bar', HeaderUtils::unquote('"foo \\\\ bar"')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testMakeDispositionInvalidDisposition() + { + HeaderUtils::makeDisposition('invalid', 'foo.html'); + } + + /** + * @dataProvider provideMakeDisposition + */ + public function testMakeDisposition($disposition, $filename, $filenameFallback, $expected) + { + $this->assertEquals($expected, HeaderUtils::makeDisposition($disposition, $filename, $filenameFallback)); + } + + public function provideMakeDisposition() + { + return array( + array('attachment', 'foo.html', 'foo.html', 'attachment; filename=foo.html'), + array('attachment', 'foo.html', '', 'attachment; filename=foo.html'), + array('attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'), + array('attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'), + array('attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'), + array('attachment', 'föö.html', 'foo.html', 'attachment; filename=foo.html; filename*=utf-8\'\'f%C3%B6%C3%B6.html'), + ); + } + + /** + * @dataProvider provideMakeDispositionFail + * @expectedException \InvalidArgumentException + */ + public function testMakeDispositionFail($disposition, $filename) + { + HeaderUtils::makeDisposition($disposition, $filename); + } + + public function provideMakeDispositionFail() + { + return array( + array('attachment', 'foo%20bar.html'), + array('attachment', 'foo/bar.html'), + array('attachment', '/foo.html'), + array('attachment', 'foo\bar.html'), + array('attachment', '\foo.html'), + array('attachment', 'föö.html'), + ); + } +} diff --git a/vendor/symfony/http-foundation/Tests/JsonResponseTest.php b/vendor/symfony/http-foundation/Tests/JsonResponseTest.php index 6687fde5be..201839f89c 100644 --- a/vendor/symfony/http-foundation/Tests/JsonResponseTest.php +++ b/vendor/symfony/http-foundation/Tests/JsonResponseTest.php @@ -16,15 +16,6 @@ use Symfony\Component\HttpFoundation\JsonResponse; class JsonResponseTest extends TestCase { - protected function setUp() - { - parent::setUp(); - - if (!\defined('HHVM_VERSION')) { - $this->iniSet('serialize_precision', 14); - } - } - public function testConstructorEmptyCreatesJsonObject() { $response = new JsonResponse(); diff --git a/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php b/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php index 10d764a776..cc35ad637b 100644 --- a/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php +++ b/vendor/symfony/http-foundation/Tests/RequestMatcherTest.php @@ -78,6 +78,21 @@ class RequestMatcherTest extends TestCase $this->assertSame($isMatch, $matcher->matches($request)); } + public function testPort() + { + $matcher = new RequestMatcher(); + $request = Request::create('', 'get', array(), array(), array(), array('HTTP_HOST' => null, 'SERVER_PORT' => 8000)); + + $matcher->matchPort(8000); + $this->assertTrue($matcher->matches($request)); + + $matcher->matchPort(9000); + $this->assertFalse($matcher->matches($request)); + + $matcher = new RequestMatcher(null, null, null, null, array(), null, 8000); + $this->assertTrue($matcher->matches($request)); + } + public function getHostData() { return array( diff --git a/vendor/symfony/http-foundation/Tests/RequestTest.php b/vendor/symfony/http-foundation/Tests/RequestTest.php index ff4dd67b30..0711c515f2 100644 --- a/vendor/symfony/http-foundation/Tests/RequestTest.php +++ b/vendor/symfony/http-foundation/Tests/RequestTest.php @@ -232,6 +232,55 @@ class RequestTest extends TestCase $this->assertEquals(80, $request->getPort()); $this->assertEquals('test.com', $request->getHttpHost()); $this->assertFalse($request->isSecure()); + + // Fragment should not be included in the URI + $request = Request::create('http://test.com/foo#bar'); + $this->assertEquals('http://test.com/foo', $request->getUri()); + } + + public function testCreateWithRequestUri() + { + $request = Request::create('http://test.com:80/foo'); + $request->server->set('REQUEST_URI', 'http://test.com:80/foo'); + $this->assertEquals('http://test.com/foo', $request->getUri()); + $this->assertEquals('/foo', $request->getPathInfo()); + $this->assertEquals('test.com', $request->getHost()); + $this->assertEquals('test.com', $request->getHttpHost()); + $this->assertEquals(80, $request->getPort()); + $this->assertFalse($request->isSecure()); + + $request = Request::create('http://test.com:8080/foo'); + $request->server->set('REQUEST_URI', 'http://test.com:8080/foo'); + $this->assertEquals('http://test.com:8080/foo', $request->getUri()); + $this->assertEquals('/foo', $request->getPathInfo()); + $this->assertEquals('test.com', $request->getHost()); + $this->assertEquals('test.com:8080', $request->getHttpHost()); + $this->assertEquals(8080, $request->getPort()); + $this->assertFalse($request->isSecure()); + + $request = Request::create('http://test.com/foo?bar=foo', 'GET', array('bar' => 'baz')); + $request->server->set('REQUEST_URI', 'http://test.com/foo?bar=foo'); + $this->assertEquals('http://test.com/foo?bar=baz', $request->getUri()); + $this->assertEquals('/foo', $request->getPathInfo()); + $this->assertEquals('bar=baz', $request->getQueryString()); + $this->assertEquals('test.com', $request->getHost()); + $this->assertEquals('test.com', $request->getHttpHost()); + $this->assertEquals(80, $request->getPort()); + $this->assertFalse($request->isSecure()); + + $request = Request::create('https://test.com:443/foo'); + $request->server->set('REQUEST_URI', 'https://test.com:443/foo'); + $this->assertEquals('https://test.com/foo', $request->getUri()); + $this->assertEquals('/foo', $request->getPathInfo()); + $this->assertEquals('test.com', $request->getHost()); + $this->assertEquals('test.com', $request->getHttpHost()); + $this->assertEquals(443, $request->getPort()); + $this->assertTrue($request->isSecure()); + + // Fragment should not be included in the URI + $request = Request::create('http://test.com/foo#bar'); + $request->server->set('REQUEST_URI', 'http://test.com/foo#bar'); + $this->assertEquals('http://test.com/foo', $request->getUri()); } public function testCreateCheckPrecedence() @@ -332,6 +381,9 @@ class RequestTest extends TestCase { $request = new Request(); $this->assertEquals('json', $request->getFormat('application/json; charset=utf-8')); + $this->assertEquals('json', $request->getFormat('application/json;charset=utf-8')); + $this->assertEquals('json', $request->getFormat('application/json ; charset=utf-8')); + $this->assertEquals('json', $request->getFormat('application/json ;charset=utf-8')); } /** @@ -675,7 +727,7 @@ class RequestTest extends TestCase public function getQueryStringNormalizationData() { return array( - array('foo', 'foo', 'works with valueless parameters'), + array('foo', 'foo=', 'works with valueless parameters'), array('foo=', 'foo=', 'includes a dangling equal sign'), array('bar=&foo=bar', 'bar=&foo=bar', '->works with empty parameters'), array('foo=bar&bar=', 'bar=&foo=bar', 'sorts keys alphabetically'), @@ -684,18 +736,24 @@ class RequestTest extends TestCase // PHP also converts "+" to spaces when filling the global _GET or when using the function parse_str. array('him=John%20Doe&her=Jane+Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes spaces in both encodings "%20" and "+"'), - array('foo[]=1&foo[]=2', 'foo%5B%5D=1&foo%5B%5D=2', 'allows array notation'), - array('foo=1&foo=2', 'foo=1&foo=2', 'allows repeated parameters'), + array('foo[]=1&foo[]=2', 'foo%5B0%5D=1&foo%5B1%5D=2', 'allows array notation'), + array('foo=1&foo=2', 'foo=2', 'merges repeated parameters'), array('pa%3Dram=foo%26bar%3Dbaz&test=test', 'pa%3Dram=foo%26bar%3Dbaz&test=test', 'works with encoded delimiters'), - array('0', '0', 'allows "0"'), - array('Jane Doe&John%20Doe', 'Jane%20Doe&John%20Doe', 'normalizes encoding in keys'), + array('0', '0=', 'allows "0"'), + array('Jane Doe&John%20Doe', 'Jane_Doe=&John_Doe=', 'normalizes encoding in keys'), array('her=Jane Doe&him=John%20Doe', 'her=Jane%20Doe&him=John%20Doe', 'normalizes encoding in values'), - array('foo=bar&&&test&&', 'foo=bar&test', 'removes unneeded delimiters'), + array('foo=bar&&&test&&', 'foo=bar&test=', 'removes unneeded delimiters'), array('formula=e=m*c^2', 'formula=e%3Dm%2Ac%5E2', 'correctly treats only the first "=" as delimiter and the next as value'), // Ignore pairs with empty key, even if there was a value, e.g. "=value", as such nameless values cannot be retrieved anyway. // PHP also does not include them when building _GET. array('foo=bar&=a=b&=x=y', 'foo=bar', 'removes params with empty key'), + + // Don't reorder nested query string keys + array('foo[]=Z&foo[]=A', 'foo%5B0%5D=Z&foo%5B1%5D=A', 'keeps order of values'), + array('foo[Z]=B&foo[A]=B', 'foo%5BZ%5D=B&foo%5BA%5D=B', 'keeps order of keys'), + + array('utf8=✓', 'utf8=%E2%9C%93', 'encodes UTF-8'), ); } @@ -893,7 +951,7 @@ class RequestTest extends TestCase array(array('127.0.0.1'), '127.0.0.1', 'for="_gazonk"', array('127.0.0.1')), array(array('88.88.88.88'), '127.0.0.1', 'for="88.88.88.88:80"', array('127.0.0.1')), array(array('192.0.2.60'), '::1', 'for=192.0.2.60;proto=http;by=203.0.113.43', array('::1')), - array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for=2620:0:1cfe:face:b00c::3', array('::1')), + array(array('2620:0:1cfe:face:b00c::3', '192.0.2.43'), '::1', 'for=192.0.2.43, for="[2620:0:1cfe:face:b00c::3]"', array('::1')), array(array('2001:db8:cafe::17'), '::1', 'for="[2001:db8:cafe::17]:4711', array('::1')), ); } @@ -1077,21 +1135,6 @@ class RequestTest extends TestCase $this->assertEquals('My other content', $req->getContent()); } - /** - * @expectedException \LogicException - * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider - */ - public function testGetContentCantBeCalledTwiceWithResources($first, $second) - { - if (\PHP_VERSION_ID >= 50600) { - $this->markTestSkipped('PHP >= 5.6 allows to open php://input several times.'); - } - - $req = new Request(); - $req->getContent($first); - $req->getContent($second); - } - public function getContentCantBeCalledTwiceWithResourcesProvider() { return array( @@ -1102,7 +1145,6 @@ class RequestTest extends TestCase /** * @dataProvider getContentCanBeCalledTwiceWithResourcesProvider - * @requires PHP 5.6 */ public function testGetContentCanBeCalledTwiceWithResources($first, $second) { @@ -1512,6 +1554,15 @@ class RequestTest extends TestCase $this->assertObjectHasAttribute('attributeName', $session); } + /** + * @group legacy + * @expectedDeprecation Calling "Symfony\Component\HttpFoundation\Request::getSession()" when no session has been set is deprecated since Symfony 4.1 and will throw an exception in 5.0. Use "hasSession()" instead. + */ + public function testGetSessionNullable() + { + (new Request())->getSession(); + } + public function testHasPreviousSession() { $request = new Request(); @@ -1769,53 +1820,6 @@ class RequestTest extends TestCase $this->assertTrue($request->isSecure()); } - /** - * @group legacy - * @expectedDeprecation The "Symfony\Component\HttpFoundation\Request::setTrustedHeaderName()" method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the $trustedHeaderSet argument of the Request::setTrustedProxies() method instead. - */ - public function testLegacyTrustedProxies() - { - $request = Request::create('http://example.com/'); - $request->server->set('REMOTE_ADDR', '3.3.3.3'); - $request->headers->set('X_FORWARDED_FOR', '1.1.1.1, 2.2.2.2'); - $request->headers->set('X_FORWARDED_HOST', 'foo.example.com, real.example.com:8080'); - $request->headers->set('X_FORWARDED_PROTO', 'https'); - $request->headers->set('X_FORWARDED_PORT', 443); - $request->headers->set('X_MY_FOR', '3.3.3.3, 4.4.4.4'); - $request->headers->set('X_MY_HOST', 'my.example.com'); - $request->headers->set('X_MY_PROTO', 'http'); - $request->headers->set('X_MY_PORT', 81); - - Request::setTrustedProxies(array('3.3.3.3', '2.2.2.2'), Request::HEADER_X_FORWARDED_ALL); - - // custom header names - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_MY_FOR'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_MY_HOST'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_MY_PORT'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_MY_PROTO'); - $this->assertEquals('4.4.4.4', $request->getClientIp()); - $this->assertEquals('my.example.com', $request->getHost()); - $this->assertEquals(81, $request->getPort()); - $this->assertFalse($request->isSecure()); - - // disabling via empty header names - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, null); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, null); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, null); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, null); - $this->assertEquals('3.3.3.3', $request->getClientIp()); - $this->assertEquals('example.com', $request->getHost()); - $this->assertEquals(80, $request->getPort()); - $this->assertFalse($request->isSecure()); - - //reset - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO'); - } - public function testTrustedProxiesForwarded() { $request = Request::create('http://example.com/'); @@ -1866,26 +1870,6 @@ class RequestTest extends TestCase } /** - * @group legacy - * @expectedException \InvalidArgumentException - */ - public function testSetTrustedProxiesInvalidHeaderName() - { - Request::create('http://example.com/'); - Request::setTrustedHeaderName('bogus name', 'X_MY_FOR'); - } - - /** - * @group legacy - * @expectedException \InvalidArgumentException - */ - public function testGetTrustedProxiesInvalidHeaderName() - { - Request::create('http://example.com/'); - Request::getTrustedHeaderName('bogus name'); - } - - /** * @dataProvider iisRequestUriProvider */ public function testIISRequestUri($headers, $server, $expectedRequestUri) @@ -2102,14 +2086,13 @@ class RequestTest extends TestCase } /** - * @group legacy - * @expectedDeprecation Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is deprecated since Symfony 3.2 and will throw an exception in 4.0. Disable checking only for cacheable methods by calling the method with `false` as first argument or use the Request::isMethodCacheable() instead. + * @expectedException \BadMethodCallException */ public function testMethodSafeChecksCacheable() { $request = new Request(); $request->setMethod('OPTIONS'); - $this->assertFalse($request->isMethodSafe()); + $request->isMethodSafe(); } /** @@ -2139,61 +2122,6 @@ class RequestTest extends TestCase } /** - * @group legacy - */ - public function testGetTrustedHeaderName() - { - Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_X_FORWARDED_ALL); - - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertSame('X_FORWARDED_FOR', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertSame('X_FORWARDED_HOST', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertSame('X_FORWARDED_PORT', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertSame('X_FORWARDED_PROTO', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED); - - $this->assertSame('FORWARDED', Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'A'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'B'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'C'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'D'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'E'); - - Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED); - - $this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_X_FORWARDED_ALL); - - $this->assertNull(Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - $this->assertSame('B', Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)); - $this->assertSame('C', Request::getTrustedHeaderName(Request::HEADER_CLIENT_HOST)); - $this->assertSame('D', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PORT)); - $this->assertSame('E', Request::getTrustedHeaderName(Request::HEADER_CLIENT_PROTO)); - - Request::setTrustedProxies(array('8.8.8.8'), Request::HEADER_FORWARDED); - - $this->assertSame('A', Request::getTrustedHeaderName(Request::HEADER_FORWARDED)); - - //reset - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, 'FORWARDED'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_FORWARDED_FOR'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, 'X_FORWARDED_HOST'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, 'X_FORWARDED_PORT'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, 'X_FORWARDED_PROTO'); - } - - /** * @dataProvider protocolVersionProvider */ public function testProtocolVersion($serverProtocol, $trustedProxy, $via, $expected) diff --git a/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php b/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php index 06e2d41d01..f6ddb98ea7 100644 --- a/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php +++ b/vendor/symfony/http-foundation/Tests/ResponseHeaderBagTest.php @@ -110,9 +110,9 @@ class ResponseHeaderBagTest extends TestCase public function testToStringIncludesCookieHeaders() { $bag = new ResponseHeaderBag(array()); - $bag->setCookie(new Cookie('foo', 'bar')); + $bag->setCookie(Cookie::create('foo', 'bar')); - $this->assertSetCookieHeader('foo=bar; path=/; httponly', $bag); + $this->assertSetCookieHeader('foo=bar; path=/; httponly; samesite=lax', $bag); $bag->clearCookie('foo'); @@ -154,24 +154,24 @@ class ResponseHeaderBagTest extends TestCase public function testCookiesWithSameNames() { $bag = new ResponseHeaderBag(); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar')); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'foo.bar')); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/bar', 'bar.foo')); - $bag->setCookie(new Cookie('foo', 'bar')); + $bag->setCookie(Cookie::create('foo', 'bar', 0, '/path/foo', 'foo.bar')); + $bag->setCookie(Cookie::create('foo', 'bar', 0, '/path/bar', 'foo.bar')); + $bag->setCookie(Cookie::create('foo', 'bar', 0, '/path/bar', 'bar.foo')); + $bag->setCookie(Cookie::create('foo', 'bar')); $this->assertCount(4, $bag->getCookies()); - $this->assertEquals('foo=bar; path=/path/foo; domain=foo.bar; httponly', $bag->get('set-cookie')); + $this->assertEquals('foo=bar; path=/path/foo; domain=foo.bar; httponly; samesite=lax', $bag->get('set-cookie')); $this->assertEquals(array( - 'foo=bar; path=/path/foo; domain=foo.bar; httponly', - 'foo=bar; path=/path/bar; domain=foo.bar; httponly', - 'foo=bar; path=/path/bar; domain=bar.foo; httponly', - 'foo=bar; path=/; httponly', + 'foo=bar; path=/path/foo; domain=foo.bar; httponly; samesite=lax', + 'foo=bar; path=/path/bar; domain=foo.bar; httponly; samesite=lax', + 'foo=bar; path=/path/bar; domain=bar.foo; httponly; samesite=lax', + 'foo=bar; path=/; httponly; samesite=lax', ), $bag->get('set-cookie', null, false)); - $this->assertSetCookieHeader('foo=bar; path=/path/foo; domain=foo.bar; httponly', $bag); - $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=foo.bar; httponly', $bag); - $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=bar.foo; httponly', $bag); - $this->assertSetCookieHeader('foo=bar; path=/; httponly', $bag); + $this->assertSetCookieHeader('foo=bar; path=/path/foo; domain=foo.bar; httponly; samesite=lax', $bag); + $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=foo.bar; httponly; samesite=lax', $bag); + $this->assertSetCookieHeader('foo=bar; path=/path/bar; domain=bar.foo; httponly; samesite=lax', $bag); + $this->assertSetCookieHeader('foo=bar; path=/; httponly; samesite=lax', $bag); $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); @@ -186,8 +186,8 @@ class ResponseHeaderBagTest extends TestCase $bag = new ResponseHeaderBag(); $this->assertFalse($bag->has('set-cookie')); - $bag->setCookie(new Cookie('foo', 'bar', 0, '/path/foo', 'foo.bar')); - $bag->setCookie(new Cookie('bar', 'foo', 0, '/path/bar', 'foo.bar')); + $bag->setCookie(Cookie::create('foo', 'bar', 0, '/path/foo', 'foo.bar')); + $bag->setCookie(Cookie::create('bar', 'foo', 0, '/path/bar', 'foo.bar')); $this->assertTrue($bag->has('set-cookie')); $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); @@ -209,8 +209,8 @@ class ResponseHeaderBagTest extends TestCase public function testRemoveCookieWithNullRemove() { $bag = new ResponseHeaderBag(); - $bag->setCookie(new Cookie('foo', 'bar', 0)); - $bag->setCookie(new Cookie('bar', 'foo', 0)); + $bag->setCookie(Cookie::create('foo', 'bar')); + $bag->setCookie(Cookie::create('bar', 'foo')); $cookies = $bag->getCookies(ResponseHeaderBag::COOKIES_ARRAY); $this->assertArrayHasKey('/', $cookies['']); @@ -228,12 +228,12 @@ class ResponseHeaderBagTest extends TestCase { $bag = new ResponseHeaderBag(); $bag->set('set-cookie', 'foo=bar'); - $this->assertEquals(array(new Cookie('foo', 'bar', 0, '/', null, false, false, true)), $bag->getCookies()); + $this->assertEquals(array(Cookie::create('foo', 'bar', 0, '/', null, false, false, true, null)), $bag->getCookies()); $bag->set('set-cookie', 'foo2=bar2', false); $this->assertEquals(array( - new Cookie('foo', 'bar', 0, '/', null, false, false, true), - new Cookie('foo2', 'bar2', 0, '/', null, false, false, true), + Cookie::create('foo', 'bar', 0, '/', null, false, false, true, null), + Cookie::create('foo2', 'bar2', 0, '/', null, false, false, true, null), ), $bag->getCookies()); $bag->remove('set-cookie'); @@ -250,26 +250,6 @@ class ResponseHeaderBagTest extends TestCase $bag->getCookies('invalid_argument'); } - /** - * @expectedException \InvalidArgumentException - */ - public function testMakeDispositionInvalidDisposition() - { - $headers = new ResponseHeaderBag(); - - $headers->makeDisposition('invalid', 'foo.html'); - } - - /** - * @dataProvider provideMakeDisposition - */ - public function testMakeDisposition($disposition, $filename, $filenameFallback, $expected) - { - $headers = new ResponseHeaderBag(); - - $this->assertEquals($expected, $headers->makeDisposition($disposition, $filename, $filenameFallback)); - } - public function testToStringDoesntMessUpHeaders() { $headers = new ResponseHeaderBag(); @@ -284,41 +264,6 @@ class ResponseHeaderBagTest extends TestCase $this->assertEquals(array('text/html'), $allHeaders['Content-type']); } - public function provideMakeDisposition() - { - return array( - array('attachment', 'foo.html', 'foo.html', 'attachment; filename="foo.html"'), - array('attachment', 'foo.html', '', 'attachment; filename="foo.html"'), - array('attachment', 'foo bar.html', '', 'attachment; filename="foo bar.html"'), - array('attachment', 'foo "bar".html', '', 'attachment; filename="foo \\"bar\\".html"'), - array('attachment', 'foo%20bar.html', 'foo bar.html', 'attachment; filename="foo bar.html"; filename*=utf-8\'\'foo%2520bar.html'), - array('attachment', 'föö.html', 'foo.html', 'attachment; filename="foo.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html'), - ); - } - - /** - * @dataProvider provideMakeDispositionFail - * @expectedException \InvalidArgumentException - */ - public function testMakeDispositionFail($disposition, $filename) - { - $headers = new ResponseHeaderBag(); - - $headers->makeDisposition($disposition, $filename); - } - - public function provideMakeDispositionFail() - { - return array( - array('attachment', 'foo%20bar.html'), - array('attachment', 'foo/bar.html'), - array('attachment', '/foo.html'), - array('attachment', 'foo\bar.html'), - array('attachment', '\foo.html'), - array('attachment', 'föö.html'), - ); - } - public function testDateHeaderAddedOnCreation() { $now = time(); diff --git a/vendor/symfony/http-foundation/Tests/ResponseTest.php b/vendor/symfony/http-foundation/Tests/ResponseTest.php index 43fa9b70aa..03dcc11abd 100644 --- a/vendor/symfony/http-foundation/Tests/ResponseTest.php +++ b/vendor/symfony/http-foundation/Tests/ResponseTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpFoundation\Tests; +use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -305,7 +306,7 @@ class ResponseTest extends ResponseTestCase $response = new Response(); $response->headers->set('Cache-Control', 'must-revalidate'); $response->headers->set('Expires', -1); - $this->assertEquals('Sat, 01 Jan 00 00:00:00 +0000', $response->getExpires()->format(DATE_RFC822)); + $this->assertLessThanOrEqual(time() - 2 * 86400, $response->getExpires()->format('U')); $response = new Response(); $this->assertNull($response->getMaxAge(), '->getMaxAge() returns null if no freshness information available'); @@ -573,6 +574,24 @@ class ResponseTest extends ResponseTestCase $this->assertFalse($response->headers->has('expires')); } + public function testPrepareSetsCookiesSecure() + { + $cookie = Cookie::create('foo', 'bar'); + + $response = new Response('foo'); + $response->headers->setCookie($cookie); + + $request = Request::create('/', 'GET'); + $response->prepare($request); + + $this->assertFalse($cookie->isSecure()); + + $request = Request::create('https://localhost/', 'GET'); + $response->prepare($request); + + $this->assertTrue($cookie->isSecure()); + } + public function testSetCache() { $response = new Response(); @@ -663,6 +682,22 @@ class ResponseTest extends ResponseTestCase $this->assertTrue($response->isImmutable()); } + public function testSetDate() + { + $response = new Response(); + $response->setDate(\DateTime::createFromFormat(\DateTime::ATOM, '2013-01-26T09:21:56+0100', new \DateTimeZone('Europe/Berlin'))); + + $this->assertEquals('2013-01-26T08:21:56+00:00', $response->getDate()->format(\DateTime::ATOM)); + } + + public function testSetDateWithImmutable() + { + $response = new Response(); + $response->setDate(\DateTimeImmutable::createFromFormat(\DateTime::ATOM, '2013-01-26T09:21:56+0100', new \DateTimeZone('Europe/Berlin'))); + + $this->assertEquals('2013-01-26T08:21:56+00:00', $response->getDate()->format(\DateTime::ATOM)); + } + public function testSetExpires() { $response = new Response(); @@ -676,6 +711,16 @@ class ResponseTest extends ResponseTestCase $this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp()); } + public function testSetExpiresWithImmutable() + { + $response = new Response(); + + $now = $this->createDateTimeImmutableNow(); + $response->setExpires($now); + + $this->assertEquals($response->getExpires()->getTimestamp(), $now->getTimestamp()); + } + public function testSetLastModified() { $response = new Response(); @@ -686,6 +731,16 @@ class ResponseTest extends ResponseTestCase $this->assertNull($response->getLastModified()); } + public function testSetLastModifiedWithImmutable() + { + $response = new Response(); + $response->setLastModified($this->createDateTimeImmutableNow()); + $this->assertNotNull($response->getLastModified()); + + $response->setLastModified(null); + $this->assertNull($response->getLastModified()); + } + public function testIsInvalid() { $response = new Response(); @@ -922,6 +977,13 @@ class ResponseTest extends ResponseTestCase return $date->setTimestamp(time()); } + protected function createDateTimeImmutableNow() + { + $date = new \DateTimeImmutable(); + + return $date->setTimestamp(time()); + } + protected function provideResponse() { return new Response(); @@ -1000,14 +1062,3 @@ class StringableObject class DefaultResponse extends Response { } - -class ExtendedResponse extends Response -{ - public function setLastModified(\DateTime $date = null) - { - } - - public function getDate() - { - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php b/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php index 43644e23ea..8c41e47510 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Attribute/AttributeBagTest.php @@ -45,7 +45,7 @@ class AttributeBagTest extends TestCase ), ), ); - $this->bag = new AttributeBag('_sf2'); + $this->bag = new AttributeBag('_sf'); $this->bag->initialize($this->array); } @@ -67,7 +67,7 @@ class AttributeBagTest extends TestCase public function testGetStorageKey() { - $this->assertEquals('_sf2', $this->bag->getStorageKey()); + $this->assertEquals('_sf', $this->bag->getStorageKey()); $attributeBag = new AttributeBag('test'); $this->assertEquals('test', $attributeBag->getStorageKey()); } diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php new file mode 100644 index 0000000000..a2bf168de4 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractRedisSessionHandlerTestCase.php @@ -0,0 +1,145 @@ +<?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\Session\Storage\Handler; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\RedisSessionHandler; + +/** + * @requires extension redis + * @group time-sensitive + */ +abstract class AbstractRedisSessionHandlerTestCase extends TestCase +{ + protected const PREFIX = 'prefix_'; + + /** + * @var RedisSessionHandler + */ + protected $storage; + + /** + * @var \Redis|\RedisArray|\RedisCluster|\Predis\Client + */ + protected $redisClient; + + /** + * @return \Redis|\RedisArray|\RedisCluster|\Predis\Client + */ + abstract protected function createRedisClient(string $host); + + protected function setUp() + { + parent::setUp(); + + if (!\extension_loaded('redis')) { + self::markTestSkipped('Extension redis required.'); + } + + $host = getenv('REDIS_HOST') ?: 'localhost'; + + $this->redisClient = $this->createRedisClient($host); + $this->storage = new RedisSessionHandler( + $this->redisClient, + array('prefix' => self::PREFIX) + ); + } + + protected function tearDown() + { + $this->redisClient = null; + $this->storage = null; + + parent::tearDown(); + } + + public function testOpenSession() + { + $this->assertTrue($this->storage->open('', '')); + } + + public function testCloseSession() + { + $this->assertTrue($this->storage->close()); + } + + public function testReadSession() + { + $this->redisClient->set(self::PREFIX.'id1', null); + $this->redisClient->set(self::PREFIX.'id2', 'abc123'); + + $this->assertEquals('', $this->storage->read('id1')); + $this->assertEquals('abc123', $this->storage->read('id2')); + } + + public function testWriteSession() + { + $this->assertTrue($this->storage->write('id', 'data')); + + $this->assertTrue((bool) $this->redisClient->exists(self::PREFIX.'id')); + $this->assertEquals('data', $this->redisClient->get(self::PREFIX.'id')); + } + + public function testUseSessionGcMaxLifetimeAsTimeToLive() + { + $this->storage->write('id', 'data'); + $ttl = $this->redisClient->ttl(self::PREFIX.'id'); + + $this->assertLessThanOrEqual(ini_get('session.gc_maxlifetime'), $ttl); + $this->assertGreaterThanOrEqual(0, $ttl); + } + + public function testDestroySession() + { + $this->redisClient->set(self::PREFIX.'id', 'foo'); + + $this->assertTrue((bool) $this->redisClient->exists(self::PREFIX.'id')); + $this->assertTrue($this->storage->destroy('id')); + $this->assertFalse((bool) $this->redisClient->exists(self::PREFIX.'id')); + } + + public function testGcSession() + { + $this->assertTrue($this->storage->gc(123)); + } + + public function testUpdateTimestamp() + { + $lowTtl = 10; + + $this->redisClient->setex(self::PREFIX.'id', $lowTtl, 'foo'); + $this->storage->updateTimestamp('id', array()); + + $this->assertGreaterThan($lowTtl, $this->redisClient->ttl(self::PREFIX.'id')); + } + + /** + * @dataProvider getOptionFixtures + */ + public function testSupportedParam(array $options, bool $supported) + { + try { + new RedisSessionHandler($this->redisClient, $options); + $this->assertTrue($supported); + } catch (\InvalidArgumentException $e) { + $this->assertFalse($supported); + } + } + + public function getOptionFixtures(): array + { + return array( + array(array('prefix' => 'session'), true), + array(array('prefix' => 'sfs', 'foo' => 'bar'), false), + ); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php index 3ac081e388..6566d6eee4 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/AbstractSessionHandlerTest.php @@ -13,9 +13,6 @@ namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; use PHPUnit\Framework\TestCase; -/** - * @requires PHP 7.0 - */ class AbstractSessionHandlerTest extends TestCase { private static $server; diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected new file mode 100644 index 0000000000..d20fb88ec0 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.expected @@ -0,0 +1,16 @@ +open +validateId +read +doRead: +read + +write +doWrite: foo|s:3:"bar"; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax +) +shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php new file mode 100644 index 0000000000..2d32792a8f --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite.php @@ -0,0 +1,13 @@ +<?php + +require __DIR__.'/common.inc'; + +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; + +$storage = new NativeSessionStorage(array('cookie_samesite' => 'lax')); +$storage->setSaveHandler(new TestSessionHandler()); +$storage->start(); + +$_SESSION = array('foo' => 'bar'); + +ob_start(function ($buffer) { return str_replace(session_id(), 'random_session_id', $buffer); }); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected new file mode 100644 index 0000000000..8b5fc08bd3 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.expected @@ -0,0 +1,23 @@ +open +validateId +read +doRead: +read +destroy +close +open +validateId +read +doRead: +read + +write +doWrite: foo|s:3:"bar"; +close +Array +( + [0] => Content-Type: text/plain; charset=utf-8 + [1] => Cache-Control: max-age=0, private, must-revalidate + [2] => Set-Cookie: sid=random_session_id; path=/; secure; HttpOnly; SameSite=lax +) +shutdown diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php new file mode 100644 index 0000000000..e0ff64b951 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/Fixtures/with_samesite_and_migration.php @@ -0,0 +1,15 @@ +<?php + +require __DIR__.'/common.inc'; + +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; + +$storage = new NativeSessionStorage(array('cookie_samesite' => 'lax')); +$storage->setSaveHandler(new TestSessionHandler()); +$storage->start(); + +$_SESSION = array('foo' => 'bar'); + +$storage->regenerate(true); + +ob_start(function ($buffer) { return preg_replace('~_sf2_meta.*$~m', '', str_replace(session_id(), 'random_session_id', $buffer)); }); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php deleted file mode 100644 index d3d31762ae..0000000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php +++ /dev/null @@ -1,135 +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\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\MemcacheSessionHandler; - -/** - * @requires extension memcache - * @group time-sensitive - * @group legacy - */ -class MemcacheSessionHandlerTest extends TestCase -{ - const PREFIX = 'prefix_'; - const TTL = 1000; - - /** - * @var MemcacheSessionHandler - */ - protected $storage; - - protected $memcache; - - protected function setUp() - { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the Memcache class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - - parent::setUp(); - $this->memcache = $this->getMockBuilder('Memcache')->getMock(); - $this->storage = new MemcacheSessionHandler( - $this->memcache, - array('prefix' => self::PREFIX, 'expiretime' => self::TTL) - ); - } - - protected function tearDown() - { - $this->memcache = null; - $this->storage = null; - parent::tearDown(); - } - - public function testOpenSession() - { - $this->assertTrue($this->storage->open('', '')); - } - - public function testCloseSession() - { - $this->assertTrue($this->storage->close()); - } - - public function testReadSession() - { - $this->memcache - ->expects($this->once()) - ->method('get') - ->with(self::PREFIX.'id') - ; - - $this->assertEquals('', $this->storage->read('id')); - } - - public function testWriteSession() - { - $this->memcache - ->expects($this->once()) - ->method('set') - ->with(self::PREFIX.'id', 'data', 0, $this->equalTo(time() + self::TTL, 2)) - ->will($this->returnValue(true)) - ; - - $this->assertTrue($this->storage->write('id', 'data')); - } - - public function testDestroySession() - { - $this->memcache - ->expects($this->once()) - ->method('delete') - ->with(self::PREFIX.'id') - ->will($this->returnValue(true)) - ; - - $this->assertTrue($this->storage->destroy('id')); - } - - public function testGcSession() - { - $this->assertTrue($this->storage->gc(123)); - } - - /** - * @dataProvider getOptionFixtures - */ - public function testSupportedOptions($options, $supported) - { - try { - new MemcacheSessionHandler($this->memcache, $options); - $this->assertTrue($supported); - } catch (\InvalidArgumentException $e) { - $this->assertFalse($supported); - } - } - - public function getOptionFixtures() - { - return array( - array(array('prefix' => 'session'), true), - array(array('expiretime' => 100), true), - array(array('prefix' => 'session', 'expiretime' => 200), true), - array(array('expiretime' => 100, 'foo' => 'bar'), false), - ); - } - - public function testGetConnection() - { - $method = new \ReflectionMethod($this->storage, 'getMemcache'); - $method->setAccessible(true); - - $this->assertInstanceOf('\Memcache', $method->invoke($this->storage)); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php index 2a11480105..5bb2db0699 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php @@ -32,10 +32,6 @@ class MemcachedSessionHandlerTest extends TestCase protected function setUp() { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the Memcached class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - parent::setUp(); if (version_compare(phpversion('memcached'), '2.2.0', '>=') && version_compare(phpversion('memcached'), '3.0.0b1', '<')) { diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MigratingSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MigratingSessionHandlerTest.php new file mode 100644 index 0000000000..1c0f3ca663 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MigratingSessionHandlerTest.php @@ -0,0 +1,186 @@ +<?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\Session\Storage\Handler; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\MigratingSessionHandler; + +class MigratingSessionHandlerTest extends TestCase +{ + private $dualHandler; + private $currentHandler; + private $writeOnlyHandler; + + protected function setUp() + { + $this->currentHandler = $this->createMock(\SessionHandlerInterface::class); + $this->writeOnlyHandler = $this->createMock(\SessionHandlerInterface::class); + + $this->dualHandler = new MigratingSessionHandler($this->currentHandler, $this->writeOnlyHandler); + } + + public function testInstanceOf() + { + $this->assertInstanceOf(\SessionHandlerInterface::class, $this->dualHandler); + $this->assertInstanceOf(\SessionUpdateTimestampHandlerInterface::class, $this->dualHandler); + } + + public function testClose() + { + $this->currentHandler->expects($this->once()) + ->method('close') + ->will($this->returnValue(true)); + + $this->writeOnlyHandler->expects($this->once()) + ->method('close') + ->will($this->returnValue(false)); + + $result = $this->dualHandler->close(); + + $this->assertTrue($result); + } + + public function testDestroy() + { + $sessionId = 'xyz'; + + $this->currentHandler->expects($this->once()) + ->method('destroy') + ->with($sessionId) + ->will($this->returnValue(true)); + + $this->writeOnlyHandler->expects($this->once()) + ->method('destroy') + ->with($sessionId) + ->will($this->returnValue(false)); + + $result = $this->dualHandler->destroy($sessionId); + + $this->assertTrue($result); + } + + public function testGc() + { + $maxlifetime = 357; + + $this->currentHandler->expects($this->once()) + ->method('gc') + ->with($maxlifetime) + ->will($this->returnValue(true)); + + $this->writeOnlyHandler->expects($this->once()) + ->method('gc') + ->with($maxlifetime) + ->will($this->returnValue(false)); + + $result = $this->dualHandler->gc($maxlifetime); + $this->assertTrue($result); + } + + public function testOpen() + { + $savePath = '/path/to/save/location'; + $sessionName = 'xyz'; + + $this->currentHandler->expects($this->once()) + ->method('open') + ->with($savePath, $sessionName) + ->will($this->returnValue(true)); + + $this->writeOnlyHandler->expects($this->once()) + ->method('open') + ->with($savePath, $sessionName) + ->will($this->returnValue(false)); + + $result = $this->dualHandler->open($savePath, $sessionName); + + $this->assertTrue($result); + } + + public function testRead() + { + $sessionId = 'xyz'; + $readValue = 'something'; + + $this->currentHandler->expects($this->once()) + ->method('read') + ->with($sessionId) + ->will($this->returnValue($readValue)); + + $this->writeOnlyHandler->expects($this->never()) + ->method('read') + ->with($this->any()); + + $result = $this->dualHandler->read($sessionId); + + $this->assertSame($readValue, $result); + } + + public function testWrite() + { + $sessionId = 'xyz'; + $data = 'my-serialized-data'; + + $this->currentHandler->expects($this->once()) + ->method('write') + ->with($sessionId, $data) + ->will($this->returnValue(true)); + + $this->writeOnlyHandler->expects($this->once()) + ->method('write') + ->with($sessionId, $data) + ->will($this->returnValue(false)); + + $result = $this->dualHandler->write($sessionId, $data); + + $this->assertTrue($result); + } + + public function testValidateId() + { + $sessionId = 'xyz'; + $readValue = 'something'; + + $this->currentHandler->expects($this->once()) + ->method('read') + ->with($sessionId) + ->will($this->returnValue($readValue)); + + $this->writeOnlyHandler->expects($this->never()) + ->method('read') + ->with($this->any()); + + $result = $this->dualHandler->validateId($sessionId); + + $this->assertTrue($result); + } + + public function testUpdateTimestamp() + { + $sessionId = 'xyz'; + $data = 'my-serialized-data'; + + $this->currentHandler->expects($this->once()) + ->method('write') + ->with($sessionId, $data) + ->will($this->returnValue(true)); + + $this->writeOnlyHandler->expects($this->once()) + ->method('write') + ->with($sessionId, $data) + ->will($this->returnValue(false)); + + $result = $this->dualHandler->updateTimestamp($sessionId, $data); + + $this->assertTrue($result); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php index 186fc0a2d0..c585fd4f1b 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php @@ -17,7 +17,7 @@ use Symfony\Component\HttpFoundation\Session\Storage\Handler\MongoDbSessionHandl /** * @author Markus Bachmann <markus.bachmann@bachi.biz> * @group time-sensitive - * @group legacy + * @requires extension mongodb */ class MongoDbSessionHandlerTest extends TestCase { @@ -32,21 +32,11 @@ class MongoDbSessionHandlerTest extends TestCase { parent::setUp(); - if (\extension_loaded('mongodb')) { - if (!class_exists('MongoDB\Client')) { - $this->markTestSkipped('The mongodb/mongodb package is required.'); - } - } elseif (!\extension_loaded('mongo')) { - $this->markTestSkipped('The Mongo or MongoDB extension is required.'); + if (!class_exists(\MongoDB\Client::class)) { + $this->markTestSkipped('The mongodb/mongodb package is required.'); } - if (phpversion('mongodb')) { - $mongoClass = 'MongoDB\Client'; - } else { - $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; - } - - $this->mongo = $this->getMockBuilder($mongoClass) + $this->mongo = $this->getMockBuilder(\MongoDB\Client::class) ->disableOriginalConstructor() ->getMock(); @@ -55,7 +45,7 @@ class MongoDbSessionHandlerTest extends TestCase 'data_field' => 'data', 'time_field' => 'time', 'expiry_field' => 'expires_at', - 'database' => 'sf2-test', + 'database' => 'sf-test', 'collection' => 'session-test', ); @@ -65,14 +55,6 @@ class MongoDbSessionHandlerTest extends TestCase /** * @expectedException \InvalidArgumentException */ - public function testConstructorShouldThrowExceptionForInvalidMongo() - { - new MongoDbSessionHandler(new \stdClass(), $this->options); - } - - /** - * @expectedException \InvalidArgumentException - */ public function testConstructorShouldThrowExceptionForMissingOptions() { new MongoDbSessionHandler($this->mongo, array()); @@ -110,27 +92,14 @@ class MongoDbSessionHandlerTest extends TestCase $this->assertArrayHasKey($this->options['expiry_field'], $criteria); $this->assertArrayHasKey('$gte', $criteria[$this->options['expiry_field']]); - if (phpversion('mongodb')) { - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$gte']); - $this->assertGreaterThanOrEqual(round((string) $criteria[$this->options['expiry_field']]['$gte'] / 1000), $testTimeout); - } else { - $this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$gte']); - $this->assertGreaterThanOrEqual($criteria[$this->options['expiry_field']]['$gte']->sec, $testTimeout); - } + $this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $criteria[$this->options['expiry_field']]['$gte']); + $this->assertGreaterThanOrEqual(round((string) $criteria[$this->options['expiry_field']]['$gte'] / 1000), $testTimeout); - $fields = array( + return array( $this->options['id_field'] => 'foo', + $this->options['expiry_field'] => new \MongoDB\BSON\UTCDateTime(), + $this->options['data_field'] => new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY), ); - - if (phpversion('mongodb')) { - $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY); - $fields[$this->options['id_field']] = new \MongoDB\BSON\UTCDateTime(time() * 1000); - } else { - $fields[$this->options['data_field']] = new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY); - $fields[$this->options['id_field']] = new \MongoDate(); - } - - return $fields; })); $this->assertEquals('bar', $this->storage->read('foo')); @@ -145,89 +114,22 @@ class MongoDbSessionHandlerTest extends TestCase ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); - $data = array(); - - $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; - - $collection->expects($this->once()) - ->method($methodName) - ->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) { - $this->assertEquals(array($this->options['id_field'] => 'foo'), $criteria); - - if (phpversion('mongodb')) { - $this->assertEquals(array('upsert' => true), $options); - } else { - $this->assertEquals(array('upsert' => true, 'multiple' => false), $options); - } - - $data = $updateData['$set']; - })); - - $expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime'); - $this->assertTrue($this->storage->write('foo', 'bar')); - - if (phpversion('mongodb')) { - $this->assertEquals('bar', $data[$this->options['data_field']]->getData()); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]); - $this->assertGreaterThanOrEqual($expectedExpiry, round((string) $data[$this->options['expiry_field']] / 1000)); - } else { - $this->assertEquals('bar', $data[$this->options['data_field']]->bin); - $this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]); - $this->assertGreaterThanOrEqual($expectedExpiry, $data[$this->options['expiry_field']]->sec); - } - } - - public function testWriteWhenUsingExpiresField() - { - $this->options = array( - 'id_field' => '_id', - 'data_field' => 'data', - 'time_field' => 'time', - 'database' => 'sf2-test', - 'collection' => 'session-test', - 'expiry_field' => 'expiresAt', - ); - - $this->storage = new MongoDbSessionHandler($this->mongo, $this->options); - - $collection = $this->createMongoCollectionMock(); - - $this->mongo->expects($this->once()) - ->method('selectCollection') - ->with($this->options['database'], $this->options['collection']) - ->will($this->returnValue($collection)); - - $data = array(); - - $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; - $collection->expects($this->once()) - ->method($methodName) - ->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) { + ->method('updateOne') + ->will($this->returnCallback(function ($criteria, $updateData, $options) { $this->assertEquals(array($this->options['id_field'] => 'foo'), $criteria); - - if (phpversion('mongodb')) { - $this->assertEquals(array('upsert' => true), $options); - } else { - $this->assertEquals(array('upsert' => true, 'multiple' => false), $options); - } + $this->assertEquals(array('upsert' => true), $options); $data = $updateData['$set']; + $expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime'); + $this->assertInstanceOf(\MongoDB\BSON\Binary::class, $data[$this->options['data_field']]); + $this->assertEquals('bar', $data[$this->options['data_field']]->getData()); + $this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $data[$this->options['time_field']]); + $this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $data[$this->options['expiry_field']]); + $this->assertGreaterThanOrEqual($expectedExpiry, round((string) $data[$this->options['expiry_field']] / 1000)); })); $this->assertTrue($this->storage->write('foo', 'bar')); - - if (phpversion('mongodb')) { - $this->assertEquals('bar', $data[$this->options['data_field']]->getData()); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$this->options['expiry_field']]); - } else { - $this->assertEquals('bar', $data[$this->options['data_field']]->bin); - $this->assertInstanceOf('MongoDate', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]); - } } public function testReplaceSessionData() @@ -241,10 +143,8 @@ class MongoDbSessionHandlerTest extends TestCase $data = array(); - $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; - $collection->expects($this->exactly(2)) - ->method($methodName) + ->method('updateOne') ->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) { $data = $updateData; })); @@ -252,11 +152,7 @@ class MongoDbSessionHandlerTest extends TestCase $this->storage->write('foo', 'bar'); $this->storage->write('foo', 'foobar'); - if (phpversion('mongodb')) { - $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData()); - } else { - $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin); - } + $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData()); } public function testDestroy() @@ -268,10 +164,8 @@ class MongoDbSessionHandlerTest extends TestCase ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); - $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove'; - $collection->expects($this->once()) - ->method($methodName) + ->method('deleteOne') ->with(array($this->options['id_field'] => 'foo')); $this->assertTrue($this->storage->destroy('foo')); @@ -286,18 +180,11 @@ class MongoDbSessionHandlerTest extends TestCase ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); - $methodName = phpversion('mongodb') ? 'deleteMany' : 'remove'; - $collection->expects($this->once()) - ->method($methodName) + ->method('deleteMany') ->will($this->returnCallback(function ($criteria) { - if (phpversion('mongodb')) { - $this->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$this->options['expiry_field']]['$lt']); - $this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000)); - } else { - $this->assertInstanceOf('MongoDate', $criteria[$this->options['expiry_field']]['$lt']); - $this->assertGreaterThanOrEqual(time() - 1, $criteria[$this->options['expiry_field']]['$lt']->sec); - } + $this->assertInstanceOf(\MongoDB\BSON\UTCDateTime::class, $criteria[$this->options['expiry_field']]['$lt']); + $this->assertGreaterThanOrEqual(time() - 1, round((string) $criteria[$this->options['expiry_field']]['$lt'] / 1000)); })); $this->assertTrue($this->storage->gc(1)); @@ -308,23 +195,12 @@ class MongoDbSessionHandlerTest extends TestCase $method = new \ReflectionMethod($this->storage, 'getMongo'); $method->setAccessible(true); - if (phpversion('mongodb')) { - $mongoClass = 'MongoDB\Client'; - } else { - $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; - } - - $this->assertInstanceOf($mongoClass, $method->invoke($this->storage)); + $this->assertInstanceOf(\MongoDB\Client::class, $method->invoke($this->storage)); } private function createMongoCollectionMock() { - $collectionClass = 'MongoCollection'; - if (phpversion('mongodb')) { - $collectionClass = 'MongoDB\Collection'; - } - - $collection = $this->getMockBuilder($collectionClass) + $collection = $this->getMockBuilder(\MongoDB\Collection::class) ->disableOriginalConstructor() ->getMock(); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php index a6264e51d2..95e725f4bc 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php @@ -29,7 +29,6 @@ class NativeFileSessionHandlerTest extends TestCase { $storage = new NativeSessionStorage(array('name' => 'TESTING'), new NativeFileSessionHandler(sys_get_temp_dir())); - $this->assertEquals('files', $storage->getSaveHandler()->getSaveHandlerName()); $this->assertEquals('user', ini_get('session.save_handler')); $this->assertEquals(sys_get_temp_dir(), ini_get('session.save_path')); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php deleted file mode 100644 index 4a9fb600d2..0000000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/NativeSessionHandlerTest.php +++ /dev/null @@ -1,38 +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\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler; - -/** - * Test class for NativeSessionHandler. - * - * @author Drak <drak@zikula.org> - * - * @runTestsInSeparateProcesses - * @preserveGlobalState disabled - * @group legacy - */ -class NativeSessionHandlerTest extends TestCase -{ - /** - * @expectedDeprecation The Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeSessionHandler class is deprecated since Symfony 3.4 and will be removed in 4.0. Use the \SessionHandler class instead. - */ - public function testConstruct() - { - $handler = new NativeSessionHandler(); - - $this->assertInstanceOf('SessionHandler', $handler); - $this->assertTrue($handler instanceof NativeSessionHandler); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php index 3060452e9e..0a65eaa8e4 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php @@ -33,7 +33,7 @@ class PdoSessionHandlerTest extends TestCase protected function getPersistentSqliteDsn() { - $this->dbFile = tempnam(sys_get_temp_dir(), 'sf2_sqlite_sessions'); + $this->dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_sessions'); return 'sqlite:'.$this->dbFile; } @@ -136,10 +136,6 @@ class PdoSessionHandlerTest extends TestCase public function testReadConvertsStreamToString() { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - $pdo = new MockPdo('pgsql'); $pdo->prepareResult = $this->getMockBuilder('PDOStatement')->getMock(); @@ -157,10 +153,7 @@ class PdoSessionHandlerTest extends TestCase public function testReadLockedConvertsStreamToString() { - if (\defined('HHVM_VERSION')) { - $this->markTestSkipped('PHPUnit_MockObject cannot mock the PDOStatement class on HHVM. See https://github.com/sebastianbergmann/phpunit-mock-objects/pull/289'); - } - if (ini_get('session.use_strict_mode')) { + if (filter_var(ini_get('session.use_strict_mode'), FILTER_VALIDATE_BOOLEAN)) { $this->markTestSkipped('Strict mode needs no locking for new sessions.'); } diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php new file mode 100644 index 0000000000..458100101c --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisClusterSessionHandlerTest.php @@ -0,0 +1,22 @@ +<?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\Session\Storage\Handler; + +use Predis\Client; + +class PredisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase +{ + protected function createRedisClient(string $host): Client + { + return new Client(array(array('host' => $host))); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisSessionHandlerTest.php new file mode 100644 index 0000000000..a9db4eb1bf --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/PredisSessionHandlerTest.php @@ -0,0 +1,22 @@ +<?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\Session\Storage\Handler; + +use Predis\Client; + +class PredisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase +{ + protected function createRedisClient(string $host): Client + { + return new Client(array('host' => $host)); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisArraySessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisArraySessionHandlerTest.php new file mode 100644 index 0000000000..d263e18ff7 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisArraySessionHandlerTest.php @@ -0,0 +1,20 @@ +<?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\Session\Storage\Handler; + +class RedisArraySessionHandlerTest extends AbstractRedisSessionHandlerTestCase +{ + protected function createRedisClient(string $host): \RedisArray + { + return new \RedisArray(array($host)); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.php new file mode 100644 index 0000000000..7d85a59ee7 --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisClusterSessionHandlerTest.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\HttpFoundation\Tests\Session\Storage\Handler; + +class RedisClusterSessionHandlerTest extends AbstractRedisSessionHandlerTestCase +{ + public static function setupBeforeClass() + { + if (!class_exists('RedisCluster')) { + self::markTestSkipped('The RedisCluster class is required.'); + } + + if (!$hosts = getenv('REDIS_CLUSTER_HOSTS')) { + self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); + } + } + + protected function createRedisClient(string $host): \RedisCluster + { + return new \RedisCluster(null, explode(' ', getenv('REDIS_CLUSTER_HOSTS'))); + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisSessionHandlerTest.php new file mode 100644 index 0000000000..afdb6c503b --- /dev/null +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/RedisSessionHandlerTest.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\HttpFoundation\Tests\Session\Storage\Handler; + +class RedisSessionHandlerTest extends AbstractRedisSessionHandlerTestCase +{ + protected function createRedisClient(string $host): \Redis + { + $client = new \Redis(); + $client->connect($host); + + return $client; + } +} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php deleted file mode 100644 index 898a7d11a5..0000000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Handler/WriteCheckSessionHandlerTest.php +++ /dev/null @@ -1,97 +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\HttpFoundation\Tests\Session\Storage\Handler; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler; - -/** - * @author Adrien Brault <adrien.brault@gmail.com> - * - * @group legacy - */ -class WriteCheckSessionHandlerTest extends TestCase -{ - public function test() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('close') - ->with() - ->will($this->returnValue(true)) - ; - - $this->assertTrue($writeCheckSessionHandler->close()); - } - - public function testWrite() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('write') - ->with('foo', 'bar') - ->will($this->returnValue(true)) - ; - - $this->assertTrue($writeCheckSessionHandler->write('foo', 'bar')); - } - - public function testSkippedWrite() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('read') - ->with('foo') - ->will($this->returnValue('bar')) - ; - - $wrappedSessionHandlerMock - ->expects($this->never()) - ->method('write') - ; - - $this->assertEquals('bar', $writeCheckSessionHandler->read('foo')); - $this->assertTrue($writeCheckSessionHandler->write('foo', 'bar')); - } - - public function testNonSkippedWrite() - { - $wrappedSessionHandlerMock = $this->getMockBuilder('SessionHandlerInterface')->getMock(); - $writeCheckSessionHandler = new WriteCheckSessionHandler($wrappedSessionHandlerMock); - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('read') - ->with('foo') - ->will($this->returnValue('bar')) - ; - - $wrappedSessionHandlerMock - ->expects($this->once()) - ->method('write') - ->with('foo', 'baZZZ') - ->will($this->returnValue(true)) - ; - - $this->assertEquals('bar', $writeCheckSessionHandler->read('foo')); - $this->assertTrue($writeCheckSessionHandler->write('foo', 'baZZZ')); - } -} diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php index 1695798175..f8394d8cab 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/MockFileSessionStorageTest.php @@ -35,7 +35,7 @@ class MockFileSessionStorageTest extends TestCase protected function setUp() { - $this->sessionDir = sys_get_temp_dir().'/sf2test'; + $this->sessionDir = sys_get_temp_dir().'/sftest'; $this->storage = $this->getStorage(); } diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php index 52da2947cb..8ce703b34e 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/NativeSessionStorageTest.php @@ -36,7 +36,7 @@ class NativeSessionStorageTest extends TestCase protected function setUp() { $this->iniSet('session.save_handler', 'files'); - $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sf2test'); + $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sftest'); if (!is_dir($this->savePath)) { mkdir($this->savePath); } @@ -171,6 +171,10 @@ class NativeSessionStorageTest extends TestCase 'cookie_httponly' => false, ); + if (\PHP_VERSION_ID >= 70300) { + $options['cookie_samesite'] = 'lax'; + } + $this->getStorage($options); $temp = session_get_cookie_params(); $gco = array(); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php index 7cb63c5aac..a5a8561465 100644 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php +++ b/vendor/symfony/http-foundation/Tests/Session/Storage/PhpBridgeSessionStorageTest.php @@ -32,7 +32,7 @@ class PhpBridgeSessionStorageTest extends TestCase protected function setUp() { $this->iniSet('session.save_handler', 'files'); - $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sf2test'); + $this->iniSet('session.save_path', $this->savePath = sys_get_temp_dir().'/sftest'); if (!is_dir($this->savePath)) { mkdir($this->savePath); } @@ -64,13 +64,12 @@ class PhpBridgeSessionStorageTest extends TestCase { $storage = $this->getStorage(); - $this->assertFalse($storage->getSaveHandler()->isActive()); + $this->assertNotSame(\PHP_SESSION_ACTIVE, session_status()); $this->assertFalse($storage->isStarted()); session_start(); $this->assertTrue(isset($_SESSION)); - // in PHP 5.4 we can reliably detect a session started - $this->assertTrue($storage->getSaveHandler()->isActive()); + $this->assertSame(\PHP_SESSION_ACTIVE, session_status()); // PHP session might have started, but the storage driver has not, so false is correct here $this->assertFalse($storage->isStarted()); diff --git a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php b/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php deleted file mode 100644 index ed4fee6bfe..0000000000 --- a/vendor/symfony/http-foundation/Tests/Session/Storage/Proxy/NativeProxyTest.php +++ /dev/null @@ -1,38 +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\HttpFoundation\Tests\Session\Storage\Proxy; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Session\Storage\Proxy\NativeProxy; - -/** - * Test class for NativeProxy. - * - * @group legacy - * - * @author Drak <drak@zikula.org> - */ -class NativeProxyTest extends TestCase -{ - public function testIsWrapper() - { - $proxy = new NativeProxy(); - $this->assertFalse($proxy->isWrapper()); - } - - public function testGetSaveHandlerName() - { - $name = ini_get('session.save_handler'); - $proxy = new NativeProxy(); - $this->assertEquals($name, $proxy->getSaveHandlerName()); - } -} diff --git a/vendor/symfony/http-foundation/composer.json b/vendor/symfony/http-foundation/composer.json index f6c6f2e623..76381a7c46 100644 --- a/vendor/symfony/http-foundation/composer.json +++ b/vendor/symfony/http-foundation/composer.json @@ -16,12 +16,12 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php70": "~1.6" + "php": "^7.1.3", + "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { - "symfony/expression-language": "~2.8|~3.0|~4.0" + "predis/predis": "~1.0", + "symfony/expression-language": "~3.4|~4.0" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" }, @@ -32,7 +32,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } } } diff --git a/vendor/symfony/http-foundation/phpunit.xml.dist b/vendor/symfony/http-foundation/phpunit.xml.dist index c1d61f8bf1..f57bc9e62d 100644 --- a/vendor/symfony/http-foundation/phpunit.xml.dist +++ b/vendor/symfony/http-foundation/phpunit.xml.dist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" diff --git a/vendor/symfony/http-kernel/Bundle/Bundle.php b/vendor/symfony/http-kernel/Bundle/Bundle.php index f42895a733..26dea9b205 100644 --- a/vendor/symfony/http-kernel/Bundle/Bundle.php +++ b/vendor/symfony/http-kernel/Bundle/Bundle.php @@ -16,7 +16,6 @@ use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAwareTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Extension\ExtensionInterface; -use Symfony\Component\Finder\Finder; /** * An implementation of BundleInterface that adds a few conventions @@ -119,14 +118,9 @@ abstract class Bundle implements BundleInterface } /** - * {@inheritdoc} - */ - public function getParent() - { - } - - /** - * {@inheritdoc} + * Returns the bundle name (the class short name). + * + * @return string The Bundle name */ final public function getName() { @@ -137,48 +131,8 @@ abstract class Bundle implements BundleInterface return $this->name; } - /** - * Finds and registers Commands. - * - * Override this method if your bundle commands do not follow the conventions: - * - * * Commands are in the 'Command' sub-directory - * * Commands extend Symfony\Component\Console\Command\Command - */ public function registerCommands(Application $application) { - if (!is_dir($dir = $this->getPath().'/Command')) { - return; - } - - if (!class_exists('Symfony\Component\Finder\Finder')) { - throw new \RuntimeException('You need the symfony/finder component to register bundle commands.'); - } - - $finder = new Finder(); - $finder->files()->name('*Command.php')->in($dir); - - $prefix = $this->getNamespace().'\\Command'; - foreach ($finder as $file) { - $ns = $prefix; - if ($relativePath = $file->getRelativePath()) { - $ns .= '\\'.str_replace('/', '\\', $relativePath); - } - $class = $ns.'\\'.$file->getBasename('.php'); - if ($this->container) { - $commandIds = $this->container->hasParameter('console.command.ids') ? $this->container->getParameter('console.command.ids') : array(); - $alias = 'console.command.'.strtolower(str_replace('\\', '_', $class)); - if (isset($commandIds[$alias]) || $this->container->has($alias)) { - continue; - } - } - $r = new \ReflectionClass($class); - if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract() && !$r->getConstructor()->getNumberOfRequiredParameters()) { - @trigger_error(sprintf('Auto-registration of the command "%s" is deprecated since Symfony 3.4 and won\'t be supported in 4.0. Use PSR-4 based service discovery instead.', $class), E_USER_DEPRECATED); - - $application->add($r->newInstance()); - } - } } /** diff --git a/vendor/symfony/http-kernel/Bundle/BundleInterface.php b/vendor/symfony/http-kernel/Bundle/BundleInterface.php index 14a7f6f4fd..88a95d8332 100644 --- a/vendor/symfony/http-kernel/Bundle/BundleInterface.php +++ b/vendor/symfony/http-kernel/Bundle/BundleInterface.php @@ -47,19 +47,6 @@ interface BundleInterface extends ContainerAwareInterface public function getContainerExtension(); /** - * Returns the bundle name that this bundle overrides. - * - * Despite its name, this method does not imply any parent/child relationship - * between the bundles, just a way to extend and override an existing - * bundle. - * - * @return string The Bundle name it overrides or null if no parent - * - * @deprecated This method is deprecated as of 3.4 and will be removed in 4.0. - */ - public function getParent(); - - /** * Returns the bundle name (the class short name). * * @return string The Bundle name diff --git a/vendor/symfony/http-kernel/CHANGELOG.md b/vendor/symfony/http-kernel/CHANGELOG.md index fb29f76962..b96b4aefa1 100644 --- a/vendor/symfony/http-kernel/CHANGELOG.md +++ b/vendor/symfony/http-kernel/CHANGELOG.md @@ -1,6 +1,48 @@ CHANGELOG ========= +4.2.0 +----- + + * deprecated `KernelInterface::getRootDir()` and the `kernel.root_dir` parameter + * deprecated `KernelInterface::getName()` and the `kernel.name` parameter + * deprecated the first and second constructor argument of `ConfigDataCollector` + * deprecated `ConfigDataCollector::getApplicationName()` + * deprecated `ConfigDataCollector::getApplicationVersion()` + +4.1.0 +----- + + * added orphaned events support to `EventDataCollector` + * `ExceptionListener` now logs exceptions at priority `0` (previously logged at `-128`) + * Added support for using `service::method` to reference controllers, making it consistent with other cases. It is recommended over the `service:action` syntax with a single colon, which will be deprecated in the future. + * Added the ability to profile individual argument value resolvers via the + `Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver` + +4.0.0 +----- + + * removed the `DataCollector::varToString()` method, use `DataCollector::cloneVar()` + instead + * using the `DataCollector::cloneVar()` method requires the VarDumper component + * removed the `ValueExporter` class + * removed `ControllerResolverInterface::getArguments()` + * removed `TraceableControllerResolver::getArguments()` + * removed `ControllerResolver::getArguments()` and the ability to resolve arguments + * removed the `argument_resolver` service dependency from the `debug.controller_resolver` + * removed `LazyLoadingFragmentHandler::addRendererService()` + * removed `Psr6CacheClearer::addPool()` + * removed `Extension::addClassesToCompile()` and `Extension::getClassesToCompile()` + * removed `Kernel::loadClassCache()`, `Kernel::doLoadClassCache()`, `Kernel::setClassCache()`, + and `Kernel::getEnvParameters()` + * support for the `X-Status-Code` when handling exceptions in the `HttpKernel` + has been dropped, use the `HttpKernel::allowCustomResponseCode()` method + instead + * removed convention-based commands registration + * removed the `ChainCacheClearer::add()` method + * removed the `CacheaWarmerAggregate::add()` and `setWarmers()` methods + * made `CacheWarmerAggregate` and `ChainCacheClearer` classes final + 3.4.0 ----- diff --git a/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php b/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php index 8ee4275b16..a646119d99 100644 --- a/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php +++ b/vendor/symfony/http-kernel/CacheClearer/ChainCacheClearer.php @@ -16,18 +16,13 @@ namespace Symfony\Component\HttpKernel\CacheClearer; * * @author Dustin Dobervich <ddobervich@gmail.com> * - * @final since version 3.4 + * @final */ class ChainCacheClearer implements CacheClearerInterface { - protected $clearers; + private $clearers; - /** - * Constructs a new instance of ChainCacheClearer. - * - * @param array $clearers The initial clearers - */ - public function __construct($clearers = array()) + public function __construct(iterable $clearers = array()) { $this->clearers = $clearers; } @@ -41,16 +36,4 @@ class ChainCacheClearer implements CacheClearerInterface $clearer->clear($cacheDir); } } - - /** - * Adds a cache clearer to the aggregate. - * - * @deprecated since version 3.4, to be removed in 4.0, inject the list of clearers as a constructor argument instead. - */ - public function add(CacheClearerInterface $clearer) - { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0, inject the list of clearers as a constructor argument instead.', __METHOD__), E_USER_DEPRECATED); - - $this->clearers[] = $clearer; - } } diff --git a/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php b/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php index d413d2c9d6..d7db027072 100644 --- a/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php +++ b/vendor/symfony/http-kernel/CacheClearer/Psr6CacheClearer.php @@ -11,8 +11,6 @@ namespace Symfony\Component\HttpKernel\CacheClearer; -use Psr\Cache\CacheItemPoolInterface; - /** * @author Nicolas Grekas <p@tchwork.com> */ @@ -25,16 +23,18 @@ class Psr6CacheClearer implements CacheClearerInterface $this->pools = $pools; } - public function addPool(CacheItemPoolInterface $pool) + public function hasPool($name) { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Pass an array of pools indexed by name to the constructor instead.', __METHOD__), E_USER_DEPRECATED); - - $this->pools[] = $pool; + return isset($this->pools[$name]); } - public function hasPool($name) + public function getPool($name) { - return isset($this->pools[$name]); + if (!$this->hasPool($name)) { + throw new \InvalidArgumentException(sprintf('Cache pool not found: %s.', $name)); + } + + return $this->pools[$name]; } public function clearPool($name) diff --git a/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php b/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php index ca3911ed5f..171b38596f 100644 --- a/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php +++ b/vendor/symfony/http-kernel/CacheWarmer/CacheWarmerAggregate.php @@ -16,20 +16,21 @@ namespace Symfony\Component\HttpKernel\CacheWarmer; * * @author Fabien Potencier <fabien@symfony.com> * - * @final since version 3.4 + * @final */ class CacheWarmerAggregate implements CacheWarmerInterface { - protected $warmers = array(); - protected $optionalsEnabled = false; - private $triggerDeprecation = false; + private $warmers; + private $debug; + private $deprecationLogsFilepath; + private $optionalsEnabled = false; + private $onlyOptionalsEnabled = false; - public function __construct($warmers = array()) + public function __construct(iterable $warmers = array(), bool $debug = false, string $deprecationLogsFilepath = null) { - foreach ($warmers as $warmer) { - $this->add($warmer); - } - $this->triggerDeprecation = true; + $this->warmers = $warmers; + $this->debug = $debug; + $this->deprecationLogsFilepath = $deprecationLogsFilepath; } public function enableOptionalWarmers() @@ -37,6 +38,11 @@ class CacheWarmerAggregate implements CacheWarmerInterface $this->optionalsEnabled = true; } + public function enableOnlyOptionalWarmers() + { + $this->onlyOptionalsEnabled = $this->optionalsEnabled = true; + } + /** * Warms up the cache. * @@ -44,12 +50,62 @@ class CacheWarmerAggregate implements CacheWarmerInterface */ public function warmUp($cacheDir) { - foreach ($this->warmers as $warmer) { - if (!$this->optionalsEnabled && $warmer->isOptional()) { - continue; + if ($this->debug) { + $collectedLogs = array(); + $previousHandler = \defined('PHPUNIT_COMPOSER_INSTALL'); + $previousHandler = $previousHandler ?: set_error_handler(function ($type, $message, $file, $line) use (&$collectedLogs, &$previousHandler) { + if (E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) { + return $previousHandler ? $previousHandler($type, $message, $file, $line) : false; + } + + if (isset($collectedLogs[$message])) { + ++$collectedLogs[$message]['count']; + + return; + } + + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); + // Clean the trace by removing first frames added by the error handler itself. + for ($i = 0; isset($backtrace[$i]); ++$i) { + if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { + $backtrace = \array_slice($backtrace, 1 + $i); + break; + } + } + + $collectedLogs[$message] = array( + 'type' => $type, + 'message' => $message, + 'file' => $file, + 'line' => $line, + 'trace' => $backtrace, + 'count' => 1, + ); + }); + } + + try { + foreach ($this->warmers as $warmer) { + if (!$this->optionalsEnabled && $warmer->isOptional()) { + continue; + } + if ($this->onlyOptionalsEnabled && !$warmer->isOptional()) { + continue; + } + + $warmer->warmUp($cacheDir); } + } finally { + if ($this->debug && true !== $previousHandler) { + restore_error_handler(); - $warmer->warmUp($cacheDir); + if (file_exists($this->deprecationLogsFilepath)) { + $previousLogs = unserialize(file_get_contents($this->deprecationLogsFilepath)); + $collectedLogs = array_merge($previousLogs, $collectedLogs); + } + + file_put_contents($this->deprecationLogsFilepath, serialize(array_values($collectedLogs))); + } } } @@ -62,29 +118,4 @@ class CacheWarmerAggregate implements CacheWarmerInterface { return false; } - - /** - * @deprecated since version 3.4, to be removed in 4.0, inject the list of clearers as a constructor argument instead. - */ - public function setWarmers(array $warmers) - { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0, inject the list of clearers as a constructor argument instead.', __METHOD__), E_USER_DEPRECATED); - - $this->warmers = array(); - foreach ($warmers as $warmer) { - $this->add($warmer); - } - } - - /** - * @deprecated since version 3.4, to be removed in 4.0, inject the list of clearers as a constructor argument instead. - */ - public function add(CacheWarmerInterface $warmer) - { - if ($this->triggerDeprecation) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 3.4 and will be removed in 4.0, inject the list of clearers as a constructor argument instead.', __METHOD__), E_USER_DEPRECATED); - } - - $this->warmers[] = $warmer; - } } diff --git a/vendor/symfony/http-kernel/Client.php b/vendor/symfony/http-kernel/Client.php index 324710bb8a..62555e9a5a 100644 --- a/vendor/symfony/http-kernel/Client.php +++ b/vendor/symfony/http-kernel/Client.php @@ -25,8 +25,8 @@ use Symfony\Component\HttpFoundation\Response; * * @author Fabien Potencier <fabien@symfony.com> * - * @method Request|null getRequest() A Request instance - * @method Response|null getResponse() A Response instance + * @method Request getRequest() A Request instance + * @method Response getResponse() A Response instance */ class Client extends BaseClient { @@ -169,7 +169,6 @@ EOF; '', $value->getClientOriginalName(), $value->getClientMimeType(), - 0, UPLOAD_ERR_INI_SIZE, true ); @@ -178,7 +177,6 @@ EOF; $value->getPathname(), $value->getClientOriginalName(), $value->getClientMimeType(), - $value->getClientSize(), $value->getError(), true ); diff --git a/vendor/symfony/http-kernel/Config/EnvParametersResource.php b/vendor/symfony/http-kernel/Config/EnvParametersResource.php deleted file mode 100644 index f8d2a72b2a..0000000000 --- a/vendor/symfony/http-kernel/Config/EnvParametersResource.php +++ /dev/null @@ -1,99 +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\HttpKernel\Config; - -use Symfony\Component\Config\Resource\SelfCheckingResourceInterface; - -/** - * EnvParametersResource represents resources stored in prefixed environment variables. - * - * @author Chris Wilkinson <chriswilkinson84@gmail.com> - * - * @deprecated since version 3.4, to be removed in 4.0 - */ -class EnvParametersResource implements SelfCheckingResourceInterface, \Serializable -{ - /** - * @var string - */ - private $prefix; - - /** - * @var string - */ - private $variables; - - /** - * @param string $prefix - */ - public function __construct($prefix) - { - $this->prefix = $prefix; - $this->variables = $this->findVariables(); - } - - /** - * {@inheritdoc} - */ - public function __toString() - { - return serialize($this->getResource()); - } - - /** - * @return array An array with two keys: 'prefix' for the prefix used and 'variables' containing all the variables watched by this resource - */ - public function getResource() - { - return array('prefix' => $this->prefix, 'variables' => $this->variables); - } - - /** - * {@inheritdoc} - */ - public function isFresh($timestamp) - { - return $this->findVariables() === $this->variables; - } - - public function serialize() - { - return serialize(array('prefix' => $this->prefix, 'variables' => $this->variables)); - } - - public function unserialize($serialized) - { - if (\PHP_VERSION_ID >= 70000) { - $unserialized = unserialize($serialized, array('allowed_classes' => false)); - } else { - $unserialized = unserialize($serialized); - } - - $this->prefix = $unserialized['prefix']; - $this->variables = $unserialized['variables']; - } - - private function findVariables() - { - $variables = array(); - - foreach ($_SERVER as $key => $value) { - if (0 === strpos($key, $this->prefix)) { - $variables[$key] = $value; - } - } - - ksort($variables); - - return $variables; - } -} diff --git a/vendor/symfony/http-kernel/Config/FileLocator.php b/vendor/symfony/http-kernel/Config/FileLocator.php index c047ba3dac..20d91b2f05 100644 --- a/vendor/symfony/http-kernel/Config/FileLocator.php +++ b/vendor/symfony/http-kernel/Config/FileLocator.php @@ -29,7 +29,7 @@ class FileLocator extends BaseFileLocator * @param string|null $path The path the global resource directory * @param array $paths An array of paths where to look for resources */ - public function __construct(KernelInterface $kernel, $path = null, array $paths = array()) + public function __construct(KernelInterface $kernel, string $path = null, array $paths = array()) { $this->kernel = $kernel; if (null !== $path) { diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver.php index fc316920c7..142a6d54a6 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver.php @@ -34,7 +34,7 @@ final class ArgumentResolver implements ArgumentResolverInterface */ private $argumentValueResolvers; - public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, $argumentValueResolvers = array()) + public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = array()) { $this->argumentMetadataFactory = $argumentMetadataFactory ?: new ArgumentMetadataFactory(); $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers(); @@ -81,7 +81,7 @@ final class ArgumentResolver implements ArgumentResolverInterface return $arguments; } - public static function getDefaultArgumentValueResolvers() + public static function getDefaultArgumentValueResolvers(): iterable { return array( new RequestAttributeValueResolver(), diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php index 3294ec862e..e7df546b66 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/ServiceValueResolver.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Psr\Container\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; @@ -72,6 +73,21 @@ final class ServiceValueResolver implements ArgumentValueResolverInterface $controller = substr($controller, 0, $i).strtolower(substr($controller, $i)); } - yield $this->container->get($controller)->get($argument->getName()); + try { + yield $this->container->get($controller)->get($argument->getName()); + } catch (RuntimeException $e) { + $what = sprintf('argument $%s of "%s()"', $argument->getName(), $controller); + $message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage()); + + if ($e->getMessage() === $message) { + $message = sprintf('Cannot resolve %s: %s', $what, $message); + } + + $r = new \ReflectionProperty($e, 'message'); + $r->setAccessible(true); + $r->setValue($e, $message); + + throw $e; + } } } diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php index 9e656d281b..276d65461c 100644 --- a/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/SessionValueResolver.php @@ -28,6 +28,10 @@ final class SessionValueResolver implements ArgumentValueResolverInterface */ public function supports(Request $request, ArgumentMetadata $argument) { + if (!$request->hasSession()) { + return false; + } + $type = $argument->getType(); if (SessionInterface::class !== $type && !is_subclass_of($type, SessionInterface::class)) { return false; diff --git a/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php b/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.php new file mode 100644 index 0000000000..bde3c90c1a --- /dev/null +++ b/vendor/symfony/http-kernel/Controller/ArgumentResolver/TraceableValueResolver.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\HttpKernel\Controller\ArgumentResolver; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * Provides timing information via the stopwatch. + * + * @author Iltar van der Berg <kjarli@gmail.com> + */ +final class TraceableValueResolver implements ArgumentValueResolverInterface +{ + private $inner; + private $stopwatch; + + public function __construct(ArgumentValueResolverInterface $inner, Stopwatch $stopwatch) + { + $this->inner = $inner; + $this->stopwatch = $stopwatch; + } + + /** + * {@inheritdoc} + */ + public function supports(Request $request, ArgumentMetadata $argument): bool + { + $method = \get_class($this->inner).'::'.__FUNCTION__; + $this->stopwatch->start($method, 'controller.argument_value_resolver'); + + $return = $this->inner->supports($request, $argument); + + $this->stopwatch->stop($method); + + return $return; + } + + /** + * {@inheritdoc} + */ + public function resolve(Request $request, ArgumentMetadata $argument): iterable + { + $method = \get_class($this->inner).'::'.__FUNCTION__; + $this->stopwatch->start($method, 'controller.argument_value_resolver'); + + yield from $this->inner->resolve($request, $argument); + + $this->stopwatch->stop($method); + } +} diff --git a/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php b/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php index bc53e94bef..4f80921cf5 100644 --- a/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/ContainerControllerResolver.php @@ -14,7 +14,6 @@ namespace Symfony\Component\HttpKernel\Controller; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Container; -use Symfony\Component\HttpFoundation\Request; /** * A controller resolver searching for a controller in a psr-11 container when using the "service:method" notation. @@ -33,58 +32,14 @@ class ContainerControllerResolver extends ControllerResolver parent::__construct($logger); } - /** - * {@inheritdoc} - */ - public function getController(Request $request) - { - $controller = parent::getController($request); - - if (\is_array($controller) && isset($controller[0]) && \is_string($controller[0]) && $this->container->has($controller[0])) { - $controller[0] = $this->instantiateController($controller[0]); - } - - return $controller; - } - - /** - * Returns a callable for the given controller. - * - * @param string $controller A Controller string - * - * @return mixed A PHP callable - * - * @throws \LogicException When the name could not be parsed - * @throws \InvalidArgumentException When the controller class does not exist - */ protected function createController($controller) { - if (false !== strpos($controller, '::')) { - return parent::createController($controller); - } - - $method = null; - if (1 == substr_count($controller, ':')) { - // controller in the "service:method" notation - list($controller, $method) = explode(':', $controller, 2); - } - - if (!$this->container->has($controller)) { - $this->throwExceptionIfControllerWasRemoved($controller); - - throw new \LogicException(sprintf('Controller not found: service "%s" does not exist.', $controller)); - } - - $service = $this->container->get($controller); - if (null !== $method) { - return array($service, $method); + if (1 === substr_count($controller, ':')) { + $controller = str_replace(':', '::', $controller); + // TODO deprecate this in 5.1 } - if (!method_exists($service, '__invoke')) { - throw new \LogicException(sprintf('Controller "%s" cannot be called without a method name. Did you forget an "__invoke" method?', $controller)); - } - - return $service; + return parent::createController($controller); } /** @@ -98,24 +53,22 @@ class ContainerControllerResolver extends ControllerResolver try { return parent::instantiateController($class); - } catch (\ArgumentCountError $e) { - } catch (\ErrorException $e) { - } catch (\TypeError $e) { + } catch (\Error $e) { } $this->throwExceptionIfControllerWasRemoved($class, $e); - throw $e; + if ($e instanceof \ArgumentCountError) { + throw new \InvalidArgumentException(sprintf('Controller "%s" has required constructor arguments and does not exist in the container. Did you forget to define such a service?', $class), 0, $e); + } + + throw new \InvalidArgumentException(sprintf('Controller "%s" does neither exist as service nor as class', $class), 0, $e); } - /** - * @param string $controller - * @param \Exception|\Throwable|null $previous - */ - private function throwExceptionIfControllerWasRemoved($controller, $previous = null) + private function throwExceptionIfControllerWasRemoved(string $controller, \Throwable $previous) { if ($this->container instanceof Container && isset($this->container->getRemovedIds()[$controller])) { - throw new \LogicException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); + throw new \InvalidArgumentException(sprintf('Controller "%s" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?', $controller), 0, $previous); } } } diff --git a/vendor/symfony/http-kernel/Controller/ControllerReference.php b/vendor/symfony/http-kernel/Controller/ControllerReference.php index fae4e7fa44..f424fdc833 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerReference.php +++ b/vendor/symfony/http-kernel/Controller/ControllerReference.php @@ -35,7 +35,7 @@ class ControllerReference * @param array $attributes An array of parameters to add to the Request attributes * @param array $query An array of parameters to add to the Request query string */ - public function __construct($controller, array $attributes = array(), array $query = array()) + public function __construct(string $controller, array $attributes = array(), array $query = array()) { $this->controller = $controller; $this->attributes = $attributes; diff --git a/vendor/symfony/http-kernel/Controller/ControllerResolver.php b/vendor/symfony/http-kernel/Controller/ControllerResolver.php index 6d898e7831..04c5fcf53d 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/ControllerResolver.php @@ -16,44 +16,22 @@ use Symfony\Component\HttpFoundation\Request; /** * This implementation uses the '_controller' request attribute to determine - * the controller to execute and uses the request attributes to determine - * the controller method arguments. + * the controller to execute. * * @author Fabien Potencier <fabien@symfony.com> + * @author Tobias Schultze <http://tobion.de> */ -class ControllerResolver implements ArgumentResolverInterface, ControllerResolverInterface +class ControllerResolver implements ControllerResolverInterface { private $logger; - /** - * If the ...$arg functionality is available. - * - * Requires at least PHP 5.6.0 or HHVM 3.9.1 - * - * @var bool - */ - private $supportsVariadic; - - /** - * If scalar types exists. - * - * @var bool - */ - private $supportsScalarTypes; - public function __construct(LoggerInterface $logger = null) { $this->logger = $logger; - - $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic'); - $this->supportsScalarTypes = method_exists('ReflectionParameter', 'getType'); } /** * {@inheritdoc} - * - * This method looks for a '_controller' request attribute that represents - * the controller name (a string like ClassName::MethodName). */ public function getController(Request $request) { @@ -66,23 +44,42 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve } if (\is_array($controller)) { + if (isset($controller[0]) && \is_string($controller[0]) && isset($controller[1])) { + try { + $controller[0] = $this->instantiateController($controller[0]); + } catch (\Error | \LogicException $e) { + try { + // We cannot just check is_callable but have to use reflection because a non-static method + // can still be called statically in PHP but we don't want that. This is deprecated in PHP 7, so we + // could simplify this with PHP 8. + if ((new \ReflectionMethod($controller[0], $controller[1]))->isStatic()) { + return $controller; + } + } catch (\ReflectionException $reflectionException) { + throw $e; + } + + throw $e; + } + } + + if (!\is_callable($controller)) { + throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($controller))); + } + return $controller; } if (\is_object($controller)) { - if (method_exists($controller, '__invoke')) { - return $controller; + if (!\is_callable($controller)) { + throw new \InvalidArgumentException(sprintf('The controller for URI "%s" is not callable. %s', $request->getPathInfo(), $this->getControllerError($controller))); } - throw new \InvalidArgumentException(sprintf('Controller "%s" for URI "%s" is not callable.', \get_class($controller), $request->getPathInfo())); + return $controller; } - if (false === strpos($controller, ':')) { - if (method_exists($controller, '__invoke')) { - return $this->instantiateController($controller); - } elseif (\function_exists($controller)) { - return $controller; - } + if (\function_exists($controller)) { + return $controller; } $callable = $this->createController($controller); @@ -95,92 +92,33 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve } /** - * {@inheritdoc} - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Implement the ArgumentResolverInterface and inject it in the HttpKernel instead. - */ - public function getArguments(Request $request, $controller) - { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); - - if (\is_array($controller)) { - $r = new \ReflectionMethod($controller[0], $controller[1]); - } elseif (\is_object($controller) && !$controller instanceof \Closure) { - $r = new \ReflectionObject($controller); - $r = $r->getMethod('__invoke'); - } else { - $r = new \ReflectionFunction($controller); - } - - return $this->doGetArguments($request, $controller, $r->getParameters()); - } - - /** - * @param Request $request - * @param callable $controller - * @param \ReflectionParameter[] $parameters - * - * @return array The arguments to use when calling the action - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Implement the ArgumentResolverInterface and inject it in the HttpKernel instead. - */ - protected function doGetArguments(Request $request, $controller, array $parameters) - { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Implement the %s and inject it in the HttpKernel instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); - - $attributes = $request->attributes->all(); - $arguments = array(); - foreach ($parameters as $param) { - if (array_key_exists($param->name, $attributes)) { - if ($this->supportsVariadic && $param->isVariadic() && \is_array($attributes[$param->name])) { - $arguments = array_merge($arguments, array_values($attributes[$param->name])); - } else { - $arguments[] = $attributes[$param->name]; - } - } elseif ($param->getClass() && $param->getClass()->isInstance($request)) { - $arguments[] = $request; - } elseif ($param->isDefaultValueAvailable()) { - $arguments[] = $param->getDefaultValue(); - } elseif ($this->supportsScalarTypes && $param->hasType() && $param->allowsNull()) { - $arguments[] = null; - } else { - if (\is_array($controller)) { - $repr = sprintf('%s::%s()', \get_class($controller[0]), $controller[1]); - } elseif (\is_object($controller)) { - $repr = \get_class($controller); - } else { - $repr = $controller; - } - - throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->name)); - } - } - - return $arguments; - } - - /** * Returns a callable for the given controller. * * @param string $controller A Controller string * * @return callable A PHP callable - * - * @throws \InvalidArgumentException */ protected function createController($controller) { if (false === strpos($controller, '::')) { - throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller)); + return $this->instantiateController($controller); } list($class, $method) = explode('::', $controller, 2); - if (!class_exists($class)) { - throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class)); - } + try { + return array($this->instantiateController($class), $method); + } catch (\Error | \LogicException $e) { + try { + if ((new \ReflectionMethod($class, $method))->isStatic()) { + return $class.'::'.$method; + } + } catch (\ReflectionException $reflectionException) { + throw $e; + } - return array($this->instantiateController($class), $method); + throw $e; + } } /** @@ -199,24 +137,25 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve { if (\is_string($callable)) { if (false !== strpos($callable, '::')) { - $callable = explode('::', $callable); + $callable = explode('::', $callable, 2); + } else { + return sprintf('Function "%s" does not exist.', $callable); } + } - if (class_exists($callable) && !method_exists($callable, '__invoke')) { - return sprintf('Class "%s" does not have a method "__invoke".', $callable); - } + if (\is_object($callable)) { + $availableMethods = $this->getClassMethodsWithoutMagicMethods($callable); + $alternativeMsg = $availableMethods ? sprintf(' or use one of the available methods: "%s"', implode('", "', $availableMethods)) : ''; - if (!\function_exists($callable)) { - return sprintf('Function "%s" does not exist.', $callable); - } + return sprintf('Controller class "%s" cannot be called without a method name. You need to implement "__invoke"%s.', \get_class($callable), $alternativeMsg); } if (!\is_array($callable)) { - return sprintf('Invalid type for controller given, expected string or array, got "%s".', \gettype($callable)); + return sprintf('Invalid type for controller given, expected string, array or object, got "%s".', \gettype($callable)); } - if (2 !== \count($callable)) { - return 'Invalid format for controller, expected array(controller, method) or controller::method.'; + if (!isset($callable[0]) || !isset($callable[1]) || 2 !== \count($callable)) { + return 'Invalid array callable, expected array(controller, method).'; } list($controller, $method) = $callable; @@ -231,7 +170,7 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve return sprintf('Method "%s" on class "%s" should be public and non-abstract.', $method, $className); } - $collection = get_class_methods($controller); + $collection = $this->getClassMethodsWithoutMagicMethods($controller); $alternatives = array(); @@ -255,4 +194,13 @@ class ControllerResolver implements ArgumentResolverInterface, ControllerResolve return $message; } + + private function getClassMethodsWithoutMagicMethods($classOrObject) + { + $methods = get_class_methods($classOrObject); + + return array_filter($methods, function (string $method) { + return 0 !== strncmp($method, '__', 2); + }); + } } diff --git a/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php b/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php index afe9fb7337..a54f8b518b 100644 --- a/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php +++ b/vendor/symfony/http-kernel/Controller/ControllerResolverInterface.php @@ -17,8 +17,6 @@ use Symfony\Component\HttpFoundation\Request; * A ControllerResolverInterface implementation knows how to determine the * controller to execute based on a Request object. * - * It can also determine the arguments to pass to the Controller. - * * A Controller can be any valid PHP callable. * * @author Fabien Potencier <fabien@symfony.com> @@ -37,21 +35,7 @@ interface ControllerResolverInterface * @return callable|false A PHP callable representing the Controller, * or false if this resolver is not able to determine the controller * - * @throws \LogicException If the controller can't be found + * @throws \LogicException If a controller was found based on the request but it is not callable */ public function getController(Request $request); - - /** - * Returns the arguments to pass to the controller. - * - * @param Request $request A Request instance - * @param callable $controller A PHP callable - * - * @return array An array of arguments to pass to the controller - * - * @throws \RuntimeException When value for argument given is not provided - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. Please use the {@see ArgumentResolverInterface} instead. - */ - public function getArguments(Request $request, $controller); } diff --git a/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php b/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php index 6f39f81d2a..bf6b6aa1f2 100644 --- a/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php +++ b/vendor/symfony/http-kernel/Controller/TraceableControllerResolver.php @@ -17,26 +17,15 @@ use Symfony\Component\Stopwatch\Stopwatch; /** * @author Fabien Potencier <fabien@symfony.com> */ -class TraceableControllerResolver implements ControllerResolverInterface, ArgumentResolverInterface +class TraceableControllerResolver implements ControllerResolverInterface { private $resolver; private $stopwatch; - private $argumentResolver; - public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch, ArgumentResolverInterface $argumentResolver = null) + public function __construct(ControllerResolverInterface $resolver, Stopwatch $stopwatch) { $this->resolver = $resolver; $this->stopwatch = $stopwatch; - $this->argumentResolver = $argumentResolver; - - // BC - if (null === $this->argumentResolver) { - $this->argumentResolver = $resolver; - } - - if (!$this->argumentResolver instanceof TraceableArgumentResolver) { - $this->argumentResolver = new TraceableArgumentResolver($this->argumentResolver, $this->stopwatch); - } } /** @@ -52,18 +41,4 @@ class TraceableControllerResolver implements ControllerResolverInterface, Argume return $ret; } - - /** - * {@inheritdoc} - * - * @deprecated This method is deprecated as of 3.1 and will be removed in 4.0. - */ - public function getArguments(Request $request, $controller) - { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.1 and will be removed in 4.0. Please use the %s instead.', __METHOD__, TraceableArgumentResolver::class), E_USER_DEPRECATED); - - $ret = $this->argumentResolver->getArguments($request, $controller); - - return $ret; - } } diff --git a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php index 32316a8d51..4ea8ea643f 100644 --- a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php +++ b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadata.php @@ -25,15 +25,7 @@ class ArgumentMetadata private $defaultValue; private $isNullable; - /** - * @param string $name - * @param string $type - * @param bool $isVariadic - * @param bool $hasDefaultValue - * @param mixed $defaultValue - * @param bool $isNullable - */ - public function __construct($name, $type, $isVariadic, $hasDefaultValue, $defaultValue, $isNullable = false) + public function __construct(string $name, ?string $type, bool $isVariadic, bool $hasDefaultValue, $defaultValue, bool $isNullable = false) { $this->name = $name; $this->type = $type; diff --git a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php index b46be7e8b7..cc2ed9f2b7 100644 --- a/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php +++ b/vendor/symfony/http-kernel/ControllerMetadata/ArgumentMetadataFactory.php @@ -19,30 +19,6 @@ namespace Symfony\Component\HttpKernel\ControllerMetadata; final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface { /** - * If the ...$arg functionality is available. - * - * Requires at least PHP 5.6.0 or HHVM 3.9.1 - * - * @var bool - */ - private $supportsVariadic; - - /** - * If the reflection supports the getType() method to resolve types. - * - * Requires at least PHP 7.0.0 or HHVM 3.11.0 - * - * @var bool - */ - private $supportsParameterType; - - public function __construct() - { - $this->supportsVariadic = method_exists('ReflectionParameter', 'isVariadic'); - $this->supportsParameterType = method_exists('ReflectionParameter', 'getType'); - } - - /** * {@inheritdoc} */ public function createArgumentMetadata($controller) @@ -58,49 +34,13 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface } foreach ($reflection->getParameters() as $param) { - $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $this->isVariadic($param), $this->hasDefaultValue($param), $this->getDefaultValue($param), $param->allowsNull()); + $arguments[] = new ArgumentMetadata($param->getName(), $this->getType($param, $reflection), $param->isVariadic(), $param->isDefaultValueAvailable(), $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null, $param->allowsNull()); } return $arguments; } /** - * Returns whether an argument is variadic. - * - * @param \ReflectionParameter $parameter - * - * @return bool - */ - private function isVariadic(\ReflectionParameter $parameter) - { - return $this->supportsVariadic && $parameter->isVariadic(); - } - - /** - * Determines whether an argument has a default value. - * - * @param \ReflectionParameter $parameter - * - * @return bool - */ - private function hasDefaultValue(\ReflectionParameter $parameter) - { - return $parameter->isDefaultValueAvailable(); - } - - /** - * Returns a default value if available. - * - * @param \ReflectionParameter $parameter - * - * @return mixed|null - */ - private function getDefaultValue(\ReflectionParameter $parameter) - { - return $this->hasDefaultValue($parameter) ? $parameter->getDefaultValue() : null; - } - - /** * Returns an associated type to the given parameter if available. * * @param \ReflectionParameter $parameter @@ -109,20 +49,10 @@ final class ArgumentMetadataFactory implements ArgumentMetadataFactoryInterface */ private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbstract $function) { - if ($this->supportsParameterType) { - if (!$type = $parameter->getType()) { - return; - } - $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); - if ('array' === $name && !$type->isBuiltin()) { - // Special case for HHVM with variadics - return; - } - } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $name)) { - $name = $name[1]; - } else { + if (!$type = $parameter->getType()) { return; } + $name = $type->getName(); $lcName = strtolower($name); if ('self' !== $lcName && 'parent' !== $lcName) { diff --git a/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php b/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php index abfd939f5f..f07ac89c0f 100644 --- a/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/ConfigDataCollector.php @@ -30,12 +30,15 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte private $version; private $hasVarDumper; - /** - * @param string $name The name of the application using the web profiler - * @param string $version The version of the application using the web profiler - */ - public function __construct($name = null, $version = null) + public function __construct(string $name = null, string $version = null) { + if (1 <= \func_num_args()) { + @trigger_error(sprintf('The "$name" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + } + if (2 <= \func_num_args()) { + @trigger_error(sprintf('The "$version" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + } + $this->name = $name; $this->version = $version; $this->hasVarDumper = class_exists(LinkStub::class); @@ -60,7 +63,6 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte 'token' => $response->headers->get('X-Debug-Token'), 'symfony_version' => Kernel::VERSION, 'symfony_state' => 'unknown', - 'name' => isset($this->kernel) ? $this->kernel->getName() : 'n/a', 'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a', 'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a', 'php_version' => PHP_VERSION, @@ -106,13 +108,23 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte $this->data = $this->cloneVar($this->data); } + /** + * @deprecated since Symfony 4.2 + */ public function getApplicationName() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + return $this->data['app_name']; } + /** + * @deprecated since Symfony 4.2 + */ public function getApplicationVersion() { + @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + return $this->data['app_version']; } @@ -227,10 +239,14 @@ class ConfigDataCollector extends DataCollector implements LateDataCollectorInte * Gets the application name. * * @return string The application name + * + * @deprecated since Symfony 4.2 */ public function getAppName() { - return $this->data['name']; + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + + return 'n/a'; } /** diff --git a/vendor/symfony/http-kernel/DataCollector/DataCollector.php b/vendor/symfony/http-kernel/DataCollector/DataCollector.php index 6d1a822e47..a3d8c99d84 100644 --- a/vendor/symfony/http-kernel/DataCollector/DataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DataCollector.php @@ -11,7 +11,6 @@ namespace Symfony\Component\HttpKernel\DataCollector; -use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter; use Symfony\Component\VarDumper\Caster\CutStub; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Cloner\Data; @@ -31,11 +30,6 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable protected $data = array(); /** - * @var ValueExporter - */ - private $valueExporter; - - /** * @var ClonerInterface */ private $cloner; @@ -66,47 +60,18 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable return $var; } if (null === $this->cloner) { - if (class_exists(CutStub::class)) { - $this->cloner = new VarCloner(); - $this->cloner->setMaxItems(-1); - $this->cloner->addCasters($this->getCasters()); - } else { - @trigger_error(sprintf('Using the %s() method without the VarDumper component is deprecated since Symfony 3.2 and won\'t be supported in 4.0. Install symfony/var-dumper version 3.2 or above.', __METHOD__), E_USER_DEPRECATED); - $this->cloner = false; + if (!class_exists(CutStub::class)) { + throw new \LogicException(sprintf('The VarDumper component is needed for the %s() method. Install symfony/var-dumper version 3.4 or above.', __METHOD__)); } - } - if (false === $this->cloner) { - if (null === $this->valueExporter) { - $this->valueExporter = new ValueExporter(); - } - - return $this->valueExporter->exportValue($var); + $this->cloner = new VarCloner(); + $this->cloner->setMaxItems(-1); + $this->cloner->addCasters($this->getCasters()); } return $this->cloner->cloneVar($var); } /** - * Converts a PHP variable to a string. - * - * @param mixed $var A PHP variable - * - * @return string The string representation of the variable - * - * @deprecated since version 3.2, to be removed in 4.0. Use cloneVar() instead. - */ - protected function varToString($var) - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.2 and will be removed in 4.0. Use cloneVar() instead.', __METHOD__), E_USER_DEPRECATED); - - if (null === $this->valueExporter) { - $this->valueExporter = new ValueExporter(); - } - - return $this->valueExporter->exportValue($var); - } - - /** * @return callable[] The casters to add to the cloner */ protected function getCasters() diff --git a/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php b/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php index 2470089b81..b9584110ec 100644 --- a/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php +++ b/vendor/symfony/http-kernel/DataCollector/DataCollectorInterface.php @@ -13,15 +13,14 @@ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Contracts\Service\ResetInterface; /** * DataCollectorInterface. * * @author Fabien Potencier <fabien@symfony.com> - * - * @method reset() Resets this data collector to its initial state. */ -interface DataCollectorInterface +interface DataCollectorInterface extends ResetInterface { /** * Collects data for the given Request and Response. diff --git a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php index 7e2430c4ba..13694f5a59 100644 --- a/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/DumpDataCollector.php @@ -18,9 +18,10 @@ use Symfony\Component\Stopwatch\Stopwatch; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Dumper\ContextProvider\SourceContextProvider; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; use Symfony\Component\VarDumper\Dumper\HtmlDumper; -use Twig\Template; +use Symfony\Component\VarDumper\Server\Connection; /** * @author Nicolas Grekas <p@tchwork.com> @@ -37,16 +38,18 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface private $charset; private $requestStack; private $dumper; - private $dumperIsInjected; + private $sourceContextProvider; - public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, $charset = null, RequestStack $requestStack = null, DataDumperInterface $dumper = null) + /** + * @param DataDumperInterface|Connection|null $dumper + */ + public function __construct(Stopwatch $stopwatch = null, $fileLinkFormat = null, string $charset = null, RequestStack $requestStack = null, $dumper = null) { $this->stopwatch = $stopwatch; $this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); $this->charset = $charset ?: ini_get('php.output_encoding') ?: ini_get('default_charset') ?: 'UTF-8'; $this->requestStack = $requestStack; $this->dumper = $dumper; - $this->dumperIsInjected = null !== $dumper; // All clones share these properties by reference: $this->rootRefs = array( @@ -55,6 +58,8 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface &$this->isCollected, &$this->clonesCount, ); + + $this->sourceContextProvider = $dumper instanceof Connection && isset($dumper->getContextProviders()['source']) ? $dumper->getContextProviders()['source'] : new SourceContextProvider($this->charset); } public function __clone() @@ -67,65 +72,17 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface if ($this->stopwatch) { $this->stopwatch->start('dump'); } - if ($this->isCollected && !$this->dumper) { - $this->isCollected = false; - } - - $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 7); - - $file = $trace[0]['file']; - $line = $trace[0]['line']; - $name = false; - $fileExcerpt = false; - - for ($i = 1; $i < 7; ++$i) { - if (isset($trace[$i]['class'], $trace[$i]['function']) - && 'dump' === $trace[$i]['function'] - && 'Symfony\Component\VarDumper\VarDumper' === $trace[$i]['class'] - ) { - $file = $trace[$i]['file']; - $line = $trace[$i]['line']; - - while (++$i < 7) { - if (isset($trace[$i]['function'], $trace[$i]['file']) && empty($trace[$i]['class']) && 0 !== strpos($trace[$i]['function'], 'call_user_func')) { - $file = $trace[$i]['file']; - $line = $trace[$i]['line']; - break; - } elseif (isset($trace[$i]['object']) && $trace[$i]['object'] instanceof Template) { - $template = $trace[$i]['object']; - $name = $template->getTemplateName(); - $src = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : false); - $info = $template->getDebugInfo(); - if (isset($info[$trace[$i - 1]['line']])) { - $line = $info[$trace[$i - 1]['line']]; - $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; + list('name' => $name, 'file' => $file, 'line' => $line, 'file_excerpt' => $fileExcerpt) = $this->sourceContextProvider->getContext(); - if ($src) { - $src = explode("\n", $src); - $fileExcerpt = array(); - - for ($i = max($line - 3, 1), $max = min($line + 3, \count($src)); $i <= $max; ++$i) { - $fileExcerpt[] = '<li'.($i === $line ? ' class="selected"' : '').'><code>'.$this->htmlEncode($src[$i - 1]).'</code></li>'; - } - - $fileExcerpt = '<ol start="'.max($line - 3, 1).'">'.implode("\n", $fileExcerpt).'</ol>'; - } - } - break; - } - } - break; + if ($this->dumper instanceof Connection) { + if (!$this->dumper->write($data)) { + $this->isCollected = false; } - } - - if (false === $name) { - $name = str_replace('\\', '/', $file); - $name = substr($name, strrpos($name, '/') + 1); - } - - if ($this->dumper) { - $this->doDump($data, $name, $file, $line); + } elseif ($this->dumper) { + $this->doDump($this->dumper, $data, $name, $file, $line); + } else { + $this->isCollected = false; } $this->data[] = compact('data', 'name', 'file', 'line', 'fileExcerpt'); @@ -152,14 +109,14 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface || false === strripos($response->getContent(), '</body>') ) { if ($response->headers->has('Content-Type') && false !== strpos($response->headers->get('Content-Type'), 'html')) { - $this->dumper = new HtmlDumper('php://output', $this->charset); - $this->dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + $dumper = new HtmlDumper('php://output', $this->charset); + $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); } else { - $this->dumper = new CliDumper('php://output', $this->charset); + $dumper = new CliDumper('php://output', $this->charset); } foreach ($this->data as $dump) { - $this->doDump($dump['data'], $dump['name'], $dump['file'], $dump['line']); + $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']); } } } @@ -188,9 +145,6 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface $this->data = array(); $this->dataCount = 0; $this->isCollected = true; - if (!$this->dumperIsInjected) { - $this->dumper = null; - } return $ser; } @@ -250,16 +204,22 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface --$i; } - if (!\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true) && stripos($h[$i], 'html')) { - $this->dumper = new HtmlDumper('php://output', $this->charset); - $this->dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); + if (isset($_SERVER['VAR_DUMPER_FORMAT'])) { + $html = 'html' === $_SERVER['VAR_DUMPER_FORMAT']; + } else { + $html = !\in_array(\PHP_SAPI, array('cli', 'phpdbg'), true) && stripos($h[$i], 'html'); + } + + if ($html) { + $dumper = new HtmlDumper('php://output', $this->charset); + $dumper->setDisplayOptions(array('fileLinkFormat' => $this->fileLinkFormat)); } else { - $this->dumper = new CliDumper('php://output', $this->charset); + $dumper = new CliDumper('php://output', $this->charset); } foreach ($this->data as $i => $dump) { $this->data[$i] = null; - $this->doDump($dump['data'], $dump['name'], $dump['file'], $dump['line']); + $this->doDump($dumper, $dump['data'], $dump['name'], $dump['file'], $dump['line']); } $this->data = array(); @@ -267,9 +227,9 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface } } - private function doDump($data, $name, $file, $line) + private function doDump(DataDumperInterface $dumper, $data, $name, $file, $line) { - if ($this->dumper instanceof CliDumper) { + if ($dumper instanceof CliDumper) { $contextDumper = function ($name, $file, $line, $fmt) { if ($this instanceof HtmlDumper) { if ($file) { @@ -290,26 +250,12 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface } $this->dumpLine(0); }; - $contextDumper = $contextDumper->bindTo($this->dumper, $this->dumper); + $contextDumper = $contextDumper->bindTo($dumper, $dumper); $contextDumper($name, $file, $line, $this->fileLinkFormat); } else { $cloner = new VarCloner(); - $this->dumper->dump($cloner->cloneVar($name.' on line '.$line.':')); + $dumper->dump($cloner->cloneVar($name.' on line '.$line.':')); } - $this->dumper->dump($data); - } - - private function htmlEncode($s) - { - $html = ''; - - $dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset); - $dumper->setDumpHeader(''); - $dumper->setDumpBoundaries('', ''); - - $cloner = new VarCloner(); - $dumper->dump($cloner->cloneVar($s)); - - return substr(strip_tags($html), 1, -1); + $dumper->dump($data); } } diff --git a/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php b/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php index 81076fd726..3a7e51bf8d 100644 --- a/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/EventDataCollector.php @@ -11,10 +11,12 @@ 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\Response; +use Symfony\Contracts\Service\ResetInterface; /** * EventDataCollector. @@ -27,9 +29,6 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter public function __construct(EventDispatcherInterface $dispatcher = null) { - if ($dispatcher instanceof TraceableEventDispatcherInterface && !method_exists($dispatcher, 'reset')) { - @trigger_error(sprintf('Implementing "%s" without the "reset()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".', TraceableEventDispatcherInterface::class, \get_class($dispatcher)), E_USER_DEPRECATED); - } $this->dispatcher = $dispatcher; } @@ -41,6 +40,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter $this->data = array( 'called_listeners' => array(), 'not_called_listeners' => array(), + 'orphaned_events' => array(), ); } @@ -48,11 +48,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter { $this->data = array(); - if ($this->dispatcher instanceof TraceableEventDispatcherInterface) { - if (!method_exists($this->dispatcher, 'reset')) { - return; // @deprecated - } - + if ($this->dispatcher instanceof ResetInterface) { $this->dispatcher->reset(); } } @@ -63,6 +59,11 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter $this->setCalledListeners($this->dispatcher->getCalledListeners()); $this->setNotCalledListeners($this->dispatcher->getNotCalledListeners()); } + + if ($this->dispatcher instanceof TraceableEventDispatcher) { + $this->setOrphanedEvents($this->dispatcher->getOrphanedEvents()); + } + $this->data = $this->cloneVar($this->data); } @@ -71,7 +72,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter * * @param array $listeners An array of called listeners * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function setCalledListeners(array $listeners) { @@ -83,7 +84,7 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter * * @return array An array of called listeners * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function getCalledListeners() { @@ -93,9 +94,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter /** * Sets the not called listeners. * - * @param array $listeners An array of not called listeners + * @param array $listeners * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function setNotCalledListeners(array $listeners) { @@ -105,9 +106,9 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter /** * Gets the not called listeners. * - * @return array An array of not called listeners + * @return array * - * @see TraceableEventDispatcherInterface + * @see TraceableEventDispatcher */ public function getNotCalledListeners() { @@ -115,6 +116,30 @@ class EventDataCollector extends DataCollector implements LateDataCollectorInter } /** + * Sets the orphaned events. + * + * @param array $events An array of orphaned events + * + * @see TraceableEventDispatcher + */ + public function setOrphanedEvents(array $events) + { + $this->data['orphaned_events'] = $events; + } + + /** + * Gets the orphaned events. + * + * @return array An array of orphaned events + * + * @see TraceableEventDispatcher + */ + public function getOrphanedEvents() + { + return $this->data['orphaned_events']; + } + + /** * {@inheritdoc} */ public function getName() diff --git a/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php b/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php index 97b8a8620c..3081ac7fb5 100644 --- a/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/LoggerDataCollector.php @@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\DataCollector; use Symfony\Component\Debug\Exception\SilencedErrorContext; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; @@ -25,18 +26,17 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte { private $logger; private $containerPathPrefix; + private $currentRequest; + private $requestStack; - public function __construct($logger = null, $containerPathPrefix = null) + public function __construct($logger = null, string $containerPathPrefix = null, RequestStack $requestStack = null) { if (null !== $logger && $logger instanceof DebugLoggerInterface) { - if (!method_exists($logger, 'clear')) { - @trigger_error(sprintf('Implementing "%s" without the "clear()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".', DebugLoggerInterface::class, \get_class($logger)), E_USER_DEPRECATED); - } - $this->logger = $logger; } $this->containerPathPrefix = $containerPathPrefix; + $this->requestStack = $requestStack; } /** @@ -44,7 +44,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte */ public function collect(Request $request, Response $response, \Exception $exception = null) { - // everything is done as late as possible + $this->currentRequest = $this->requestStack && $this->requestStack->getMasterRequest() !== $request ? $request : null; } /** @@ -52,7 +52,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte */ public function reset() { - if ($this->logger && method_exists($this->logger, 'clear')) { + if ($this->logger instanceof DebugLoggerInterface) { $this->logger->clear(); } $this->data = array(); @@ -67,9 +67,10 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte $containerDeprecationLogs = $this->getContainerDeprecationLogs(); $this->data = $this->computeErrorsCount($containerDeprecationLogs); $this->data['compiler_logs'] = $this->getContainerCompilerLogs(); - $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs(), $containerDeprecationLogs)); + $this->data['logs'] = $this->sanitizeLogs(array_merge($this->logger->getLogs($this->currentRequest), $containerDeprecationLogs)); $this->data = $this->cloneVar($this->data); } + $this->currentRequest = null; } /** @@ -133,7 +134,7 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte $log['timestamp'] = $bootTime; $log['priority'] = 100; $log['priorityName'] = 'DEBUG'; - $log['channel'] = '-'; + $log['channel'] = null; $log['scream'] = false; unset($log['type'], $log['file'], $log['line'], $log['trace'], $log['trace'], $log['count']); $logs[] = $log; @@ -233,14 +234,14 @@ class LoggerDataCollector extends DataCollector implements LateDataCollectorInte { $silencedLogs = array(); $count = array( - 'error_count' => $this->logger->countErrors(), + 'error_count' => $this->logger->countErrors($this->currentRequest), 'deprecation_count' => 0, 'warning_count' => 0, 'scream_count' => 0, 'priorities' => array(), ); - foreach ($this->logger->getLogs() as $log) { + foreach ($this->logger->getLogs($this->currentRequest) as $log) { if (isset($count['priorities'][$log['priority']])) { ++$count['priorities'][$log['priority']]['count']; } else { diff --git a/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php b/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php index e415833cc3..ed75382618 100644 --- a/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php +++ b/vendor/symfony/http-kernel/DataCollector/RequestDataCollector.php @@ -79,6 +79,13 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter $responseCookies[$cookie->getName()] = $cookie; } + $dotenvVars = array(); + foreach (explode(',', getenv('SYMFONY_DOTENV_VARS')) as $name) { + if ('' !== $name && false !== $value = getenv($name)) { + $dotenvVars[$name] = $value; + } + } + $this->data = array( 'method' => $request->getMethod(), 'format' => $request->getRequestFormat(), @@ -88,6 +95,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter 'status_code' => $statusCode, 'request_query' => $request->query->all(), 'request_request' => $request->request->all(), + 'request_files' => $request->files->all(), 'request_headers' => $request->headers->all(), 'request_server' => $request->server->all(), 'request_cookies' => $request->cookies->all(), @@ -101,6 +109,7 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter 'path_info' => $request->getPathInfo(), 'controller' => 'n/a', 'locale' => $request->getLocale(), + 'dotenv_vars' => $dotenvVars, ); if (isset($this->data['request_headers']['php-auth-pw'])) { @@ -145,11 +154,16 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter 'controller' => $this->parseController($request->attributes->get('_controller')), 'status_code' => $statusCode, 'status_text' => Response::$statusTexts[(int) $statusCode], - )) + )), + 0, '/', null, $request->isSecure(), true, false, 'lax' )); } $this->data['identifier'] = $this->data['route'] ?: (\is_array($this->data['controller']) ? $this->data['controller']['class'].'::'.$this->data['controller']['method'].'()' : $this->data['controller']); + + if ($response->headers->has('x-previous-debug-token')) { + $this->data['forward_token'] = $response->headers->get('x-previous-debug-token'); + } } public function lateCollect() @@ -183,6 +197,11 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter return new ParameterBag($this->data['request_query']->getValue()); } + public function getRequestFiles() + { + return new ParameterBag($this->data['request_files']->getValue()); + } + public function getRequestHeaders() { return new ParameterBag($this->data['request_headers']->getValue()); @@ -258,6 +277,11 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter return $this->data['locale']; } + public function getDotenvVars() + { + return new ParameterBag($this->data['dotenv_vars']->getValue()); + } + /** * Gets the route name. * @@ -309,6 +333,11 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter return isset($this->data['redirect']) ? $this->data['redirect'] : false; } + public function getForwardToken() + { + return isset($this->data['forward_token']) ? $this->data['forward_token'] : null; + } + public function onKernelController(FilterControllerEvent $event) { $this->controllers[$event->getRequest()] = $event->getController(); @@ -380,12 +409,25 @@ class RequestDataCollector extends DataCollector implements EventSubscriberInter if ($controller instanceof \Closure) { $r = new \ReflectionFunction($controller); - return array( + $controller = array( 'class' => $r->getName(), 'method' => null, 'file' => $r->getFileName(), 'line' => $r->getStartLine(), ); + + if (false !== strpos($r->name, '{closure}')) { + return $controller; + } + $controller['method'] = $r->name; + + if ($class = $r->getClosureScopeClass()) { + $controller['class'] = $class->name; + } else { + return $r->name; + } + + return $controller; } if (\is_object($controller)) { diff --git a/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php b/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php deleted file mode 100644 index e30b3a5029..0000000000 --- a/vendor/symfony/http-kernel/DataCollector/Util/ValueExporter.php +++ /dev/null @@ -1,99 +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\HttpKernel\DataCollector\Util; - -@trigger_error('The '.__NAMESPACE__.'\ValueExporter class is deprecated since Symfony 3.2 and will be removed in 4.0. Use the VarDumper component instead.', E_USER_DEPRECATED); - -/** - * @author Bernhard Schussek <bschussek@gmail.com> - * - * @deprecated since version 3.2, to be removed in 4.0. Use the VarDumper component instead. - */ -class ValueExporter -{ - /** - * Converts a PHP value to a string. - * - * @param mixed $value The PHP value - * @param int $depth Only for internal usage - * @param bool $deep Only for internal usage - * - * @return string The string representation of the given value - */ - public function exportValue($value, $depth = 1, $deep = false) - { - if ($value instanceof \__PHP_Incomplete_Class) { - return sprintf('__PHP_Incomplete_Class(%s)', $this->getClassNameFromIncomplete($value)); - } - - if (\is_object($value)) { - if ($value instanceof \DateTimeInterface) { - return sprintf('Object(%s) - %s', \get_class($value), $value->format(\DateTime::ATOM)); - } - - return sprintf('Object(%s)', \get_class($value)); - } - - if (\is_array($value)) { - if (empty($value)) { - return '[]'; - } - - $indent = str_repeat(' ', $depth); - - $a = array(); - foreach ($value as $k => $v) { - if (\is_array($v)) { - $deep = true; - } - $a[] = sprintf('%s => %s', $k, $this->exportValue($v, $depth + 1, $deep)); - } - - if ($deep) { - return sprintf("[\n%s%s\n%s]", $indent, implode(sprintf(", \n%s", $indent), $a), str_repeat(' ', $depth - 1)); - } - - $s = sprintf('[%s]', implode(', ', $a)); - - if (80 > \strlen($s)) { - return $s; - } - - return sprintf("[\n%s%s\n]", $indent, implode(sprintf(",\n%s", $indent), $a)); - } - - if (\is_resource($value)) { - return sprintf('Resource(%s#%d)', get_resource_type($value), $value); - } - - if (null === $value) { - return 'null'; - } - - if (false === $value) { - return 'false'; - } - - if (true === $value) { - return 'true'; - } - - return (string) $value; - } - - private function getClassNameFromIncomplete(\__PHP_Incomplete_Class $value) - { - $array = new \ArrayObject($value); - - return $array['__PHP_Incomplete_Class_Name']; - } -} diff --git a/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php b/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php index b3c2595b0d..e187022b54 100644 --- a/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php +++ b/vendor/symfony/http-kernel/Debug/FileLinkFormatter.php @@ -31,7 +31,7 @@ class FileLinkFormatter implements \Serializable /** * @param string|\Closure $urlFormat the URL format, or a closure that returns it on-demand */ - public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, $baseDir = null, $urlFormat = null) + public function __construct($fileLinkFormat = null, RequestStack $requestStack = null, string $baseDir = null, $urlFormat = null) { $fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format'); if ($fileLinkFormat && !\is_array($fileLinkFormat)) { @@ -68,11 +68,7 @@ class FileLinkFormatter implements \Serializable public function unserialize($serialized) { - if (\PHP_VERSION_ID >= 70000) { - $this->fileLinkFormat = unserialize($serialized, array('allowed_classes' => false)); - } else { - $this->fileLinkFormat = unserialize($serialized); - } + $this->fileLinkFormat = unserialize($serialized, array('allowed_classes' => false)); } /** diff --git a/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php b/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php index 645e8f30ff..54f87edd99 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @@ -36,23 +36,15 @@ class AddAnnotatedClassesToCachePass implements CompilerPassInterface */ public function process(ContainerBuilder $container) { - $classes = array(); - $annotatedClasses = array(); + $annotatedClasses = $this->kernel->getAnnotatedClassesToCompile(); foreach ($container->getExtensions() as $extension) { if ($extension instanceof Extension) { - if (\PHP_VERSION_ID < 70000) { - $classes = array_merge($classes, $extension->getClassesToCompile()); - } $annotatedClasses = array_merge($annotatedClasses, $extension->getAnnotatedClassesToCompile()); } } $existingClasses = $this->getClassesInComposerClassMaps(); - if (\PHP_VERSION_ID < 70000) { - $classes = $container->getParameterBag()->resolveValue($classes); - $this->kernel->setClassCache($this->expandClasses($classes, $existingClasses)); - } $annotatedClasses = $container->getParameterBag()->resolveValue($annotatedClasses); $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses)); } diff --git a/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php b/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php deleted file mode 100644 index 8ae78e0d84..0000000000 --- a/vendor/symfony/http-kernel/DependencyInjection/AddClassesToCachePass.php +++ /dev/null @@ -1,25 +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\HttpKernel\DependencyInjection; - -@trigger_error('The '.__NAMESPACE__.'\AddClassesToCachePass class is deprecated since Symfony 3.3 and will be removed in 4.0.', E_USER_DEPRECATED); - -/** - * Sets the classes to compile in the cache for the container. - * - * @author Fabien Potencier <fabien@symfony.com> - * - * @deprecated since version 3.3, to be removed in 4.0. - */ -class AddClassesToCachePass extends AddAnnotatedClassesToCachePass -{ -} diff --git a/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php b/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php index 343e217b96..77c0e479ae 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/ControllerArgumentValueResolverPass.php @@ -15,6 +15,9 @@ use Symfony\Component\DependencyInjection\Argument\IteratorArgument; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; +use Symfony\Component\Stopwatch\Stopwatch; /** * Gathers and configures the argument value resolvers. @@ -27,11 +30,13 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface private $argumentResolverService; private $argumentValueResolverTag; + private $traceableResolverStopwatch; - public function __construct($argumentResolverService = 'argument_resolver', $argumentValueResolverTag = 'controller.argument_value_resolver') + public function __construct(string $argumentResolverService = 'argument_resolver', string $argumentValueResolverTag = 'controller.argument_value_resolver', string $traceableResolverStopwatch = 'debug.stopwatch') { $this->argumentResolverService = $argumentResolverService; $this->argumentValueResolverTag = $argumentValueResolverTag; + $this->traceableResolverStopwatch = $traceableResolverStopwatch; } public function process(ContainerBuilder $container) @@ -40,9 +45,20 @@ class ControllerArgumentValueResolverPass implements CompilerPassInterface return; } + $resolvers = $this->findAndSortTaggedServices($this->argumentValueResolverTag, $container); + + if ($container->getParameter('kernel.debug') && class_exists(Stopwatch::class) && $container->has($this->traceableResolverStopwatch)) { + foreach ($resolvers as $resolverReference) { + $id = (string) $resolverReference; + $container->register("debug.$id", TraceableValueResolver::class) + ->setDecoratedService($id) + ->setArguments(array(new Reference("debug.$id.inner"), new Reference($this->traceableResolverStopwatch))); + } + } + $container ->getDefinition($this->argumentResolverService) - ->replaceArgument(1, new IteratorArgument($this->findAndSortTaggedServices($this->argumentValueResolverTag, $container))) + ->replaceArgument(1, new IteratorArgument($resolvers)) ; } } diff --git a/vendor/symfony/http-kernel/DependencyInjection/Extension.php b/vendor/symfony/http-kernel/DependencyInjection/Extension.php index a382c15d67..647875554b 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/Extension.php +++ b/vendor/symfony/http-kernel/DependencyInjection/Extension.php @@ -20,26 +20,9 @@ use Symfony\Component\DependencyInjection\Extension\Extension as BaseExtension; */ abstract class Extension extends BaseExtension { - private $classes = array(); private $annotatedClasses = array(); /** - * Gets the classes to cache. - * - * @return array An array of classes - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function getClassesToCompile() - { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', E_USER_DEPRECATED); - } - - return $this->classes; - } - - /** * Gets the annotated classes to cache. * * @return array An array of classes @@ -50,22 +33,6 @@ abstract class Extension extends BaseExtension } /** - * Adds classes to the class cache. - * - * @param array $classes An array of class patterns - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function addClassesToCompile(array $classes) - { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', E_USER_DEPRECATED); - } - - $this->classes = array_merge($this->classes, $classes); - } - - /** * Adds annotated classes to the class cache. * * @param array $annotatedClasses An array of class patterns diff --git a/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php b/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php index 06a39c8bc0..2a8c1b1b11 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/FragmentRendererPass.php @@ -28,11 +28,7 @@ class FragmentRendererPass implements CompilerPassInterface private $handlerService; private $rendererTag; - /** - * @param string $handlerService Service name of the fragment handler in the container - * @param string $rendererTag Tag name used for fragments - */ - public function __construct($handlerService = 'fragment.handler', $rendererTag = 'kernel.fragment_renderer') + public function __construct(string $handlerService = 'fragment.handler', string $rendererTag = 'kernel.fragment_renderer') { $this->handlerService = $handlerService; $this->rendererTag = $rendererTag; diff --git a/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php b/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php index 00b05959cf..4bb47902b5 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php +++ b/vendor/symfony/http-kernel/DependencyInjection/LazyLoadingFragmentHandler.php @@ -23,18 +23,9 @@ use Symfony\Component\HttpKernel\Fragment\FragmentHandler; class LazyLoadingFragmentHandler extends FragmentHandler { private $container; - /** - * @deprecated since version 3.3, to be removed in 4.0 - */ - private $rendererIds = array(); private $initialized = array(); - /** - * @param ContainerInterface $container A container - * @param RequestStack $requestStack The Request stack that controls the lifecycle of requests - * @param bool $debug Whether the debug mode is enabled or not - */ - public function __construct(ContainerInterface $container, RequestStack $requestStack, $debug = false) + public function __construct(ContainerInterface $container, RequestStack $requestStack, bool $debug = false) { $this->container = $container; @@ -42,33 +33,10 @@ class LazyLoadingFragmentHandler extends FragmentHandler } /** - * Adds a service as a fragment renderer. - * - * @param string $name The service name - * @param string $renderer The render service id - * - * @deprecated since version 3.3, to be removed in 4.0 - */ - public function addRendererService($name, $renderer) - { - @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED); - - $this->rendererIds[$name] = $renderer; - } - - /** * {@inheritdoc} */ public function render($uri, $renderer = 'inline', array $options = array()) { - // BC 3.x, to be removed in 4.0 - if (isset($this->rendererIds[$renderer])) { - $this->addRenderer($this->container->get($this->rendererIds[$renderer])); - unset($this->rendererIds[$renderer]); - - return parent::render($uri, $renderer, $options); - } - if (!isset($this->initialized[$renderer]) && $this->container->has($renderer)) { $this->addRenderer($this->container->get($renderer)); $this->initialized[$renderer] = true; diff --git a/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php index cb05f6fbeb..125464b123 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php @@ -33,11 +33,13 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface { private $resolverServiceId; private $controllerTag; + private $controllerLocator; - public function __construct($resolverServiceId = 'argument_resolver.service', $controllerTag = 'controller.service_arguments') + public function __construct(string $resolverServiceId = 'argument_resolver.service', string $controllerTag = 'controller.service_arguments', string $controllerLocator = 'argument_resolver.controller_locator') { $this->resolverServiceId = $resolverServiceId; $this->controllerTag = $controllerTag; + $this->controllerLocator = $controllerLocator; } public function process(ContainerBuilder $container) @@ -120,33 +122,38 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface $args = array(); foreach ($parameters as $p) { /** @var \ReflectionParameter $p */ - $type = $target = ProxyHelper::getTypeHint($r, $p, true); + $type = ltrim($target = ProxyHelper::getTypeHint($r, $p), '\\'); $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE; if (isset($arguments[$r->name][$p->name])) { $target = $arguments[$r->name][$p->name]; if ('?' !== $target[0]) { - $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE; + $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } elseif ('' === $target = (string) substr($target, 1)) { throw new InvalidArgumentException(sprintf('A "%s" tag must have non-empty "id" attributes for service "%s".', $this->controllerTag, $id)); } elseif ($p->allowsNull() && !$p->isOptional()) { $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE; } - } elseif (isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) { + } elseif (isset($bindings[$bindingName = $type.' $'.$p->name]) || isset($bindings[$bindingName = '$'.$p->name]) || isset($bindings[$bindingName = $type])) { $binding = $bindings[$bindingName]; list($bindingValue, $bindingId) = $binding->getValues(); + $binding->setValues(array($bindingValue, $bindingId, true)); if (!$bindingValue instanceof Reference) { - continue; + $args[$p->name] = new Reference('.value.'.$container->hash($bindingValue)); + $container->register((string) $args[$p->name], 'mixed') + ->setFactory('current') + ->addArgument(array($bindingValue)); + } else { + $args[$p->name] = $bindingValue; } - $binding->setValues(array($bindingValue, $bindingId, true)); - $args[$p->name] = $bindingValue; - continue; - } elseif (!$type || !$autowire) { + } elseif (!$type || !$autowire || '\\' !== $target[0]) { continue; + } elseif (!$p->allowsNull()) { + $invalidBehavior = ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE; } if (Request::class === $type) { @@ -164,16 +171,19 @@ class RegisterControllerArgumentLocatorsPass implements CompilerPassInterface throw new InvalidArgumentException($message); } - $args[$p->name] = $type ? new TypedReference($target, $type, $r->class, $invalidBehavior) : new Reference($target, $invalidBehavior); + $target = ltrim($target, '\\'); + $args[$p->name] = $type ? new TypedReference($target, $type, $invalidBehavior, $p->name) : new Reference($target, $invalidBehavior); } // register the maps as a per-method service-locators if ($args) { - $controllers[$id.':'.$r->name] = ServiceLocatorTagPass::register($container, $args); + $controllers[$id.'::'.$r->name] = ServiceLocatorTagPass::register($container, $args); } } } $container->getDefinition($this->resolverServiceId) - ->replaceArgument(0, ServiceLocatorTagPass::register($container, $controllers)); + ->replaceArgument(0, $controllerLocatorRef = ServiceLocatorTagPass::register($container, $controllers)); + + $container->setAlias($this->controllerLocator, (string) $controllerLocatorRef); } } diff --git a/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php b/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php index e230a67ea6..596b6188f6 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPass.php @@ -21,21 +21,16 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; */ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface { - private $resolverServiceId; + private $controllerLocator; - public function __construct($resolverServiceId = 'argument_resolver.service') + public function __construct(string $controllerLocator = 'argument_resolver.controller_locator') { - $this->resolverServiceId = $resolverServiceId; + $this->controllerLocator = $controllerLocator; } public function process(ContainerBuilder $container) { - if (false === $container->hasDefinition($this->resolverServiceId)) { - return; - } - - $serviceResolver = $container->getDefinition($this->resolverServiceId); - $controllerLocator = $container->getDefinition((string) $serviceResolver->getArgument(0)); + $controllerLocator = $container->findDefinition($this->controllerLocator); $controllers = $controllerLocator->getArgument(0); foreach ($controllers as $controller => $argumentRef) { @@ -47,8 +42,7 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface } else { // any methods listed for call-at-instantiation cannot be actions $reason = false; - $action = substr(strrchr($controller, ':'), 1); - $id = substr($controller, 0, -1 - \strlen($action)); + list($id, $action) = explode('::', $controller); $controllerDef = $container->getDefinition($id); foreach ($controllerDef->getMethodCalls() as list($method)) { if (0 === strcasecmp($action, $method)) { @@ -57,9 +51,9 @@ class RemoveEmptyControllerArgumentLocatorsPass implements CompilerPassInterface } } if (!$reason) { - if ($controllerDef->getClass() === $id) { - $controllers[$id.'::'.$action] = $argumentRef; - } + // Deprecated since Symfony 4.1. See Symfony\Component\HttpKernel\Controller\ContainerControllerResolver + $controllers[$id.':'.$action] = $argumentRef; + if ('__invoke' === $action) { $controllers[$id] = $argumentRef; } diff --git a/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php b/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php index 29433a6d5b..564f879ca7 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php +++ b/vendor/symfony/http-kernel/DependencyInjection/ResettableServicePass.php @@ -25,7 +25,7 @@ class ResettableServicePass implements CompilerPassInterface { private $tagName; - public function __construct($tagName = 'kernel.reset') + public function __construct(string $tagName = 'kernel.reset') { $this->tagName = $tagName; } diff --git a/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php b/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php index b82d2fef3c..734fadbd74 100644 --- a/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php +++ b/vendor/symfony/http-kernel/DependencyInjection/ServicesResetter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\HttpKernel\DependencyInjection; +use Symfony\Contracts\Service\ResetInterface; + /** * Resets provided services. * @@ -19,7 +21,7 @@ namespace Symfony\Component\HttpKernel\DependencyInjection; * * @internal */ -class ServicesResetter +class ServicesResetter implements ResetInterface { private $resettableServices; private $resetMethods; diff --git a/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php b/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php index 043e0584a8..5e178f2b0b 100644 --- a/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterControllerArgumentsEvent.php @@ -30,7 +30,7 @@ class FilterControllerArgumentsEvent extends FilterControllerEvent { private $arguments; - public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, $requestType) + public function __construct(HttpKernelInterface $kernel, callable $controller, array $arguments, Request $request, ?int $requestType) { parent::__construct($kernel, $controller, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/FilterControllerEvent.php b/vendor/symfony/http-kernel/Event/FilterControllerEvent.php index a4cfd62587..7eab449376 100644 --- a/vendor/symfony/http-kernel/Event/FilterControllerEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterControllerEvent.php @@ -29,7 +29,7 @@ class FilterControllerEvent extends KernelEvent { private $controller; - public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, $requestType) + public function __construct(HttpKernelInterface $kernel, callable $controller, Request $request, ?int $requestType) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/FilterResponseEvent.php b/vendor/symfony/http-kernel/Event/FilterResponseEvent.php index 1b80e34bab..04589f7b5c 100644 --- a/vendor/symfony/http-kernel/Event/FilterResponseEvent.php +++ b/vendor/symfony/http-kernel/Event/FilterResponseEvent.php @@ -28,7 +28,7 @@ class FilterResponseEvent extends KernelEvent { private $response; - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, Response $response) + public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, Response $response) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php b/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php index d68eaa18c2..a0082821de 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseForControllerResultEvent.php @@ -32,7 +32,7 @@ class GetResponseForControllerResultEvent extends GetResponseEvent */ private $controllerResult; - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, $controllerResult) + public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, $controllerResult) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php b/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php index 6199838fcc..7fab006d13 100644 --- a/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php +++ b/vendor/symfony/http-kernel/Event/GetResponseForExceptionEvent.php @@ -41,7 +41,7 @@ class GetResponseForExceptionEvent extends GetResponseEvent */ private $allowCustomResponseCode = false; - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType, \Exception $e) + public function __construct(HttpKernelInterface $kernel, Request $request, int $requestType, \Exception $e) { parent::__construct($kernel, $request, $requestType); diff --git a/vendor/symfony/http-kernel/Event/KernelEvent.php b/vendor/symfony/http-kernel/Event/KernelEvent.php index cccf01f3da..f3db8a60d9 100644 --- a/vendor/symfony/http-kernel/Event/KernelEvent.php +++ b/vendor/symfony/http-kernel/Event/KernelEvent.php @@ -32,7 +32,7 @@ class KernelEvent extends Event * @param int $requestType The request type the kernel is currently processing; one of * HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST */ - public function __construct(HttpKernelInterface $kernel, Request $request, $requestType) + public function __construct(HttpKernelInterface $kernel, Request $request, ?int $requestType) { $this->kernel = $kernel; $this->request = $request; diff --git a/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php b/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php index 41187d4125..c7c1717069 100644 --- a/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/AbstractSessionListener.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpKernel\EventListener; +use Psr\Container\ContainerInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -20,28 +21,48 @@ use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** - * Sets the session in the request. + * Sets the session onto the request on the "kernel.request" event and saves + * it on the "kernel.response" event. + * + * In addition, if the session has been started it overrides the Cache-Control + * header in such a way that all caching is disabled in that case. + * If you have a scenario where caching responses with session information in + * them makes sense, you can disable this behaviour by setting the header + * AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER on the response. * * @author Johannes M. Schmitt <schmittjoh@gmail.com> + * @author Tobias Schultze <http://tobion.de> */ abstract class AbstractSessionListener implements EventSubscriberInterface { + const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl'; + + protected $container; private $sessionUsageStack = array(); + public function __construct(ContainerInterface $container = null) + { + $this->container = $container; + } + public function onKernelRequest(GetResponseEvent $event) { if (!$event->isMasterRequest()) { return; } + $session = null; $request = $event->getRequest(); - $session = $this->getSession(); - $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : null; - if (null === $session || $request->hasSession()) { - return; + if ($request->hasSession()) { + // no-op + } elseif (method_exists($request, 'setSessionFactory')) { + $request->setSessionFactory(function () { return $this->getSession(); }); + } elseif ($session = $this->getSession()) { + $request->setSession($session); } - $request->setSession($session); + $session = $session ?? ($this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null); + $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0; } public function onKernelResponse(FilterResponseEvent $event) @@ -50,15 +71,51 @@ abstract class AbstractSessionListener implements EventSubscriberInterface return; } - if (!$session = $event->getRequest()->getSession()) { + $response = $event->getResponse(); + $autoCacheControl = !$response->headers->has(self::NO_AUTO_CACHE_CONTROL_HEADER); + // Always remove the internal header if present + $response->headers->remove(self::NO_AUTO_CACHE_CONTROL_HEADER); + + if (!$session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : $event->getRequest()->getSession()) { return; } if ($session instanceof Session ? $session->getUsageIndex() !== end($this->sessionUsageStack) : $session->isStarted()) { - $event->getResponse() - ->setPrivate() - ->setMaxAge(0) - ->headers->addCacheControlDirective('must-revalidate'); + if ($autoCacheControl) { + $response + ->setPrivate() + ->setMaxAge(0) + ->headers->addCacheControlDirective('must-revalidate'); + } + } + + if ($session->isStarted()) { + /* + * Saves the session, in case it is still open, before sending the response/headers. + * + * This ensures several things in case the developer did not save the session explicitly: + * + * * If a session save handler without locking is used, it ensures the data is available + * on the next request, e.g. after a redirect. PHPs auto-save at script end via + * session_register_shutdown is executed after fastcgi_finish_request. So in this case + * the data could be missing the next request because it might not be saved the moment + * the new request is processed. + * * A locking save handler (e.g. the native 'files') circumvents concurrency problems like + * the one above. But by saving the session before long-running things in the terminate event, + * we ensure the session is not blocked longer than needed. + * * When regenerating the session ID no locking is involved in PHPs session design. See + * https://bugs.php.net/bug.php?id=61470 for a discussion. So in this case, the session must + * be saved anyway before sending the headers with the new session ID. Otherwise session + * data could get lost again for concurrent requests with the new ID. One result could be + * that you get logged out after just logging in. + * + * This listener should be executed as one of the last listeners, so that previous listeners + * can still operate on the open session. This prevents the overhead of restarting it. + * Listeners after closing the session can still work with the session as usual because + * Symfonys session implementation starts the session on demand. So writing to it after + * it is saved will just restart it. + */ + $session->save(); } } @@ -76,7 +133,7 @@ abstract class AbstractSessionListener implements EventSubscriberInterface { return array( KernelEvents::REQUEST => array('onKernelRequest', 128), - // low priority to come after regular response listeners, same as SaveSessionListener + // low priority to come after regular response listeners, but higher than StreamedResponseListener KernelEvents::RESPONSE => array('onKernelResponse', -1000), KernelEvents::FINISH_REQUEST => array('onFinishRequest'), ); diff --git a/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php b/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php index cb5da50bd0..993c6ddf97 100644 --- a/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/AbstractTestSessionListener.php @@ -30,6 +30,12 @@ use Symfony\Component\HttpKernel\KernelEvents; abstract class AbstractTestSessionListener implements EventSubscriberInterface { private $sessionId; + private $sessionOptions; + + public function __construct(array $sessionOptions = array()) + { + $this->sessionOptions = $sessionOptions; + } public function onKernelRequest(GetResponseEvent $event) { @@ -61,16 +67,23 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface return; } - if (!$session = $event->getRequest()->getSession()) { + $request = $event->getRequest(); + if (!$request->hasSession()) { return; } + $session = $request->getSession(); if ($wasStarted = $session->isStarted()) { $session->save(); } if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) { - $params = session_get_cookie_params(); + $params = session_get_cookie_params() + array('samesite' => null); + foreach ($this->sessionOptions as $k => $v) { + if (0 === strpos($k, 'cookie_')) { + $params[substr($k, 7)] = $v; + } + } foreach ($event->getResponse()->headers->getCookies() as $cookie) { if ($session->getName() === $cookie->getName() && $params['path'] === $cookie->getPath() && $params['domain'] == $cookie->getDomain()) { @@ -78,7 +91,7 @@ abstract class AbstractTestSessionListener implements EventSubscriberInterface } } - $event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'])); + $event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly'], false, $params['samesite'] ?: null)); $this->sessionId = $session->getId(); } } diff --git a/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php b/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php index 04137c7468..47fe05c5e1 100644 --- a/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php +++ b/vendor/symfony/http-kernel/EventListener/DebugHandlersListener.php @@ -48,15 +48,15 @@ class DebugHandlersListener implements EventSubscriberInterface * @param string|array $fileLinkFormat The format for links to source files * @param bool $scope Enables/disables scoping mode */ - public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, $throwAt = E_ALL, $scream = true, $fileLinkFormat = null, $scope = true) + public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, ?int $throwAt = E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true) { $this->exceptionHandler = $exceptionHandler; $this->logger = $logger; $this->levels = null === $levels ? E_ALL : $levels; - $this->throwAt = is_numeric($throwAt) ? (int) $throwAt : (null === $throwAt ? null : ($throwAt ? E_ALL : null)); - $this->scream = (bool) $scream; + $this->throwAt = \is_int($throwAt) ? $throwAt : (null === $throwAt ? null : ($throwAt ? E_ALL : null)); + $this->scream = $scream; $this->fileLinkFormat = $fileLinkFormat; - $this->scope = (bool) $scope; + $this->scope = $scope; } /** diff --git a/vendor/symfony/http-kernel/EventListener/DumpListener.php b/vendor/symfony/http-kernel/EventListener/DumpListener.php index de19e13113..3acbe7d46c 100644 --- a/vendor/symfony/http-kernel/EventListener/DumpListener.php +++ b/vendor/symfony/http-kernel/EventListener/DumpListener.php @@ -15,6 +15,7 @@ use Symfony\Component\Console\ConsoleEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\VarDumper\Cloner\ClonerInterface; use Symfony\Component\VarDumper\Dumper\DataDumperInterface; +use Symfony\Component\VarDumper\Server\Connection; use Symfony\Component\VarDumper\VarDumper; /** @@ -26,20 +27,27 @@ class DumpListener implements EventSubscriberInterface { private $cloner; private $dumper; + private $connection; - public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper) + public function __construct(ClonerInterface $cloner, DataDumperInterface $dumper, Connection $connection = null) { $this->cloner = $cloner; $this->dumper = $dumper; + $this->connection = $connection; } public function configure() { $cloner = $this->cloner; $dumper = $this->dumper; + $connection = $this->connection; - VarDumper::setHandler(function ($var) use ($cloner, $dumper) { - $dumper->dump($cloner->cloneVar($var)); + VarDumper::setHandler(static function ($var) use ($cloner, $dumper, $connection) { + $data = $cloner->cloneVar($var); + + if (!$connection || !$connection->write($data)) { + $dumper->dump($data); + } }); } diff --git a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php index 147e09013d..02b1d4ddc3 100644 --- a/vendor/symfony/http-kernel/EventListener/ExceptionListener.php +++ b/vendor/symfony/http-kernel/EventListener/ExceptionListener.php @@ -13,9 +13,11 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Log\LoggerInterface; use Symfony\Component\Debug\Exception\FlattenException; +use Symfony\Component\Debug\ExceptionHandler; 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; @@ -33,28 +35,49 @@ class ExceptionListener implements EventSubscriberInterface protected $controller; protected $logger; protected $debug; + private $charset; + private $fileLinkFormat; + private $isTerminating = false; - public function __construct($controller, LoggerInterface $logger = null, $debug = false) + public function __construct($controller, LoggerInterface $logger = null, $debug = false, string $charset = null, $fileLinkFormat = null) { $this->controller = $controller; $this->logger = $logger; $this->debug = $debug; + $this->charset = $charset; + $this->fileLinkFormat = $fileLinkFormat; + } + + public function logKernelException(GetResponseForExceptionEvent $event) + { + $e = FlattenException::create($event->getException()); + + $this->logException($event->getException(), sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', $e->getClass(), $e->getMessage(), $e->getFile(), $e->getLine())); } public function onKernelException(GetResponseForExceptionEvent $event) { + if (null === $this->controller) { + if (!$event->isMasterRequest()) { + return; + } + if (!$this->isTerminating) { + $this->isTerminating = true; + + return; + } + $this->isTerminating = false; + } $exception = $event->getException(); - $request = $event->getRequest(); + $request = $this->duplicateRequest($exception, $event->getRequest()); $eventDispatcher = \func_num_args() > 2 ? func_get_arg(2) : null; - $this->logException($exception, sprintf('Uncaught PHP Exception %s: "%s" at %s line %s', \get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine())); - - $request = $this->duplicateRequest($exception, $request); - try { $response = $event->getKernel()->handle($request, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { - $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', \get_class($e), $e->getMessage(), $e->getFile(), $e->getLine())); + $f = FlattenException::create($e); + + $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); $wrapper = $e; @@ -82,10 +105,18 @@ class ExceptionListener implements EventSubscriberInterface } } + public function reset() + { + $this->isTerminating = false; + } + public static function getSubscribedEvents() { return array( - KernelEvents::EXCEPTION => array('onKernelException', -128), + KernelEvents::EXCEPTION => array( + array('logKernelException', 0), + array('onKernelException', -128), + ), ); } @@ -112,13 +143,17 @@ class ExceptionListener implements EventSubscriberInterface * @param \Exception $exception The thrown exception * @param Request $request The original request * - * @return Request $request The cloned request + * @return Request The cloned request */ protected function duplicateRequest(\Exception $exception, Request $request) { $attributes = array( - '_controller' => $this->controller, - 'exception' => FlattenException::create($exception), + 'exception' => $exception = FlattenException::create($exception), + '_controller' => $this->controller ?: function () use ($exception) { + $handler = new ExceptionHandler($this->debug, $this->charset, $this->fileLinkFormat); + + return new Response($handler->getHtml($exception), $exception->getStatusCode(), $exception->getHeaders()); + }, 'logger' => $this->logger instanceof DebugLoggerInterface ? $this->logger : null, ); $request = $request->duplicate(null, null, $attributes); diff --git a/vendor/symfony/http-kernel/EventListener/FragmentListener.php b/vendor/symfony/http-kernel/EventListener/FragmentListener.php index 574d7c05c9..b47aa7cca0 100644 --- a/vendor/symfony/http-kernel/EventListener/FragmentListener.php +++ b/vendor/symfony/http-kernel/EventListener/FragmentListener.php @@ -38,7 +38,7 @@ class FragmentListener implements EventSubscriberInterface * @param UriSigner $signer A UriSigner instance * @param string $fragmentPath The path that triggers this listener */ - public function __construct(UriSigner $signer, $fragmentPath = '/_fragment') + public function __construct(UriSigner $signer, string $fragmentPath = '/_fragment') { $this->signer = $signer; $this->fragmentPath = $fragmentPath; diff --git a/vendor/symfony/http-kernel/EventListener/LocaleListener.php b/vendor/symfony/http-kernel/EventListener/LocaleListener.php index ed0236efc8..1067e8a0a5 100644 --- a/vendor/symfony/http-kernel/EventListener/LocaleListener.php +++ b/vendor/symfony/http-kernel/EventListener/LocaleListener.php @@ -35,7 +35,7 @@ class LocaleListener implements EventSubscriberInterface * @param string $defaultLocale The default locale * @param RequestContextAwareInterface|null $router The router */ - public function __construct(RequestStack $requestStack, $defaultLocale = 'en', RequestContextAwareInterface $router = null) + public function __construct(RequestStack $requestStack, string $defaultLocale = 'en', RequestContextAwareInterface $router = null) { $this->defaultLocale = $defaultLocale; $this->requestStack = $requestStack; diff --git a/vendor/symfony/http-kernel/EventListener/ProfilerListener.php b/vendor/symfony/http-kernel/EventListener/ProfilerListener.php index 2e54a92f08..03344be7a6 100644 --- a/vendor/symfony/http-kernel/EventListener/ProfilerListener.php +++ b/vendor/symfony/http-kernel/EventListener/ProfilerListener.php @@ -43,12 +43,12 @@ class ProfilerListener implements EventSubscriberInterface * @param bool $onlyException True if the profiler only collects data when an exception occurs, false otherwise * @param bool $onlyMasterRequests True if the profiler only collects data when the request is a master request, false otherwise */ - public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, $onlyException = false, $onlyMasterRequests = false) + public function __construct(Profiler $profiler, RequestStack $requestStack, RequestMatcherInterface $matcher = null, bool $onlyException = false, bool $onlyMasterRequests = false) { $this->profiler = $profiler; $this->matcher = $matcher; - $this->onlyException = (bool) $onlyException; - $this->onlyMasterRequests = (bool) $onlyMasterRequests; + $this->onlyException = $onlyException; + $this->onlyMasterRequests = $onlyMasterRequests; $this->profiles = new \SplObjectStorage(); $this->parents = new \SplObjectStorage(); $this->requestStack = $requestStack; @@ -121,7 +121,7 @@ class ProfilerListener implements EventSubscriberInterface { return array( KernelEvents::RESPONSE => array('onKernelResponse', -100), - KernelEvents::EXCEPTION => 'onKernelException', + KernelEvents::EXCEPTION => array('onKernelException', 0), KernelEvents::TERMINATE => array('onKernelTerminate', -1024), ); } diff --git a/vendor/symfony/http-kernel/EventListener/ResponseListener.php b/vendor/symfony/http-kernel/EventListener/ResponseListener.php index f24784527b..0550c0230e 100644 --- a/vendor/symfony/http-kernel/EventListener/ResponseListener.php +++ b/vendor/symfony/http-kernel/EventListener/ResponseListener.php @@ -24,7 +24,7 @@ class ResponseListener implements EventSubscriberInterface { private $charset; - public function __construct($charset) + public function __construct(string $charset) { $this->charset = $charset; } diff --git a/vendor/symfony/http-kernel/EventListener/RouterListener.php b/vendor/symfony/http-kernel/EventListener/RouterListener.php index ab5c86cdd0..3919284564 100644 --- a/vendor/symfony/http-kernel/EventListener/RouterListener.php +++ b/vendor/symfony/http-kernel/EventListener/RouterListener.php @@ -57,7 +57,7 @@ class RouterListener implements EventSubscriberInterface * * @throws \InvalidArgumentException */ - public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, $projectDir = null, $debug = true) + public function __construct($matcher, RequestStack $requestStack, RequestContext $context = null, LoggerInterface $logger = null, string $projectDir = null, bool $debug = true) { if (!$matcher instanceof UrlMatcherInterface && !$matcher instanceof RequestMatcherInterface) { throw new \InvalidArgumentException('Matcher must either implement UrlMatcherInterface or RequestMatcherInterface.'); diff --git a/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php b/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php index 36809b59af..99382ea3cc 100644 --- a/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/SaveSessionListener.php @@ -11,36 +11,16 @@ namespace Symfony\Component\HttpKernel\EventListener; +@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.1, use AbstractSessionListener instead.', SaveSessionListener::class), E_USER_DEPRECATED); + use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; /** - * Saves the session, in case it is still open, before sending the response/headers. - * - * This ensures several things in case the developer did not save the session explicitly: - * - * * If a session save handler without locking is used, it ensures the data is available - * on the next request, e.g. after a redirect. PHPs auto-save at script end via - * session_register_shutdown is executed after fastcgi_finish_request. So in this case - * the data could be missing the next request because it might not be saved the moment - * the new request is processed. - * * A locking save handler (e.g. the native 'files') circumvents concurrency problems like - * the one above. But by saving the session before long-running things in the terminate event, - * we ensure the session is not blocked longer than needed. - * * When regenerating the session ID no locking is involved in PHPs session design. See - * https://bugs.php.net/bug.php?id=61470 for a discussion. So in this case, the session must - * be saved anyway before sending the headers with the new session ID. Otherwise session - * data could get lost again for concurrent requests with the new ID. One result could be - * that you get logged out after just logging in. - * - * This listener should be executed as one of the last listeners, so that previous listeners - * can still operate on the open session. This prevents the overhead of restarting it. - * Listeners after closing the session can still work with the session as usual because - * Symfonys session implementation starts the session on demand. So writing to it after - * it is saved will just restart it. - * * @author Tobias Schultze <http://tobion.de> + * + * @deprecated since Symfony 4.1, use AbstractSessionListener instead */ class SaveSessionListener implements EventSubscriberInterface { diff --git a/vendor/symfony/http-kernel/EventListener/SessionListener.php b/vendor/symfony/http-kernel/EventListener/SessionListener.php index 39ebfd922f..75624b6c5c 100644 --- a/vendor/symfony/http-kernel/EventListener/SessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/SessionListener.php @@ -12,18 +12,21 @@ namespace Symfony\Component\HttpKernel\EventListener; use Psr\Container\ContainerInterface; +use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage; /** * Sets the session in the request. * + * When the passed container contains a "session_storage" entry which + * holds a NativeSessionStorage instance, the "cookie_secure" option + * will be set to true whenever the current master request is secure. + * * @author Fabien Potencier <fabien@symfony.com> * - * @final since version 3.3 + * @final */ class SessionListener extends AbstractSessionListener { - private $container; - public function __construct(ContainerInterface $container) { $this->container = $container; @@ -35,6 +38,13 @@ class SessionListener extends AbstractSessionListener return; } + if ($this->container->has('session_storage') + && ($storage = $this->container->get('session_storage')) instanceof NativeSessionStorage + && $this->container->get('request_stack')->getMasterRequest()->isSecure() + ) { + $storage->setOptions(array('cookie_secure' => true)); + } + return $this->container->get('session'); } } diff --git a/vendor/symfony/http-kernel/EventListener/TestSessionListener.php b/vendor/symfony/http-kernel/EventListener/TestSessionListener.php index 36abb422f4..23589a2bb3 100644 --- a/vendor/symfony/http-kernel/EventListener/TestSessionListener.php +++ b/vendor/symfony/http-kernel/EventListener/TestSessionListener.php @@ -18,15 +18,16 @@ use Psr\Container\ContainerInterface; * * @author Fabien Potencier <fabien@symfony.com> * - * @final since version 3.3 + * @final */ class TestSessionListener extends AbstractTestSessionListener { private $container; - public function __construct(ContainerInterface $container) + public function __construct(ContainerInterface $container, array $sessionOptions = array()) { $this->container = $container; + parent::__construct($sessionOptions); } protected function getSession() diff --git a/vendor/symfony/http-kernel/EventListener/TranslatorListener.php b/vendor/symfony/http-kernel/EventListener/TranslatorListener.php index 2a5fc71280..7cf059886d 100644 --- a/vendor/symfony/http-kernel/EventListener/TranslatorListener.php +++ b/vendor/symfony/http-kernel/EventListener/TranslatorListener.php @@ -17,7 +17,8 @@ use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\KernelEvents; -use Symfony\Component\Translation\TranslatorInterface; +use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; +use Symfony\Contracts\Translation\TranslatorInterface; /** * Synchronizes the locale between the request and the translator. @@ -29,8 +30,14 @@ class TranslatorListener implements EventSubscriberInterface private $translator; private $requestStack; - public function __construct(TranslatorInterface $translator, RequestStack $requestStack) + /** + * @param TranslatorInterface $translator + */ + public function __construct($translator, RequestStack $requestStack) { + if (!$translator instanceof LegacyTranslatorInterface && !$translator instanceof TranslatorInterface) { + throw new \TypeError(sprintf('Argument 1 passed to %s() must be an instance of %s, %s given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator))); + } $this->translator = $translator; $this->requestStack = $requestStack; } diff --git a/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php b/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php index 3941884266..3aedbf97fe 100644 --- a/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/AccessDeniedHttpException.php @@ -21,9 +21,10 @@ class AccessDeniedHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(403, $message, $previous, array(), $code); + parent::__construct(403, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php b/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php index c28d83739c..ff215db45f 100644 --- a/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php +++ b/vendor/symfony/http-kernel/Exception/BadRequestHttpException.php @@ -20,9 +20,10 @@ class BadRequestHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(400, $message, $previous, array(), $code); + parent::__construct(400, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/ConflictHttpException.php b/vendor/symfony/http-kernel/Exception/ConflictHttpException.php index 79f24f2e56..60195daf7b 100644 --- a/vendor/symfony/http-kernel/Exception/ConflictHttpException.php +++ b/vendor/symfony/http-kernel/Exception/ConflictHttpException.php @@ -20,9 +20,10 @@ class ConflictHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(409, $message, $previous, array(), $code); + parent::__construct(409, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php b/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php new file mode 100644 index 0000000000..39149aa5b7 --- /dev/null +++ b/vendor/symfony/http-kernel/Exception/ControllerDoesNotReturnResponseException.php @@ -0,0 +1,78 @@ +<?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\Exception; + +/** + * @author Grégoire Pineau <lyrixx@lyrixx.info> + */ +class ControllerDoesNotReturnResponseException extends \LogicException +{ + public function __construct(string $message, callable $controller, string $file, int $line) + { + parent::__construct($message); + + if (!$controllerDefinition = $this->parseControllerDefinition($controller)) { + return; + } + + $this->file = $controllerDefinition['file']; + $this->line = $controllerDefinition['line']; + $r = new \ReflectionProperty(\Exception::class, 'trace'); + $r->setAccessible(true); + $r->setValue($this, array_merge(array( + array( + 'line' => $line, + 'file' => $file, + ), + ), $this->getTrace())); + } + + private function parseControllerDefinition(callable $controller): ?array + { + if (\is_string($controller) && false !== strpos($controller, '::')) { + $controller = explode('::', $controller); + } + + if (\is_array($controller)) { + try { + $r = new \ReflectionMethod($controller[0], $controller[1]); + + return array( + 'file' => $r->getFileName(), + 'line' => $r->getEndLine(), + ); + } catch (\ReflectionException $e) { + return null; + } + } + + if ($controller instanceof \Closure) { + $r = new \ReflectionFunction($controller); + + return array( + 'file' => $r->getFileName(), + 'line' => $r->getEndLine(), + ); + } + + if (\is_object($controller)) { + $r = new \ReflectionClass($controller); + + return array( + 'file' => $r->getFileName(), + 'line' => $r->getEndLine(), + ); + } + + return null; + } +} diff --git a/vendor/symfony/http-kernel/Exception/GoneHttpException.php b/vendor/symfony/http-kernel/Exception/GoneHttpException.php index 84e6915df7..f2f3515f77 100644 --- a/vendor/symfony/http-kernel/Exception/GoneHttpException.php +++ b/vendor/symfony/http-kernel/Exception/GoneHttpException.php @@ -20,9 +20,10 @@ class GoneHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(410, $message, $previous, array(), $code); + parent::__construct(410, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/HttpException.php b/vendor/symfony/http-kernel/Exception/HttpException.php index e8e3760583..dab73120d0 100644 --- a/vendor/symfony/http-kernel/Exception/HttpException.php +++ b/vendor/symfony/http-kernel/Exception/HttpException.php @@ -21,7 +21,7 @@ class HttpException extends \RuntimeException implements HttpExceptionInterface private $statusCode; private $headers; - public function __construct($statusCode, $message = null, \Exception $previous = null, array $headers = array(), $code = 0) + public function __construct(int $statusCode, string $message = null, \Exception $previous = null, array $headers = array(), ?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 645efe87d7..46b76ba6a3 100644 --- a/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php +++ b/vendor/symfony/http-kernel/Exception/LengthRequiredHttpException.php @@ -20,9 +20,10 @@ class LengthRequiredHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(411, $message, $previous, array(), $code); + parent::__construct(411, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php b/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php index e308a5fee2..b0085c16fa 100644 --- a/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/MethodNotAllowedHttpException.php @@ -21,10 +21,11 @@ class MethodNotAllowedHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct(array $allow, $message = null, \Exception $previous = null, $code = 0) + public function __construct(array $allow, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = array()) { - $headers = array('Allow' => strtoupper(implode(', ', $allow))); + $headers['Allow'] = strtoupper(implode(', ', $allow)); parent::__construct(405, $message, $previous, $headers, $code); } diff --git a/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php b/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php index 097a13fd9b..32c3089374 100644 --- a/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php +++ b/vendor/symfony/http-kernel/Exception/NotAcceptableHttpException.php @@ -20,9 +20,10 @@ class NotAcceptableHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(406, $message, $previous, array(), $code); + parent::__construct(406, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php b/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php index 878173cc7b..433ff9b9e0 100644 --- a/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php +++ b/vendor/symfony/http-kernel/Exception/NotFoundHttpException.php @@ -20,9 +20,10 @@ class NotFoundHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(404, $message, $previous, array(), $code); + parent::__construct(404, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php b/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php index 9f13a624cc..108178889c 100644 --- a/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/PreconditionFailedHttpException.php @@ -20,9 +20,10 @@ class PreconditionFailedHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(412, $message, $previous, array(), $code); + parent::__construct(412, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php b/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php index 9d0a36d7d3..3078328241 100644 --- a/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php +++ b/vendor/symfony/http-kernel/Exception/PreconditionRequiredHttpException.php @@ -22,9 +22,10 @@ class PreconditionRequiredHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(428, $message, $previous, array(), $code); + parent::__construct(428, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php b/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php index b2767c3fd5..667764779f 100644 --- a/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php +++ b/vendor/symfony/http-kernel/Exception/ServiceUnavailableHttpException.php @@ -21,12 +21,12 @@ class ServiceUnavailableHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($retryAfter = null, $message = null, \Exception $previous = null, $code = 0) + public function __construct($retryAfter = null, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = array()) { - $headers = array(); if ($retryAfter) { - $headers = array('Retry-After' => $retryAfter); + $headers['Retry-After'] = $retryAfter; } parent::__construct(503, $message, $previous, $headers, $code); diff --git a/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php b/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php index 7d8a803323..60b024c330 100644 --- a/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php +++ b/vendor/symfony/http-kernel/Exception/TooManyRequestsHttpException.php @@ -23,12 +23,12 @@ class TooManyRequestsHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($retryAfter = null, $message = null, \Exception $previous = null, $code = 0) + public function __construct($retryAfter = null, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = array()) { - $headers = array(); if ($retryAfter) { - $headers = array('Retry-After' => $retryAfter); + $headers['Retry-After'] = $retryAfter; } parent::__construct(429, $message, $previous, $headers, $code); diff --git a/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php b/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php index 05ac875c55..17ebb25464 100644 --- a/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnauthorizedHttpException.php @@ -21,10 +21,11 @@ class UnauthorizedHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($challenge, $message = null, \Exception $previous = null, $code = 0) + public function __construct(string $challenge, string $message = null, \Exception $previous = null, ?int $code = 0, array $headers = array()) { - $headers = array('WWW-Authenticate' => $challenge); + $headers['WWW-Authenticate'] = $challenge; parent::__construct(401, $message, $previous, $headers, $code); } diff --git a/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php b/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php index 01b8b8465a..3a4b40c984 100644 --- a/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnprocessableEntityHttpException.php @@ -20,9 +20,10 @@ class UnprocessableEntityHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(422, $message, $previous, array(), $code); + parent::__construct(422, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php b/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php index 6913504e83..ed6861154a 100644 --- a/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php +++ b/vendor/symfony/http-kernel/Exception/UnsupportedMediaTypeHttpException.php @@ -20,9 +20,10 @@ class UnsupportedMediaTypeHttpException extends HttpException * @param string $message The internal exception message * @param \Exception $previous The previous exception * @param int $code The internal exception code + * @param array $headers */ - public function __construct($message = null, \Exception $previous = null, $code = 0) + public function __construct(string $message = null, \Exception $previous = null, int $code = 0, array $headers = array()) { - parent::__construct(415, $message, $previous, array(), $code); + parent::__construct(415, $message, $previous, $headers, $code); } } diff --git a/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php index 3c8934ff89..6ab6ec1fd0 100644 --- a/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/AbstractSurrogateFragmentRenderer.php @@ -63,7 +63,7 @@ abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRendere { if (!$this->surrogate || !$this->surrogate->hasSurrogateCapability($request)) { if ($uri instanceof ControllerReference && $this->containsNonScalars($uri->attributes)) { - @trigger_error('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is deprecated since Symfony 3.1, and will be removed in 4.0. Use a different rendering strategy or pass scalar values.', E_USER_DEPRECATED); + throw new \InvalidArgumentException('Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is not supported. Use a different rendering strategy or pass scalar values.'); } return $this->inlineStrategy->render($uri, $request, $options); @@ -83,7 +83,7 @@ abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRendere return new Response($tag); } - private function generateSignedFragmentUri($uri, Request $request) + private function generateSignedFragmentUri($uri, Request $request): string { if (null === $this->signer) { throw new \LogicException('You must use a URI when using the ESI rendering strategy or set a URL signer.'); @@ -95,7 +95,7 @@ abstract class AbstractSurrogateFragmentRenderer extends RoutableFragmentRendere return substr($fragmentUri, \strlen($request->getSchemeAndHttpHost())); } - private function containsNonScalars(array $values) + private function containsNonScalars(array $values): bool { foreach ($values as $value) { if (\is_array($value)) { diff --git a/vendor/symfony/http-kernel/Fragment/FragmentHandler.php b/vendor/symfony/http-kernel/Fragment/FragmentHandler.php index f11db73dc9..0c31826b27 100644 --- a/vendor/symfony/http-kernel/Fragment/FragmentHandler.php +++ b/vendor/symfony/http-kernel/Fragment/FragmentHandler.php @@ -37,7 +37,7 @@ class FragmentHandler * @param FragmentRendererInterface[] $renderers An array of FragmentRendererInterface instances * @param bool $debug Whether the debug mode is enabled or not */ - public function __construct(RequestStack $requestStack, array $renderers = array(), $debug = false) + public function __construct(RequestStack $requestStack, array $renderers = array(), bool $debug = false) { $this->requestStack = $requestStack; foreach ($renderers as $renderer) { diff --git a/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php index f7150c1979..3ee0cfa264 100644 --- a/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/HIncludeFragmentRenderer.php @@ -38,7 +38,7 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer * @param string $globalDefaultTemplate The global default content (it can be a template name or the content) * @param string $charset */ - public function __construct($templating = null, UriSigner $signer = null, $globalDefaultTemplate = null, $charset = 'utf-8') + public function __construct($templating = null, UriSigner $signer = null, string $globalDefaultTemplate = null, string $charset = 'utf-8') { $this->setTemplating($templating); $this->globalDefaultTemplate = $globalDefaultTemplate; @@ -121,12 +121,7 @@ class HIncludeFragmentRenderer extends RoutableFragmentRenderer return new Response(sprintf('<hx:include src="%s"%s>%s</hx:include>', $uri, $renderedAttributes, $content)); } - /** - * @param string $template - * - * @return bool - */ - private function templateExists($template) + private function templateExists(string $template): bool { if ($this->templating instanceof EngineInterface) { try { diff --git a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php index 13fc335624..ecf12f2182 100644 --- a/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php +++ b/vendor/symfony/http-kernel/Fragment/InlineFragmentRenderer.php @@ -118,9 +118,12 @@ class InlineFragmentRenderer extends RoutableFragmentRenderer $subRequest->headers->set('Surrogate-Capability', $request->headers->get('Surrogate-Capability')); } - if ($session = $request->getSession()) { - $subRequest->setSession($session); + static $setSession; + + if (null === $setSession) { + $setSession = \Closure::bind(function ($subRequest, $request) { $subRequest->session = $request->session; }, null, Request::class); } + $setSession($subRequest, $request); if ($request->get('_format')) { $subRequest->attributes->set('_format', $request->get('_format')); diff --git a/vendor/symfony/http-kernel/HttpCache/HttpCache.php b/vendor/symfony/http-kernel/HttpCache/HttpCache.php index 44405209d4..6980745add 100644 --- a/vendor/symfony/http-kernel/HttpCache/HttpCache.php +++ b/vendor/symfony/http-kernel/HttpCache/HttpCache.php @@ -93,7 +93,7 @@ class HttpCache implements HttpKernelInterface, TerminableInterface /** * Gets the current store. * - * @return StoreInterface $store A StoreInterface instance + * @return StoreInterface A StoreInterface instance */ public function getStore() { @@ -634,23 +634,16 @@ class HttpCache implements HttpKernelInterface, TerminableInterface /** * Records that an event took place. - * - * @param Request $request A Request instance - * @param string $event The event name */ - private function record(Request $request, $event) + private function record(Request $request, string $event) { $this->traces[$this->getTraceKey($request)][] = $event; } /** * Calculates the key we use in the "trace" array for a given request. - * - * @param Request $request - * - * @return string */ - private function getTraceKey(Request $request) + private function getTraceKey(Request $request): string { $path = $request->getPathInfo(); if ($qs = $request->getQueryString()) { @@ -663,12 +656,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface /** * Checks whether the given (cached) response may be served as "stale" when a revalidation * is currently in progress. - * - * @param Response $entry - * - * @return bool true when the stale response may be served, false otherwise */ - private function mayServeStaleWhileRevalidate(Response $entry) + private function mayServeStaleWhileRevalidate(Response $entry): bool { $timeout = $entry->headers->getCacheControlDirective('stale-while-revalidate'); @@ -681,12 +670,8 @@ class HttpCache implements HttpKernelInterface, TerminableInterface /** * Waits for the store to release a locked entry. - * - * @param Request $request The request to wait for - * - * @return bool true if the lock was released before the internal timeout was hit; false if the wait timeout was exceeded */ - private function waitForLock(Request $request) + private function waitForLock(Request $request): bool { $wait = 0; while ($this->store->isLocked($request) && $wait < 100) { diff --git a/vendor/symfony/http-kernel/HttpCache/Store.php b/vendor/symfony/http-kernel/HttpCache/Store.php index 990091d065..925ca96fd4 100644 --- a/vendor/symfony/http-kernel/HttpCache/Store.php +++ b/vendor/symfony/http-kernel/HttpCache/Store.php @@ -29,11 +29,9 @@ class Store implements StoreInterface private $locks; /** - * @param string $root The path to the cache directory - * * @throws \RuntimeException */ - public function __construct($root) + public function __construct(string $root) { $this->root = $root; if (!file_exists($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) { diff --git a/vendor/symfony/http-kernel/HttpCache/SubRequestHandler.php b/vendor/symfony/http-kernel/HttpCache/SubRequestHandler.php index 9649072c16..84d7a84e79 100644 --- a/vendor/symfony/http-kernel/HttpCache/SubRequestHandler.php +++ b/vendor/symfony/http-kernel/HttpCache/SubRequestHandler.php @@ -23,42 +23,25 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; */ class SubRequestHandler { - /** - * @return Response - */ - public static function handle(HttpKernelInterface $kernel, Request $request, $type, $catch) + public static function handle(HttpKernelInterface $kernel, Request $request, $type, $catch): Response { // save global state related to trusted headers and proxies $trustedProxies = Request::getTrustedProxies(); $trustedHeaderSet = Request::getTrustedHeaderSet(); - if (\method_exists(Request::class, 'getTrustedHeaderName')) { - Request::setTrustedProxies($trustedProxies, -1); - $trustedHeaders = array( - Request::HEADER_FORWARDED => Request::getTrustedHeaderName(Request::HEADER_FORWARDED, false), - Request::HEADER_X_FORWARDED_FOR => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_FOR, false), - Request::HEADER_X_FORWARDED_HOST => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_HOST, false), - Request::HEADER_X_FORWARDED_PROTO => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_PROTO, false), - Request::HEADER_X_FORWARDED_PORT => Request::getTrustedHeaderName(Request::HEADER_X_FORWARDED_PORT, false), - ); - Request::setTrustedProxies($trustedProxies, $trustedHeaderSet); - } else { - $trustedHeaders = array( - Request::HEADER_FORWARDED => 'FORWARDED', - Request::HEADER_X_FORWARDED_FOR => 'X_FORWARDED_FOR', - Request::HEADER_X_FORWARDED_HOST => 'X_FORWARDED_HOST', - Request::HEADER_X_FORWARDED_PROTO => 'X_FORWARDED_PROTO', - Request::HEADER_X_FORWARDED_PORT => 'X_FORWARDED_PORT', - ); - } // remove untrusted values $remoteAddr = $request->server->get('REMOTE_ADDR'); if (!IpUtils::checkIp($remoteAddr, $trustedProxies)) { - foreach ($trustedHeaders as $key => $name) { - if ($trustedHeaderSet & $key) { - $request->headers->remove($name); - $request->server->remove('HTTP_'.strtoupper(str_replace('-', '_', $name))); - } + $trustedHeaders = array( + 'FORWARDED' => $trustedHeaderSet & Request::HEADER_FORWARDED, + 'X_FORWARDED_FOR' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_FOR, + 'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST, + 'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO, + 'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT, + ); + foreach (array_filter($trustedHeaders) as $name => $key) { + $request->headers->remove($name); + $request->server->remove('HTTP_'.$name); } } @@ -77,16 +60,16 @@ class SubRequestHandler // set trusted values, reusing as much as possible the global trusted settings if (Request::HEADER_FORWARDED & $trustedHeaderSet) { $trustedValues[0] .= sprintf(';host="%s";proto=%s', $request->getHttpHost(), $request->getScheme()); - $request->headers->set($name = $trustedHeaders[Request::HEADER_FORWARDED], $v = implode(', ', $trustedValues)); - $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); + $request->headers->set('Forwarded', $v = implode(', ', $trustedValues)); + $request->server->set('HTTP_FORWARDED', $v); } if (Request::HEADER_X_FORWARDED_FOR & $trustedHeaderSet) { - $request->headers->set($name = $trustedHeaders[Request::HEADER_X_FORWARDED_FOR], $v = implode(', ', $trustedIps)); - $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); + $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); + $request->server->set('HTTP_X_FORWARDED_FOR', $v); } elseif (!(Request::HEADER_FORWARDED & $trustedHeaderSet)) { Request::setTrustedProxies($trustedProxies, $trustedHeaderSet | Request::HEADER_X_FORWARDED_FOR); - $request->headers->set($name = $trustedHeaders[Request::HEADER_X_FORWARDED_FOR], $v = implode(', ', $trustedIps)); - $request->server->set('HTTP_'.strtoupper(str_replace('-', '_', $name)), $v); + $request->headers->set('X-Forwarded-For', $v = implode(', ', $trustedIps)); + $request->server->set('HTTP_X_FORWARDED_FOR', $v); } // fix the client IP address by setting it to 127.0.0.1, diff --git a/vendor/symfony/http-kernel/HttpKernel.php b/vendor/symfony/http-kernel/HttpKernel.php index 36c673093b..25a0423854 100644 --- a/vendor/symfony/http-kernel/HttpKernel.php +++ b/vendor/symfony/http-kernel/HttpKernel.php @@ -28,6 +28,7 @@ use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\Event\PostResponseEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\ControllerDoesNotReturnResponseException; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -51,9 +52,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface $this->argumentResolver = $argumentResolver; if (null === $this->argumentResolver) { - @trigger_error(sprintf('As of 3.1 an %s is used to resolve arguments. In 4.0 the $argumentResolver becomes the %s if no other is provided instead of using the $resolver argument.', ArgumentResolverInterface::class, ArgumentResolver::class), E_USER_DEPRECATED); - // fallback in case of deprecations - $this->argumentResolver = $resolver; + $this->argumentResolver = new ArgumentResolver(); } } @@ -118,7 +117,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface * @throws \LogicException If one of the listener does not behave as expected * @throws NotFoundHttpException When controller cannot be found */ - private function handleRaw(Request $request, $type = self::MASTER_REQUEST) + private function handleRaw(Request $request, int $type = self::MASTER_REQUEST) { $this->requestStack->push($request); @@ -148,7 +147,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface $arguments = $event->getArguments(); // call controller - $response = \call_user_func_array($controller, $arguments); + $response = $controller(...$arguments); // view if (!$response instanceof Response) { @@ -157,16 +156,15 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface if ($event->hasResponse()) { $response = $event->getResponse(); - } - - if (!$response instanceof Response) { - $msg = sprintf('The controller must return a response (%s given).', $this->varToString($response)); + } else { + $msg = sprintf('The controller must return a "Symfony\Component\HttpFoundation\Response" object but it returned %s.', $this->varToString($response)); // the user may have forgotten to return something if (null === $response) { $msg .= ' Did you forget to add a return statement somewhere in your controller?'; } - throw new \LogicException($msg); + + throw new ControllerDoesNotReturnResponseException($msg, $controller, __FILE__, __LINE__ - 17); } } @@ -184,7 +182,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface * * @throws \RuntimeException if the passed object is not a Response instance */ - private function filterResponse(Response $response, Request $request, $type) + private function filterResponse(Response $response, Request $request, int $type) { $event = new FilterResponseEvent($this, $request, $type, $response); @@ -201,11 +199,8 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface * Note that the order of the operations is important here, otherwise * operations such as {@link RequestStack::getParentRequest()} can lead to * weird results. - * - * @param Request $request - * @param int $type */ - private function finishRequest(Request $request, $type) + private function finishRequest(Request $request, int $type) { $this->dispatcher->dispatch(KernelEvents::FINISH_REQUEST, new FinishRequestEvent($this, $request, $type)); $this->requestStack->pop(); @@ -216,13 +211,11 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface * * @param \Exception $e An \Exception instance * @param Request $request A Request instance - * @param int $type The type of the request - * - * @return Response A Response instance + * @param int $type The type of the request (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST) * * @throws \Exception */ - private function handleException(\Exception $e, $request, $type) + private function handleException(\Exception $e, Request $request, int $type): Response { $event = new GetResponseForExceptionEvent($this, $request, $type, $e); $this->dispatcher->dispatch(KernelEvents::EXCEPTION, $event); @@ -239,13 +232,7 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface $response = $event->getResponse(); // the developer asked for a specific status code - if ($response->headers->has('X-Status-Code')) { - @trigger_error(sprintf('Using the X-Status-Code header is deprecated since Symfony 3.3 and will be removed in 4.0. Use %s::allowCustomResponseCode() instead.', GetResponseForExceptionEvent::class), E_USER_DEPRECATED); - - $response->setStatusCode($response->headers->get('X-Status-Code')); - - $response->headers->remove('X-Status-Code'); - } elseif (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) { + if (!$event->isAllowingCustomResponseCode() && !$response->isClientError() && !$response->isServerError() && !$response->isRedirect()) { // ensure that we actually have an error response if ($e instanceof HttpExceptionInterface) { // keep the HTTP status code and headers @@ -263,23 +250,23 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface } } - private function varToString($var) + private function varToString($var): string { if (\is_object($var)) { - return sprintf('Object(%s)', \get_class($var)); + return sprintf('an object of type %s', \get_class($var)); } if (\is_array($var)) { $a = array(); foreach ($var as $k => $v) { - $a[] = sprintf('%s => %s', $k, $this->varToString($v)); + $a[] = sprintf('%s => ...', $k); } - return sprintf('Array(%s)', implode(', ', $a)); + return sprintf('an array ([%s])', mb_substr(implode(', ', $a), 0, 255)); } if (\is_resource($var)) { - return sprintf('Resource(%s)', get_resource_type($var)); + return sprintf('a resource (%s)', get_resource_type($var)); } if (null === $var) { @@ -287,11 +274,19 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface } if (false === $var) { - return 'false'; + return 'a boolean value (false)'; } if (true === $var) { - return 'true'; + return 'a boolean value (true)'; + } + + if (\is_string($var)) { + return sprintf('a string ("%s%s")', mb_substr($var, 0, 255), mb_strlen($var) > 255 ? '...' : ''); + } + + if (is_numeric($var)) { + return sprintf('a number (%s)', (string) $var); } return (string) $var; diff --git a/vendor/symfony/http-kernel/Kernel.php b/vendor/symfony/http-kernel/Kernel.php index f0137c6842..225a047d14 100644 --- a/vendor/symfony/http-kernel/Kernel.php +++ b/vendor/symfony/http-kernel/Kernel.php @@ -13,10 +13,10 @@ namespace Symfony\Component\HttpKernel; use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator; use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper; -use Symfony\Component\ClassLoader\ClassCollectionLoader; use Symfony\Component\Config\ConfigCache; use Symfony\Component\Config\Loader\DelegatingLoader; use Symfony\Component\Config\Loader\LoaderResolver; +use Symfony\Component\Debug\DebugClassLoader; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\Compiler\PassConfig; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -33,7 +33,6 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; -use Symfony\Component\HttpKernel\Config\EnvParametersResource; use Symfony\Component\HttpKernel\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass; use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; @@ -43,6 +42,9 @@ use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfiguration * * It manages an environment made of bundles. * + * Environment names must always start with a letter and + * they must only contain letters and numbers. + * * @author Fabien Potencier <fabien@symfony.com> */ abstract class Kernel implements KernelInterface, RebootableInterface, TerminableInterface @@ -52,41 +54,41 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ protected $bundles = array(); - protected $bundleMap; protected $container; + /** + * @deprecated since Symfony 4.2 + */ protected $rootDir; protected $environment; protected $debug; protected $booted = false; + /** + * @deprecated since Symfony 4.2 + */ protected $name; protected $startTime; - protected $loadClassCache; private $projectDir; private $warmupDir; private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.18'; - const VERSION_ID = 30418; - const MAJOR_VERSION = 3; - const MINOR_VERSION = 4; - const RELEASE_VERSION = 18; + const VERSION = '4.2.0'; + const VERSION_ID = 40200; + const MAJOR_VERSION = 4; + const MINOR_VERSION = 2; + const RELEASE_VERSION = 0; const EXTRA_VERSION = ''; - const END_OF_MAINTENANCE = '11/2020'; - const END_OF_LIFE = '11/2021'; + const END_OF_MAINTENANCE = '07/2019'; + const END_OF_LIFE = '01/2020'; - /** - * @param string $environment The environment - * @param bool $debug Whether to enable debugging or not - */ - public function __construct($environment, $debug) + public function __construct(string $environment, bool $debug) { $this->environment = $environment; - $this->debug = (bool) $debug; - $this->rootDir = $this->getRootDir(); - $this->name = $this->getName(); + $this->debug = $debug; + $this->rootDir = $this->getRootDir(false); + $this->name = $this->getName(false); } public function __clone() @@ -124,10 +126,6 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl $_SERVER['SHELL_VERBOSITY'] = 3; } - if ($this->loadClassCache) { - $this->doLoadClassCache($this->loadClassCache[0], $this->loadClassCache[1]); - } - // init bundles $this->initializeBundles(); @@ -224,26 +222,16 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl /** * {@inheritdoc} */ - public function getBundle($name, $first = true/*, $noDeprecation = false */) + public function getBundle($name) { - $noDeprecation = false; - if (\func_num_args() >= 3) { - $noDeprecation = func_get_arg(2); - } - - if (!$first && !$noDeprecation) { - @trigger_error(sprintf('Passing "false" as the second argument to "%s()" is deprecated as of 3.4 and will be removed in 4.0.', __METHOD__), E_USER_DEPRECATED); - } + if (!isset($this->bundles[$name])) { + $class = \get_class($this); + $class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class; - if (!isset($this->bundleMap[$name])) { - throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the registerBundles() method of your %s.php file?', $name, \get_class($this))); + throw new \InvalidArgumentException(sprintf('Bundle "%s" does not exist or it is not enabled. Maybe you forgot to add it in the registerBundles() method of your %s.php file?', $name, $class)); } - if (true === $first) { - return $this->bundleMap[$name][0]; - } - - return $this->bundleMap[$name]; + return $this->bundles[$name]; } /** @@ -269,29 +257,18 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl $isResource = 0 === strpos($path, 'Resources') && null !== $dir; $overridePath = substr($path, 9); - $resourceBundle = null; - $bundles = $this->getBundle($bundleName, false, true); + $bundle = $this->getBundle($bundleName); $files = array(); - foreach ($bundles as $bundle) { - if ($isResource && file_exists($file = $dir.'/'.$bundle->getName().$overridePath)) { - if (null !== $resourceBundle) { - throw new \RuntimeException(sprintf('"%s" resource is hidden by a resource from the "%s" derived bundle. Create a "%s" file to override the bundle resource.', $file, $resourceBundle, $dir.'/'.$bundles[0]->getName().$overridePath)); - } - - if ($first) { - return $file; - } - $files[] = $file; - } + if ($isResource && file_exists($file = $dir.'/'.$bundle->getName().$overridePath)) { + $files[] = $file; + } - if (file_exists($file = $bundle->getPath().'/'.$path)) { - if ($first && !$isResource) { - return $file; - } - $files[] = $file; - $resourceBundle = $bundle->getName(); + if (file_exists($file = $bundle->getPath().'/'.$path)) { + if ($first && !$isResource) { + return $file; } + $files[] = $file; } if (\count($files) > 0) { @@ -303,9 +280,15 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl /** * {@inheritdoc} + * + * @deprecated since Symfony 4.2 */ - public function getName() + public function getName(/* $triggerDeprecation = true */) { + if (0 === \func_num_args() || func_get_arg(0)) { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED); + } + if (null === $this->name) { $this->name = preg_replace('/[^a-zA-Z0-9_]+/', '', basename($this->rootDir)); if (ctype_digit($this->name[0])) { @@ -334,9 +317,15 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl /** * {@inheritdoc} + * + * @deprecated since Symfony 4.2, use getProjectDir() instead */ - public function getRootDir() + public function getRootDir(/* $triggerDeprecation = true */) { + if (0 === \func_num_args() || func_get_arg(0)) { + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use getProjectDir() instead.', __METHOD__), E_USER_DEPRECATED); + } + if (null === $this->rootDir) { $r = new \ReflectionObject($this); $this->rootDir = \dirname($r->getFileName()); @@ -376,43 +365,6 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl } /** - * Loads the PHP class cache. - * - * This methods only registers the fact that you want to load the cache classes. - * The cache will actually only be loaded when the Kernel is booted. - * - * That optimization is mainly useful when using the HttpCache class in which - * case the class cache is not loaded if the Response is in the cache. - * - * @param string $name The cache name prefix - * @param string $extension File extension of the resulting file - * - * @deprecated since version 3.3, to be removed in 4.0. The class cache is not needed anymore when using PHP 7.0. - */ - public function loadClassCache($name = 'classes', $extension = '.php') - { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', E_USER_DEPRECATED); - } - - $this->loadClassCache = array($name, $extension); - } - - /** - * @internal - * - * @deprecated since version 3.3, to be removed in 4.0. - */ - public function setClassCache(array $classes) - { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', E_USER_DEPRECATED); - } - - file_put_contents(($this->warmupDir ?: $this->getCacheDir()).'/classes.map', sprintf('<?php return %s;', var_export($classes, true))); - } - - /** * @internal */ public function setAnnotatedClassCache(array $annotatedClasses) @@ -433,7 +385,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ public function getCacheDir() { - return $this->rootDir.'/cache/'.$this->environment; + return $this->getProjectDir().'/var/cache/'.$this->environment; } /** @@ -441,7 +393,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ public function getLogDir() { - return $this->rootDir.'/logs'; + return $this->getProjectDir().'/var/log'; } /** @@ -453,83 +405,28 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl } /** - * @deprecated since version 3.3, to be removed in 4.0. + * Gets the patterns defining the classes to parse and cache for annotations. */ - protected function doLoadClassCache($name, $extension) + public function getAnnotatedClassesToCompile(): array { - if (\PHP_VERSION_ID >= 70000) { - @trigger_error(__METHOD__.'() is deprecated since Symfony 3.3, to be removed in 4.0.', E_USER_DEPRECATED); - } - $cacheDir = $this->warmupDir ?: $this->getCacheDir(); - - if (!$this->booted && is_file($cacheDir.'/classes.map')) { - ClassCollectionLoader::load(include($cacheDir.'/classes.map'), $cacheDir, $name, $this->debug, false, $extension); - } + return array(); } /** - * Initializes the data structures related to the bundle management. - * - * - the bundles property maps a bundle name to the bundle instance, - * - the bundleMap property maps a bundle name to the bundle inheritance hierarchy (most derived bundle first). + * Initializes bundles. * * @throws \LogicException if two bundles share a common name - * @throws \LogicException if a bundle tries to extend a non-registered bundle - * @throws \LogicException if a bundle tries to extend itself - * @throws \LogicException if two bundles extend the same ancestor */ protected function initializeBundles() { // init bundles $this->bundles = array(); - $topMostBundles = array(); - $directChildren = array(); - foreach ($this->registerBundles() as $bundle) { $name = $bundle->getName(); if (isset($this->bundles[$name])) { throw new \LogicException(sprintf('Trying to register two bundles with the same name "%s"', $name)); } $this->bundles[$name] = $bundle; - - if ($parentName = $bundle->getParent()) { - @trigger_error('Bundle inheritance is deprecated as of 3.4 and will be removed in 4.0.', E_USER_DEPRECATED); - - if (isset($directChildren[$parentName])) { - throw new \LogicException(sprintf('Bundle "%s" is directly extended by two bundles "%s" and "%s".', $parentName, $name, $directChildren[$parentName])); - } - if ($parentName == $name) { - throw new \LogicException(sprintf('Bundle "%s" can not extend itself.', $name)); - } - $directChildren[$parentName] = $name; - } else { - $topMostBundles[$name] = $bundle; - } - } - - // look for orphans - if (!empty($directChildren) && \count($diff = array_diff_key($directChildren, $this->bundles))) { - $diff = array_keys($diff); - - throw new \LogicException(sprintf('Bundle "%s" extends bundle "%s", which is not registered.', $directChildren[$diff[0]], $diff[0])); - } - - // inheritance - $this->bundleMap = array(); - foreach ($topMostBundles as $name => $bundle) { - $bundleMap = array($bundle); - $hierarchy = array($name); - - while (isset($directChildren[$name])) { - $name = $directChildren[$name]; - array_unshift($bundleMap, $this->bundles[$name]); - $hierarchy[] = $name; - } - - foreach ($hierarchy as $hierarchyBundle) { - $this->bundleMap[$hierarchyBundle] = $bundleMap; - array_pop($bundleMap); - } } } @@ -549,7 +446,10 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ protected function getContainerClass() { - return $this->name.ucfirst($this->environment).($this->debug ? 'Debug' : '').'ProjectContainer'; + $class = \get_class($this); + $class = 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).ContainerBuilder::hash($class) : $class; + + return $this->name.str_replace('\\', '_', $class).ucfirst($this->environment).($this->debug ? 'Debug' : '').'Container'; } /** @@ -611,7 +511,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl return; } - $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3); + $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 5); // Clean the trace by removing first frames added by the error handler itself. for ($i = 0; isset($backtrace[$i]); ++$i) { if (isset($backtrace[$i]['file'], $backtrace[$i]['line']) && $backtrace[$i]['line'] === $line && $backtrace[$i]['file'] === $file) { @@ -619,13 +519,20 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl break; } } + // Remove frames added by DebugClassLoader. + for ($i = \count($backtrace) - 2; 0 < $i; --$i) { + if (DebugClassLoader::class === ($backtrace[$i]['class'] ?? null)) { + $backtrace = array($backtrace[$i + 1]); + break; + } + } $collectedLogs[$message] = array( 'type' => $type, 'message' => $message, 'file' => $file, 'line' => $line, - 'trace' => $backtrace, + 'trace' => array($backtrace[0]), 'count' => 1, ); }); @@ -694,57 +601,33 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl foreach ($this->bundles as $name => $bundle) { $bundles[$name] = \get_class($bundle); $bundlesMetadata[$name] = array( - 'parent' => $bundle->getParent(), 'path' => $bundle->getPath(), 'namespace' => $bundle->getNamespace(), ); } - return array_merge( - array( - 'kernel.root_dir' => realpath($this->rootDir) ?: $this->rootDir, - 'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(), - 'kernel.environment' => $this->environment, - 'kernel.debug' => $this->debug, - 'kernel.name' => $this->name, - 'kernel.cache_dir' => realpath($cacheDir = $this->warmupDir ?: $this->getCacheDir()) ?: $cacheDir, - 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(), - 'kernel.bundles' => $bundles, - 'kernel.bundles_metadata' => $bundlesMetadata, - 'kernel.charset' => $this->getCharset(), - 'kernel.container_class' => $this->getContainerClass(), - ), - $this->getEnvParameters(false) + return array( + /* + * @deprecated since Symfony 4.2, use kernel.project_dir instead + */ + 'kernel.root_dir' => realpath($this->rootDir) ?: $this->rootDir, + 'kernel.project_dir' => realpath($this->getProjectDir()) ?: $this->getProjectDir(), + 'kernel.environment' => $this->environment, + 'kernel.debug' => $this->debug, + /* + * @deprecated since Symfony 4.2 + */ + 'kernel.name' => $this->name, + 'kernel.cache_dir' => realpath($cacheDir = $this->warmupDir ?: $this->getCacheDir()) ?: $cacheDir, + 'kernel.logs_dir' => realpath($this->getLogDir()) ?: $this->getLogDir(), + 'kernel.bundles' => $bundles, + 'kernel.bundles_metadata' => $bundlesMetadata, + 'kernel.charset' => $this->getCharset(), + 'kernel.container_class' => $this->getContainerClass(), ); } /** - * Gets the environment parameters. - * - * Only the parameters starting with "SYMFONY__" are considered. - * - * @return array An array of parameters - * - * @deprecated since version 3.3, to be removed in 4.0 - */ - protected function getEnvParameters() - { - if (0 === \func_num_args() || func_get_arg(0)) { - @trigger_error(sprintf('The "%s()" method is deprecated as of 3.3 and will be removed in 4.0. Use the %%env()%% syntax to get the value of any environment variable from configuration files instead.', __METHOD__), E_USER_DEPRECATED); - } - - $parameters = array(); - foreach ($_SERVER as $key => $value) { - if (0 === strpos($key, 'SYMFONY__')) { - @trigger_error(sprintf('The support of special environment variables that start with SYMFONY__ (such as "%s") is deprecated as of 3.3 and will be removed in 4.0. Use the %%env()%% syntax instead to get the value of environment variables in configuration files.', $key), E_USER_DEPRECATED); - $parameters[strtolower(str_replace('__', '.', substr($key, 9)))] = $value; - } - } - - return $parameters; - } - - /** * Builds the service container. * * @return ContainerBuilder The compiled service container @@ -772,7 +655,6 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl } $container->addCompilerPass(new AddAnnotatedClassesToCachePass($this)); - $container->addResource(new EnvParametersResource('SYMFONY__')); return $container; } @@ -850,7 +732,6 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl 'file' => $cache->getPath(), 'as_files' => true, 'debug' => $this->debug, - 'inline_class_loader_parameter' => \PHP_VERSION_ID >= 70000 && !$this->loadClassCache && !class_exists(ClassCollectionLoader::class, false) ? 'container.dumper.inline_class_loader' : null, 'build_time' => $container->hasParameter('kernel.container_build_time') ? $container->getParameter('kernel.container_build_time') : time(), )); @@ -942,11 +823,9 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl $output .= $rawChunk; - if (\PHP_VERSION_ID >= 70000) { - // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098 - unset($tokens, $rawChunk); - gc_mem_caches(); - } + // 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; } @@ -958,11 +837,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl public function unserialize($data) { - if (\PHP_VERSION_ID >= 70000) { - list($environment, $debug) = unserialize($data, array('allowed_classes' => false)); - } else { - list($environment, $debug) = unserialize($data); - } + list($environment, $debug) = unserialize($data, array('allowed_classes' => false)); $this->__construct($environment, $debug); } diff --git a/vendor/symfony/http-kernel/KernelInterface.php b/vendor/symfony/http-kernel/KernelInterface.php index d624d1219d..93c4190b9b 100644 --- a/vendor/symfony/http-kernel/KernelInterface.php +++ b/vendor/symfony/http-kernel/KernelInterface.php @@ -18,9 +18,11 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface; /** * The Kernel is the heart of the Symfony system. * - * It manages an environment made of bundles. + * It manages an environment made of application kernel and bundles. * * @author Fabien Potencier <fabien@symfony.com> + * + * @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 { @@ -56,22 +58,18 @@ interface KernelInterface extends HttpKernelInterface, \Serializable public function getBundles(); /** - * Returns a bundle and optionally its descendants by its name. - * - * The second argument is deprecated as of 3.4 and will be removed in 4.0. This method - * will always return an instance of BundleInterface in 4.0. + * Returns a bundle. * - * @param string $name Bundle name - * @param bool $first Whether to return the first bundle only or together with its descendants + * @param string $name Bundle name * - * @return BundleInterface|BundleInterface[] A BundleInterface instance or an array of BundleInterface instances if $first is false + * @return BundleInterface A BundleInterface instance * * @throws \InvalidArgumentException when the bundle is not enabled */ - public function getBundle($name, $first = true); + public function getBundle($name); /** - * Returns the file path for a given resource. + * Returns the file path for a given bundle resource. * * A Resource can be a file or a directory. * @@ -104,6 +102,8 @@ interface KernelInterface extends HttpKernelInterface, \Serializable * Gets the name of the kernel. * * @return string The kernel name + * + * @deprecated since Symfony 4.2 */ public function getName(); @@ -125,6 +125,8 @@ interface KernelInterface extends HttpKernelInterface, \Serializable * Gets the application root dir (path of the project's Kernel class). * * @return string The Kernel root dir + * + * @deprecated since Symfony 4.2 */ public function getRootDir(); diff --git a/vendor/symfony/http-kernel/Log/DebugLoggerInterface.php b/vendor/symfony/http-kernel/Log/DebugLoggerInterface.php index f0606d3b0e..2a27992e20 100644 --- a/vendor/symfony/http-kernel/Log/DebugLoggerInterface.php +++ b/vendor/symfony/http-kernel/Log/DebugLoggerInterface.php @@ -11,12 +11,12 @@ namespace Symfony\Component\HttpKernel\Log; +use Symfony\Component\HttpFoundation\Request; + /** * DebugLoggerInterface. * * @author Fabien Potencier <fabien@symfony.com> - * - * @method clear() Removes all log records. */ interface DebugLoggerInterface { @@ -27,14 +27,23 @@ interface DebugLoggerInterface * timestamp, message, priority, and priorityName. * It can also have an optional context key containing an array. * + * @param Request|null $request The request to get logs for + * * @return array An array of logs */ - public function getLogs(); + public function getLogs(/* Request $request = null */); /** * Returns the number of errors. * + * @param Request|null $request The request to count logs for + * * @return int The number of errors */ - public function countErrors(); + public function countErrors(/* Request $request = null */); + + /** + * Removes all log records. + */ + public function clear(); } diff --git a/vendor/symfony/http-kernel/Log/Logger.php b/vendor/symfony/http-kernel/Log/Logger.php index ca54d22f75..8b671d84df 100644 --- a/vendor/symfony/http-kernel/Log/Logger.php +++ b/vendor/symfony/http-kernel/Log/Logger.php @@ -37,7 +37,7 @@ class Logger extends AbstractLogger private $formatter; private $handle; - public function __construct($minLevel = null, $output = 'php://stderr', callable $formatter = null) + public function __construct(string $minLevel = null, $output = 'php://stderr', callable $formatter = null) { if (null === $minLevel) { $minLevel = LogLevel::WARNING; @@ -80,14 +80,7 @@ class Logger extends AbstractLogger fwrite($this->handle, $formatter($level, $message, $context)); } - /** - * @param string $level - * @param string $message - * @param array $context - * - * @return string - */ - private function format($level, $message, array $context) + private function format(string $level, string $message, array $context): string { if (false !== strpos($message, '{')) { $replacements = array(); diff --git a/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php b/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php index 8bb57cf30c..955afed580 100644 --- a/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php +++ b/vendor/symfony/http-kernel/Profiler/FileProfilerStorage.php @@ -30,11 +30,9 @@ class FileProfilerStorage implements ProfilerStorageInterface * * Example : "file:/path/to/the/storage/folder" * - * @param string $dsn The DSN - * * @throws \RuntimeException */ - public function __construct($dsn) + public function __construct(string $dsn) { if (0 !== strpos($dsn, 'file:')) { throw new \RuntimeException(sprintf('Please check your configuration. You are trying to use FileStorage with an invalid dsn "%s". The expected format is "file:/path/to/the/storage/folder".', $dsn)); @@ -146,7 +144,7 @@ class FileProfilerStorage implements ProfilerStorageInterface // when there are errors in sub-requests, the parent and/or children tokens // may equal the profile token, resulting in infinite loops $parentToken = $profile->getParentToken() !== $profileToken ? $profile->getParentToken() : null; - $childrenToken = array_filter(array_map(function ($p) use ($profileToken) { + $childrenToken = array_filter(array_map(function (Profile $p) use ($profileToken) { return $profileToken !== $p->getToken() ? $p->getToken() : null; }, $profile->getChildren())); diff --git a/vendor/symfony/http-kernel/Profiler/Profile.php b/vendor/symfony/http-kernel/Profiler/Profile.php index 9216f09e2b..4716a229ea 100644 --- a/vendor/symfony/http-kernel/Profiler/Profile.php +++ b/vendor/symfony/http-kernel/Profiler/Profile.php @@ -43,10 +43,7 @@ class Profile */ private $children = array(); - /** - * @param string $token The token - */ - public function __construct($token) + public function __construct(string $token) { $this->token = $token; } @@ -74,7 +71,7 @@ class Profile /** * Sets the parent token. */ - public function setParent(Profile $parent) + public function setParent(self $parent) { $this->parent = $parent; } @@ -213,12 +210,23 @@ class Profile /** * Adds the child token. */ - public function addChild(Profile $child) + public function addChild(self $child) { $this->children[] = $child; $child->setParent($this); } + public function getChildByToken(string $token): ?self + { + foreach ($this->children as $child) { + if ($token === $child->getToken()) { + return $child; + } + } + + return null; + } + /** * Gets a Collector by name. * diff --git a/vendor/symfony/http-kernel/Profiler/Profiler.php b/vendor/symfony/http-kernel/Profiler/Profiler.php index f252da4766..809a3396b9 100644 --- a/vendor/symfony/http-kernel/Profiler/Profiler.php +++ b/vendor/symfony/http-kernel/Profiler/Profiler.php @@ -17,13 +17,14 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; +use Symfony\Contracts\Service\ResetInterface; /** * Profiler. * * @author Fabien Potencier <fabien@symfony.com> */ -class Profiler +class Profiler implements ResetInterface { private $storage; @@ -36,14 +37,11 @@ class Profiler private $initiallyEnabled = true; private $enabled = true; - /** - * @param bool $enable The initial enabled state - */ - public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null, $enable = true) + public function __construct(ProfilerStorageInterface $storage, LoggerInterface $logger = null, bool $enable = true) { $this->storage = $storage; $this->logger = $logger; - $this->initiallyEnabled = $this->enabled = (bool) $enable; + $this->initiallyEnabled = $this->enabled = $enable; } /** @@ -159,6 +157,10 @@ class Profiler $profile->setIp('Unknown'); } + if ($prevToken = $response->headers->get('X-Debug-Token')) { + $response->headers->set('X-Previous-Debug-Token', $prevToken); + } + $response->headers->set('X-Debug-Token', $profile->getToken()); foreach ($this->collectors as $collector) { @@ -174,10 +176,6 @@ class Profiler public function reset() { foreach ($this->collectors as $collector) { - if (!method_exists($collector, 'reset')) { - continue; - } - $collector->reset(); } $this->enabled = $this->initiallyEnabled; @@ -211,10 +209,6 @@ class Profiler */ public function add(DataCollectorInterface $collector) { - if (!method_exists($collector, 'reset')) { - @trigger_error(sprintf('Implementing "%s" without the "reset()" method is deprecated since Symfony 3.4 and will be unsupported in 4.0 for class "%s".', DataCollectorInterface::class, \get_class($collector)), E_USER_DEPRECATED); - } - $this->collectors[$collector->getName()] = $collector; } diff --git a/vendor/symfony/http-kernel/Profiler/ProfilerStorageInterface.php b/vendor/symfony/http-kernel/Profiler/ProfilerStorageInterface.php index 544fb1fef6..b78bae847f 100644 --- a/vendor/symfony/http-kernel/Profiler/ProfilerStorageInterface.php +++ b/vendor/symfony/http-kernel/Profiler/ProfilerStorageInterface.php @@ -14,6 +14,14 @@ namespace Symfony\Component\HttpKernel\Profiler; /** * ProfilerStorageInterface. * + * This interface exists for historical reasons. The only supported + * implementation is FileProfilerStorage. + * + * As the profiler must only be used on non-production servers, the file storage + * is more than enough and no other implementations will ever be supported. + * + * @internal since 4.2 + * * @author Fabien Potencier <fabien@symfony.com> */ interface ProfilerStorageInterface diff --git a/vendor/symfony/http-kernel/Tests/Bundle/BundleTest.php b/vendor/symfony/http-kernel/Tests/Bundle/BundleTest.php index 3408d7acd6..394e7ed7c6 100644 --- a/vendor/symfony/http-kernel/Tests/Bundle/BundleTest.php +++ b/vendor/symfony/http-kernel/Tests/Bundle/BundleTest.php @@ -12,11 +12,8 @@ namespace Symfony\Component\HttpKernel\Tests\Bundle; use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; -use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionAbsentBundle\ExtensionAbsentBundle; use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionNotValidBundle\ExtensionNotValidBundle; -use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\Command\FooCommand; use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\ExtensionPresentBundle; class BundleTest extends TestCase @@ -32,24 +29,6 @@ class BundleTest extends TestCase } /** - * @group legacy - * @expectedDeprecation Auto-registration of the command "Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\Command\FooCommand" is deprecated since Symfony 3.4 and won't be supported in 4.0. Use PSR-4 based service discovery instead. - */ - public function testRegisterCommands() - { - $cmd = new FooCommand(); - $app = $this->getMockBuilder('Symfony\Component\Console\Application')->getMock(); - $app->expects($this->once())->method('add')->with($this->equalTo($cmd)); - - $bundle = new ExtensionPresentBundle(); - $bundle->registerCommands($app); - - $bundle2 = new ExtensionAbsentBundle(); - - $this->assertNull($bundle2->registerCommands($app)); - } - - /** * @expectedException \LogicException * @expectedExceptionMessage must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface */ @@ -59,20 +38,6 @@ class BundleTest extends TestCase $bundle->getContainerExtension(); } - public function testHttpKernelRegisterCommandsIgnoresCommandsThatAreRegisteredAsServices() - { - $container = new ContainerBuilder(); - $container->register('console.command.symfony_component_httpkernel_tests_fixtures_extensionpresentbundle_command_foocommand', 'Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\Command\FooCommand'); - - $application = $this->getMockBuilder('Symfony\Component\Console\Application')->getMock(); - // add() is never called when the found command classes are already registered as services - $application->expects($this->never())->method('add'); - - $bundle = new ExtensionPresentBundle(); - $bundle->setContainer($container); - $bundle->registerCommands($application); - } - public function testBundleNameIsGuessedFromClass() { $bundle = new GuessedNameBundle(); diff --git a/vendor/symfony/http-kernel/Tests/CacheClearer/ChainCacheClearerTest.php b/vendor/symfony/http-kernel/Tests/CacheClearer/ChainCacheClearerTest.php index ec2ecff948..5f09e4b226 100644 --- a/vendor/symfony/http-kernel/Tests/CacheClearer/ChainCacheClearerTest.php +++ b/vendor/symfony/http-kernel/Tests/CacheClearer/ChainCacheClearerTest.php @@ -20,7 +20,7 @@ class ChainCacheClearerTest extends TestCase public static function setUpBeforeClass() { - self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf2_cache_clearer_dir'); + self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf_cache_clearer_dir'); } public static function tearDownAfterClass() @@ -39,21 +39,6 @@ class ChainCacheClearerTest extends TestCase $chainClearer->clear(self::$cacheDir); } - /** - * @group legacy - */ - public function testInjectClearerUsingAdd() - { - $clearer = $this->getMockClearer(); - $clearer - ->expects($this->once()) - ->method('clear'); - - $chainClearer = new ChainCacheClearer(); - $chainClearer->add($clearer); - $chainClearer->clear(self::$cacheDir); - } - protected function getMockClearer() { return $this->getMockBuilder('Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface')->getMock(); diff --git a/vendor/symfony/http-kernel/Tests/CacheClearer/Psr6CacheClearerTest.php b/vendor/symfony/http-kernel/Tests/CacheClearer/Psr6CacheClearerTest.php index b3bed4e87f..e1d2fe82e9 100644 --- a/vendor/symfony/http-kernel/Tests/CacheClearer/Psr6CacheClearerTest.php +++ b/vendor/symfony/http-kernel/Tests/CacheClearer/Psr6CacheClearerTest.php @@ -45,25 +45,4 @@ class Psr6CacheClearerTest extends TestCase { (new Psr6CacheClearer())->clearPool('unknown'); } - - /** - * @group legacy - * @expectedDeprecation The Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer::addPool() method is deprecated since Symfony 3.3 and will be removed in 4.0. Pass an array of pools indexed by name to the constructor instead. - */ - public function testClearPoolsInjectedByAdder() - { - $pool1 = $this->getMockBuilder(CacheItemPoolInterface::class)->getMock(); - $pool1 - ->expects($this->once()) - ->method('clear'); - - $pool2 = $this->getMockBuilder(CacheItemPoolInterface::class)->getMock(); - $pool2 - ->expects($this->once()) - ->method('clear'); - - $clearer = new Psr6CacheClearer(array('pool1' => $pool1)); - $clearer->addPool($pool2); - $clearer->clear(''); - } } diff --git a/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerAggregateTest.php b/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerAggregateTest.php index ba159124c9..09ba7020ff 100644 --- a/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerAggregateTest.php +++ b/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerAggregateTest.php @@ -20,7 +20,7 @@ class CacheWarmerAggregateTest extends TestCase public static function setUpBeforeClass() { - self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf2_cache_warmer_dir'); + self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf_cache_warmer_dir'); } public static function tearDownAfterClass() @@ -38,34 +38,6 @@ class CacheWarmerAggregateTest extends TestCase $aggregate->warmUp(self::$cacheDir); } - /** - * @group legacy - */ - public function testInjectWarmersUsingAdd() - { - $warmer = $this->getCacheWarmerMock(); - $warmer - ->expects($this->once()) - ->method('warmUp'); - $aggregate = new CacheWarmerAggregate(); - $aggregate->add($warmer); - $aggregate->warmUp(self::$cacheDir); - } - - /** - * @group legacy - */ - public function testInjectWarmersUsingSetWarmers() - { - $warmer = $this->getCacheWarmerMock(); - $warmer - ->expects($this->once()) - ->method('warmUp'); - $aggregate = new CacheWarmerAggregate(); - $aggregate->setWarmers(array($warmer)); - $aggregate->warmUp(self::$cacheDir); - } - public function testWarmupDoesCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsEnabled() { $warmer = $this->getCacheWarmerMock(); diff --git a/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerTest.php b/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerTest.php index 4d34e7bfc9..cee8b55034 100644 --- a/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerTest.php +++ b/vendor/symfony/http-kernel/Tests/CacheWarmer/CacheWarmerTest.php @@ -20,7 +20,7 @@ class CacheWarmerTest extends TestCase public static function setUpBeforeClass() { - self::$cacheFile = tempnam(sys_get_temp_dir(), 'sf2_cache_warmer_dir'); + self::$cacheFile = tempnam(sys_get_temp_dir(), 'sf_cache_warmer_dir'); } public static function tearDownAfterClass() diff --git a/vendor/symfony/http-kernel/Tests/ClientTest.php b/vendor/symfony/http-kernel/Tests/ClientTest.php index 5af2730868..4ce3670a30 100644 --- a/vendor/symfony/http-kernel/Tests/ClientTest.php +++ b/vendor/symfony/http-kernel/Tests/ClientTest.php @@ -61,13 +61,13 @@ class ClientTest extends TestCase $m->setAccessible(true); $response = new Response(); - $response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true)); + $response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true, false, null)); $domResponse = $m->invoke($client, $response); $this->assertSame((string) $cookie1, $domResponse->getHeader('Set-Cookie')); $response = new Response(); - $response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true)); - $response->headers->setCookie($cookie2 = new Cookie('foo1', 'bar1', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true)); + $response->headers->setCookie($cookie1 = new Cookie('foo', 'bar', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true, false, null)); + $response->headers->setCookie($cookie2 = new Cookie('foo1', 'bar1', \DateTime::createFromFormat('j-M-Y H:i:s T', '15-Feb-2009 20:00:00 GMT')->format('U'), '/foo', 'http://example.com', true, true, false, null)); $domResponse = $m->invoke($client, $response); $this->assertSame((string) $cookie1, $domResponse->getHeader('Set-Cookie')); $this->assertSame(array((string) $cookie1, (string) $cookie2), $domResponse->getHeader('Set-Cookie', false)); @@ -100,8 +100,8 @@ class ClientTest extends TestCase $client = new Client($kernel); $files = array( - array('tmp_name' => $source, 'name' => 'original', 'type' => 'mime/original', 'size' => 1, 'error' => UPLOAD_ERR_OK), - new UploadedFile($source, 'original', 'mime/original', 1, UPLOAD_ERR_OK, true), + array('tmp_name' => $source, 'name' => 'original', 'type' => 'mime/original', 'size' => null, 'error' => UPLOAD_ERR_OK), + new UploadedFile($source, 'original', 'mime/original', UPLOAD_ERR_OK, true), ); $file = null; @@ -116,8 +116,7 @@ class ClientTest extends TestCase $this->assertEquals('original', $file->getClientOriginalName()); $this->assertEquals('mime/original', $file->getClientMimeType()); - $this->assertSame(1, $file->getClientSize()); - $this->assertTrue($file->isValid()); + $this->assertEquals(1, $file->getSize()); } $file->move(\dirname($target), basename($target)); @@ -150,15 +149,19 @@ class ClientTest extends TestCase $file = $this ->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile') - ->setConstructorArgs(array($source, 'original', 'mime/original', 123, UPLOAD_ERR_OK, true)) - ->setMethods(array('getSize')) + ->setConstructorArgs(array($source, 'original', 'mime/original', UPLOAD_ERR_OK, true)) + ->setMethods(array('getSize', 'getClientSize')) ->getMock() ; - - $file->expects($this->once()) + /* should be modified when the getClientSize will be removed */ + $file->expects($this->any()) ->method('getSize') ->will($this->returnValue(INF)) ; + $file->expects($this->any()) + ->method('getClientSize') + ->will($this->returnValue(INF)) + ; $client->request('POST', '/', array(), array($file)); @@ -172,7 +175,7 @@ class ClientTest extends TestCase $this->assertEquals(UPLOAD_ERR_INI_SIZE, $file->getError()); $this->assertEquals('mime/original', $file->getClientMimeType()); $this->assertEquals('original', $file->getClientOriginalName()); - $this->assertEquals(0, $file->getClientSize()); + $this->assertEquals(0, $file->getSize()); unlink($source); } diff --git a/vendor/symfony/http-kernel/Tests/Config/EnvParametersResourceTest.php b/vendor/symfony/http-kernel/Tests/Config/EnvParametersResourceTest.php deleted file mode 100644 index 986e05d8b8..0000000000 --- a/vendor/symfony/http-kernel/Tests/Config/EnvParametersResourceTest.php +++ /dev/null @@ -1,110 +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\HttpKernel\Tests\Config; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpKernel\Config\EnvParametersResource; - -/** - * @group legacy - */ -class EnvParametersResourceTest extends TestCase -{ - protected $prefix = '__DUMMY_'; - protected $initialEnv; - protected $resource; - - protected function setUp() - { - $this->initialEnv = array( - $this->prefix.'1' => 'foo', - $this->prefix.'2' => 'bar', - ); - - foreach ($this->initialEnv as $key => $value) { - $_SERVER[$key] = $value; - } - - $this->resource = new EnvParametersResource($this->prefix); - } - - protected function tearDown() - { - foreach ($_SERVER as $key => $value) { - if (0 === strpos($key, $this->prefix)) { - unset($_SERVER[$key]); - } - } - } - - public function testGetResource() - { - $this->assertSame( - array('prefix' => $this->prefix, 'variables' => $this->initialEnv), - $this->resource->getResource(), - '->getResource() returns the resource' - ); - } - - public function testToString() - { - $this->assertSame( - serialize(array('prefix' => $this->prefix, 'variables' => $this->initialEnv)), - (string) $this->resource - ); - } - - public function testIsFreshNotChanged() - { - $this->assertTrue( - $this->resource->isFresh(time()), - '->isFresh() returns true if the variables have not changed' - ); - } - - public function testIsFreshValueChanged() - { - reset($this->initialEnv); - $_SERVER[key($this->initialEnv)] = 'baz'; - - $this->assertFalse( - $this->resource->isFresh(time()), - '->isFresh() returns false if a variable has been changed' - ); - } - - public function testIsFreshValueRemoved() - { - reset($this->initialEnv); - unset($_SERVER[key($this->initialEnv)]); - - $this->assertFalse( - $this->resource->isFresh(time()), - '->isFresh() returns false if a variable has been removed' - ); - } - - public function testIsFreshValueAdded() - { - $_SERVER[$this->prefix.'3'] = 'foo'; - - $this->assertFalse( - $this->resource->isFresh(time()), - '->isFresh() returns false if a variable has been added' - ); - } - - public function testSerializeUnserialize() - { - $this->assertEquals($this->resource, unserialize(serialize($this->resource))); - } -} diff --git a/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php index f6a3689638..0b38af9556 100644 --- a/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php +++ b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/ServiceValueResolverTest.php @@ -12,10 +12,12 @@ namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass; class ServiceValueResolverTest extends TestCase { @@ -103,6 +105,25 @@ class ServiceValueResolverTest extends TestCase $this->assertYieldEquals(array(new DummyService()), $resolver->resolve($request, $argument)); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage Cannot autowire argument $dummy of "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyController::index()": it references class "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyService" but no such service exists. + */ + public function testErrorIsTruncated() + { + $container = new ContainerBuilder(); + $container->addCompilerPass(new RegisterControllerArgumentLocatorsPass()); + + $container->register('argument_resolver.service', ServiceValueResolver::class)->addArgument(null)->setPublic(true); + $container->register(DummyController::class)->addTag('controller.service_arguments')->setPublic(true); + + $container->compile(); + + $request = $this->requestWithAttributes(array('_controller' => array(DummyController::class, 'index'))); + $argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null); + $container->get('argument_resolver.service')->resolve($request, $argument)->current(); + } + private function requestWithAttributes(array $attributes) { $request = Request::create('/'); @@ -128,3 +149,10 @@ class ServiceValueResolverTest extends TestCase class DummyService { } + +class DummyController +{ + public function index(DummyService $dummy) + { + } +} diff --git a/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/TraceableValueResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/TraceableValueResolverTest.php new file mode 100644 index 0000000000..3c2cc3f700 --- /dev/null +++ b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolver/TraceableValueResolverTest.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\Tests\Controller\ArgumentResolver; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver; +use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; +use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; +use Symfony\Component\Stopwatch\Stopwatch; + +class TraceableValueResolverTest extends TestCase +{ + public function testTimingsInSupports() + { + $stopwatch = new Stopwatch(); + $resolver = new TraceableValueResolver(new ResolverStub(), $stopwatch); + $argument = new ArgumentMetadata('dummy', 'string', false, false, null); + $request = new Request(); + + $this->assertTrue($resolver->supports($request, $argument)); + + $event = $stopwatch->getEvent(ResolverStub::class.'::supports'); + $this->assertCount(1, $event->getPeriods()); + } + + public function testTimingsInResolve() + { + $stopwatch = new Stopwatch(); + $resolver = new TraceableValueResolver(new ResolverStub(), $stopwatch); + $argument = new ArgumentMetadata('dummy', 'string', false, false, null); + $request = new Request(); + + $iterable = $resolver->resolve($request, $argument); + + foreach ($iterable as $index => $resolved) { + $event = $stopwatch->getEvent(ResolverStub::class.'::resolve'); + $this->assertTrue($event->isStarted()); + $this->assertEmpty($event->getPeriods()); + switch ($index) { + case 0: + $this->assertEquals('first', $resolved); + break; + case 1: + $this->assertEquals('second', $resolved); + break; + } + } + + $event = $stopwatch->getEvent(ResolverStub::class.'::resolve'); + $this->assertCount(1, $event->getPeriods()); + } +} + +class ResolverStub implements ArgumentValueResolverInterface +{ + public function supports(Request $request, ArgumentMetadata $argument) + { + return true; + } + + public function resolve(Request $request, ArgumentMetadata $argument) + { + yield 'first'; + yield 'second'; + } +} diff --git a/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolverTest.php index 729b90b2f6..bb4e06617e 100644 --- a/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolverTest.php +++ b/vendor/symfony/http-kernel/Tests/Controller/ArgumentResolverTest.php @@ -152,9 +152,6 @@ class ArgumentResolverTest extends TestCase $this->assertEquals(array($request), self::$resolver->getArguments($request, $controller), '->getArguments() injects the request when extended'); } - /** - * @requires PHP 5.6 - */ public function testGetVariadicArguments() { $request = Request::create('/'); @@ -166,7 +163,6 @@ class ArgumentResolverTest extends TestCase } /** - * @requires PHP 5.6 * @expectedException \InvalidArgumentException */ public function testGetVariadicArgumentsWithoutArrayInRequest() @@ -180,7 +176,6 @@ class ArgumentResolverTest extends TestCase } /** - * @requires PHP 5.6 * @expectedException \InvalidArgumentException */ public function testGetArgumentWithoutArray() @@ -210,9 +205,6 @@ class ArgumentResolverTest extends TestCase self::$resolver->getArguments($request, $controller); } - /** - * @requires PHP 7.1 - */ public function testGetNullableArguments() { $request = Request::create('/'); @@ -224,9 +216,6 @@ class ArgumentResolverTest extends TestCase $this->assertEquals(array('foo', new \stdClass(), 'value', 'mandatory'), self::$resolver->getArguments($request, $controller)); } - /** - * @requires PHP 7.1 - */ public function testGetNullableArgumentsWithDefaults() { $request = Request::create('/'); diff --git a/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php index 82407f5601..1a144eee49 100644 --- a/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php +++ b/vendor/symfony/http-kernel/Tests/Controller/ContainerControllerResolverTest.php @@ -13,15 +13,16 @@ namespace Symfony\Component\HttpKernel\Tests\Controller; use Psr\Container\ContainerInterface; use Psr\Log\LoggerInterface; -use Symfony\Component\Debug\ErrorHandler; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver; class ContainerControllerResolverTest extends ControllerResolverTest { - public function testGetControllerService() + public function testGetControllerServiceWithSingleColon() { + $service = new ControllerTestService('foo'); + $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') @@ -30,163 +31,132 @@ class ContainerControllerResolverTest extends ControllerResolverTest $container->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue($this)) + ->will($this->returnValue($service)) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); - $request->attributes->set('_controller', 'foo:controllerMethod1'); + $request->attributes->set('_controller', 'foo:action'); $controller = $resolver->getController($request); - $this->assertInstanceOf(\get_class($this), $controller[0]); - $this->assertSame('controllerMethod1', $controller[1]); + $this->assertSame($service, $controller[0]); + $this->assertSame('action', $controller[1]); } - public function testGetControllerInvokableService() + public function testGetControllerService() { - $invokableController = new InvokableController('bar'); + $service = new ControllerTestService('foo'); $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') ->with('foo') - ->will($this->returnValue(true)) - ; + ->will($this->returnValue(true)); $container->expects($this->once()) ->method('get') ->with('foo') - ->will($this->returnValue($invokableController)) + ->will($this->returnValue($service)) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); - $request->attributes->set('_controller', 'foo'); + $request->attributes->set('_controller', 'foo::action'); $controller = $resolver->getController($request); - $this->assertEquals($invokableController, $controller); + $this->assertSame($service, $controller[0]); + $this->assertSame('action', $controller[1]); } - public function testGetControllerInvokableServiceWithClassNameAsName() + public function testGetControllerInvokableService() { - $invokableController = new InvokableController('bar'); - $className = __NAMESPACE__.'\InvokableController'; + $service = new InvokableControllerService('bar'); $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') - ->with($className) + ->with('foo') ->will($this->returnValue(true)) ; $container->expects($this->once()) ->method('get') - ->with($className) - ->will($this->returnValue($invokableController)) + ->with('foo') + ->will($this->returnValue($service)) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); - $request->attributes->set('_controller', $className); + $request->attributes->set('_controller', 'foo'); $controller = $resolver->getController($request); - $this->assertEquals($invokableController, $controller); + $this->assertSame($service, $controller); } - public function testNonInstantiableController() + public function testGetControllerInvokableServiceWithClassNameAsName() { + $service = new InvokableControllerService('bar'); + $container = $this->createMockContainer(); $container->expects($this->once()) ->method('has') - ->with(NonInstantiableController::class) - ->will($this->returnValue(false)) + ->with(InvokableControllerService::class) + ->will($this->returnValue(true)) + ; + $container->expects($this->once()) + ->method('get') + ->with(InvokableControllerService::class) + ->will($this->returnValue($service)) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); - $request->attributes->set('_controller', array(NonInstantiableController::class, 'action')); + $request->attributes->set('_controller', InvokableControllerService::class); $controller = $resolver->getController($request); - $this->assertSame(array(NonInstantiableController::class, 'action'), $controller); + $this->assertSame($service, $controller); } /** - * @expectedException \LogicException - * @expectedExceptionMessage Controller "Symfony\Component\HttpKernel\Tests\Controller\ImpossibleConstructController" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"? + * Tests where the fallback instantiation fails due to required constructor arguments. + * + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"? */ - public function testNonConstructController() + public function testExceptionWhenUsingRemovedControllerServiceWithClassNameAsName() { $container = $this->getMockBuilder(Container::class)->getMock(); - $container->expects($this->at(0)) - ->method('has') - ->with(ImpossibleConstructController::class) - ->will($this->returnValue(true)) - ; - - $container->expects($this->at(1)) + $container->expects($this->once()) ->method('has') - ->with(ImpossibleConstructController::class) + ->with(ControllerTestService::class) ->will($this->returnValue(false)) ; $container->expects($this->atLeastOnce()) ->method('getRemovedIds') ->with() - ->will($this->returnValue(array(ImpossibleConstructController::class => true))) + ->will($this->returnValue(array(ControllerTestService::class => true))) ; $resolver = $this->createControllerResolver(null, $container); $request = Request::create('/'); - $request->attributes->set('_controller', array(ImpossibleConstructController::class, 'action')); - - if (\PHP_VERSION_ID < 70100) { - ErrorHandler::register(); - try { - $resolver->getController($request); - } finally { - restore_error_handler(); - restore_exception_handler(); - } - } else { - $resolver->getController($request); - } - } - - public function testNonInstantiableControllerWithCorrespondingService() - { - $service = new \stdClass(); + $request->attributes->set('_controller', array(ControllerTestService::class, 'action')); - $container = $this->createMockContainer(); - $container->expects($this->atLeastOnce()) - ->method('has') - ->with(NonInstantiableController::class) - ->will($this->returnValue(true)) - ; - $container->expects($this->atLeastOnce()) - ->method('get') - ->with(NonInstantiableController::class) - ->will($this->returnValue($service)) - ; - - $resolver = $this->createControllerResolver(null, $container); - $request = Request::create('/'); - $request->attributes->set('_controller', array(NonInstantiableController::class, 'action')); - - $controller = $resolver->getController($request); - - $this->assertSame(array($service, 'action'), $controller); + $resolver->getController($request); } /** - * @expectedException \LogicException + * Tests where the fallback instantiation fails due to non-existing class. + * + * @expectedException \InvalidArgumentException * @expectedExceptionMessage Controller "app.my_controller" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"? */ public function testExceptionWhenUsingRemovedControllerService() { $container = $this->getMockBuilder(Container::class)->getMock(); - $container->expects($this->at(0)) + $container->expects($this->once()) ->method('has') ->with('app.my_controller') ->will($this->returnValue(false)) @@ -205,62 +175,28 @@ class ContainerControllerResolverTest extends ControllerResolverTest $resolver->getController($request); } - /** - * @expectedException \LogicException - * @expectedExceptionMessage Controller "app.my_controller" cannot be called without a method name. Did you forget an "__invoke" method? - */ - public function testExceptionWhenUsingControllerWithoutAnInvokeMethod() - { - $container = $this->getMockBuilder(Container::class)->getMock(); - $container->expects($this->once()) - ->method('has') - ->with('app.my_controller') - ->will($this->returnValue(true)) - ; - $container->expects($this->once()) - ->method('get') - ->with('app.my_controller') - ->will($this->returnValue(new ImpossibleConstructController('toto', 'controller'))) - ; - - $resolver = $this->createControllerResolver(null, $container); - - $request = Request::create('/'); - $request->attributes->set('_controller', 'app.my_controller'); - $resolver->getController($request); - } - - /** - * @dataProvider getUndefinedControllers - */ - public function testGetControllerOnNonUndefinedFunction($controller, $exceptionName = null, $exceptionMessage = null) - { - // All this logic needs to be duplicated, since calling parent::testGetControllerOnNonUndefinedFunction will override the expected excetion and not use the regex - $resolver = $this->createControllerResolver(); - if (method_exists($this, 'expectException')) { - $this->expectException($exceptionName); - $this->expectExceptionMessageRegExp($exceptionMessage); - } else { - $this->setExpectedExceptionRegExp($exceptionName, $exceptionMessage); - } - - $request = Request::create('/'); - $request->attributes->set('_controller', $controller); - $resolver->getController($request); - } - public function getUndefinedControllers() { - return array( - array('foo', \LogicException::class, '/Controller not found: service "foo" does not exist\./'), - array('oof::bar', \InvalidArgumentException::class, '/Class "oof" does not exist\./'), - array('stdClass', \LogicException::class, '/Controller not found: service "stdClass" does not exist\./'), - array( - 'Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest::bar', - \InvalidArgumentException::class, - '/.?[cC]ontroller(.*?) for URI "\/" is not callable\.( Expected method(.*) Available methods)?/', - ), + $tests = parent::getUndefinedControllers(); + $tests[0] = array('foo', \InvalidArgumentException::class, 'Controller "foo" does neither exist as service nor as class'); + $tests[1] = array('oof::bar', \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class'); + $tests[2] = array(array('oof', 'bar'), \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class'); + $tests[] = array( + array(ControllerTestService::class, 'action'), + \InvalidArgumentException::class, + 'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" has required constructor arguments and does not exist in the container. Did you forget to define such a service?', ); + $tests[] = array( + ControllerTestService::class.'::action', + \InvalidArgumentException::class, 'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" has required constructor arguments and does not exist in the container. Did you forget to define such a service?', + ); + $tests[] = array( + InvokableControllerService::class, + \InvalidArgumentException::class, + 'Controller "Symfony\Component\HttpKernel\Tests\Controller\InvokableControllerService" has required constructor arguments and does not exist in the container. Did you forget to define such a service?', + ); + + return $tests; } protected function createControllerResolver(LoggerInterface $logger = null, ContainerInterface $container = null) @@ -278,7 +214,7 @@ class ContainerControllerResolverTest extends ControllerResolverTest } } -class InvokableController +class InvokableControllerService { public function __construct($bar) // mandatory argument to prevent automatic instantiation { @@ -289,16 +225,9 @@ class InvokableController } } -abstract class NonInstantiableController -{ - public static function action() - { - } -} - -class ImpossibleConstructController +class ControllerTestService { - public function __construct($toto, $controller) + public function __construct($foo) { } diff --git a/vendor/symfony/http-kernel/Tests/Controller/ControllerResolverTest.php b/vendor/symfony/http-kernel/Tests/Controller/ControllerResolverTest.php index 87f598d16d..fe624f7b60 100644 --- a/vendor/symfony/http-kernel/Tests/Controller/ControllerResolverTest.php +++ b/vendor/symfony/http-kernel/Tests/Controller/ControllerResolverTest.php @@ -15,8 +15,6 @@ use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerResolver; -use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\NullableController; -use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\VariadicController; class ControllerResolverTest extends TestCase { @@ -43,51 +41,55 @@ class ControllerResolverTest extends TestCase public function testGetControllerWithObjectAndInvokeMethod() { $resolver = $this->createControllerResolver(); + $object = new InvokableController(); $request = Request::create('/'); - $request->attributes->set('_controller', $this); + $request->attributes->set('_controller', $object); $controller = $resolver->getController($request); - $this->assertSame($this, $controller); + $this->assertSame($object, $controller); } public function testGetControllerWithObjectAndMethod() { $resolver = $this->createControllerResolver(); + $object = new ControllerTest(); $request = Request::create('/'); - $request->attributes->set('_controller', array($this, 'controllerMethod1')); + $request->attributes->set('_controller', array($object, 'publicAction')); $controller = $resolver->getController($request); - $this->assertSame(array($this, 'controllerMethod1'), $controller); + $this->assertSame(array($object, 'publicAction'), $controller); } - public function testGetControllerWithClassAndMethod() + public function testGetControllerWithClassAndMethodAsArray() { $resolver = $this->createControllerResolver(); $request = Request::create('/'); - $request->attributes->set('_controller', array('Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest', 'controllerMethod4')); + $request->attributes->set('_controller', array(ControllerTest::class, 'publicAction')); $controller = $resolver->getController($request); - $this->assertSame(array('Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest', 'controllerMethod4'), $controller); + $this->assertInstanceOf(ControllerTest::class, $controller[0]); + $this->assertSame('publicAction', $controller[1]); } - public function testGetControllerWithObjectAndMethodAsString() + public function testGetControllerWithClassAndMethodAsString() { $resolver = $this->createControllerResolver(); $request = Request::create('/'); - $request->attributes->set('_controller', 'Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest::controllerMethod1'); + $request->attributes->set('_controller', ControllerTest::class.'::publicAction'); $controller = $resolver->getController($request); - $this->assertInstanceOf('Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest', $controller[0], '->getController() returns a PHP callable'); + $this->assertInstanceOf(ControllerTest::class, $controller[0]); + $this->assertSame('publicAction', $controller[1]); } - public function testGetControllerWithClassAndInvokeMethod() + public function testGetControllerWithInvokableClass() { $resolver = $this->createControllerResolver(); $request = Request::create('/'); - $request->attributes->set('_controller', 'Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest'); + $request->attributes->set('_controller', InvokableController::class); $controller = $resolver->getController($request); - $this->assertInstanceOf('Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest', $controller); + $this->assertInstanceOf(InvokableController::class, $controller); } /** @@ -112,220 +114,146 @@ class ControllerResolverTest extends TestCase $this->assertSame('Symfony\Component\HttpKernel\Tests\Controller\some_controller_function', $controller); } - /** - * @dataProvider getUndefinedControllers - */ - public function testGetControllerOnNonUndefinedFunction($controller, $exceptionName = null, $exceptionMessage = null) - { - $resolver = $this->createControllerResolver(); - if (method_exists($this, 'expectException')) { - $this->expectException($exceptionName); - $this->expectExceptionMessage($exceptionMessage); - } else { - $this->setExpectedException($exceptionName, $exceptionMessage); - } - - $request = Request::create('/'); - $request->attributes->set('_controller', $controller); - $resolver->getController($request); - } - - public function getUndefinedControllers() - { - return array( - array(1, 'InvalidArgumentException', 'Unable to find controller "1".'), - array('foo', 'InvalidArgumentException', 'Unable to find controller "foo".'), - array('oof::bar', 'InvalidArgumentException', 'Class "oof" does not exist.'), - array('stdClass', 'InvalidArgumentException', 'Unable to find controller "stdClass".'), - array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::staticsAction', 'InvalidArgumentException', 'The controller for URI "/" is not callable. Expected method "staticsAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest", did you mean "staticAction"?'), - array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::privateAction', 'InvalidArgumentException', 'The controller for URI "/" is not callable. Method "privateAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'), - array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::protectedAction', 'InvalidArgumentException', 'The controller for URI "/" is not callable. Method "protectedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'), - array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::undefinedAction', 'InvalidArgumentException', 'The controller for URI "/" is not callable. Expected method "undefinedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest". Available methods: "publicAction", "staticAction"'), - ); - } - - /** - * @group legacy - */ - public function testGetArguments() + public function testGetControllerWithClosure() { $resolver = $this->createControllerResolver(); - $request = Request::create('/'); - $controller = array(new self(), 'testGetArguments'); - $this->assertEquals(array(), $resolver->getArguments($request, $controller), '->getArguments() returns an empty array if the method takes no arguments'); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $controller = array(new self(), 'controllerMethod1'); - $this->assertEquals(array('foo'), $resolver->getArguments($request, $controller), '->getArguments() returns an array of arguments for the controller method'); + $closure = function () { + return 'test'; + }; $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $controller = array(new self(), 'controllerMethod2'); - $this->assertEquals(array('foo', null), $resolver->getArguments($request, $controller), '->getArguments() uses default values if present'); - - $request->attributes->set('bar', 'bar'); - $this->assertEquals(array('foo', 'bar'), $resolver->getArguments($request, $controller), '->getArguments() overrides default values if provided in the request attributes'); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $controller = function ($foo) {}; - $this->assertEquals(array('foo'), $resolver->getArguments($request, $controller)); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $controller = function ($foo, $bar = 'bar') {}; - $this->assertEquals(array('foo', 'bar'), $resolver->getArguments($request, $controller)); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $controller = new self(); - $this->assertEquals(array('foo', null), $resolver->getArguments($request, $controller)); - $request->attributes->set('bar', 'bar'); - $this->assertEquals(array('foo', 'bar'), $resolver->getArguments($request, $controller)); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $request->attributes->set('foobar', 'foobar'); - $controller = 'Symfony\Component\HttpKernel\Tests\Controller\some_controller_function'; - $this->assertEquals(array('foo', 'foobar'), $resolver->getArguments($request, $controller)); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $request->attributes->set('foobar', 'foobar'); - $controller = array(new self(), 'controllerMethod3'); - - try { - $resolver->getArguments($request, $controller); - $this->fail('->getArguments() throws a \RuntimeException exception if it cannot determine the argument value'); - } catch (\Exception $e) { - $this->assertInstanceOf('\RuntimeException', $e, '->getArguments() throws a \RuntimeException exception if it cannot determine the argument value'); - } - - $request = Request::create('/'); - $controller = array(new self(), 'controllerMethod5'); - $this->assertEquals(array($request), $resolver->getArguments($request, $controller), '->getArguments() injects the request'); + $request->attributes->set('_controller', $closure); + $controller = $resolver->getController($request); + $this->assertInstanceOf(\Closure::class, $controller); + $this->assertSame('test', $controller()); } /** - * @requires PHP 5.6 - * @group legacy + * @dataProvider getStaticControllers */ - public function testGetVariadicArguments() + public function testGetControllerWithStaticController($staticController, $returnValue) { - $resolver = new ControllerResolver(); - - $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $request->attributes->set('bar', array('foo', 'bar')); - $controller = array(new VariadicController(), 'action'); - $this->assertEquals(array('foo', 'foo', 'bar'), $resolver->getArguments($request, $controller)); - } - - public function testCreateControllerCanReturnAnyCallable() - { - $mock = $this->getMockBuilder('Symfony\Component\HttpKernel\Controller\ControllerResolver')->setMethods(array('createController'))->getMock(); - $mock->expects($this->once())->method('createController')->will($this->returnValue('Symfony\Component\HttpKernel\Tests\Controller\some_controller_function')); + $resolver = $this->createControllerResolver(); $request = Request::create('/'); - $request->attributes->set('_controller', 'foobar'); - $mock->getController($request); + $request->attributes->set('_controller', $staticController); + $controller = $resolver->getController($request); + $this->assertSame($staticController, $controller); + $this->assertSame($returnValue, $controller()); } - /** - * @expectedException \RuntimeException - * @group legacy - */ - public function testIfExceptionIsThrownWhenMissingAnArgument() + public function getStaticControllers() { - $resolver = new ControllerResolver(); - $request = Request::create('/'); - - $controller = array($this, 'controllerMethod1'); - - $resolver->getArguments($request, $controller); + return array( + array(TestAbstractController::class.'::staticAction', 'foo'), + array(array(TestAbstractController::class, 'staticAction'), 'foo'), + array(PrivateConstructorController::class.'::staticAction', 'bar'), + array(array(PrivateConstructorController::class, 'staticAction'), 'bar'), + ); } /** - * @requires PHP 7.1 - * @group legacy + * @dataProvider getUndefinedControllers */ - public function testGetNullableArguments() + public function testGetControllerWithUndefinedController($controller, $exceptionName = null, $exceptionMessage = null) { - $resolver = new ControllerResolver(); + $resolver = $this->createControllerResolver(); + if (method_exists($this, 'expectException')) { + $this->expectException($exceptionName); + $this->expectExceptionMessage($exceptionMessage); + } else { + $this->setExpectedException($exceptionName, $exceptionMessage); + } $request = Request::create('/'); - $request->attributes->set('foo', 'foo'); - $request->attributes->set('bar', new \stdClass()); - $request->attributes->set('mandatory', 'mandatory'); - $controller = array(new NullableController(), 'action'); - $this->assertEquals(array('foo', new \stdClass(), 'value', 'mandatory'), $resolver->getArguments($request, $controller)); + $request->attributes->set('_controller', $controller); + $resolver->getController($request); } - /** - * @requires PHP 7.1 - * @group legacy - */ - public function testGetNullableArgumentsWithDefaults() + public function getUndefinedControllers() { - $resolver = new ControllerResolver(); + $controller = new ControllerTest(); - $request = Request::create('/'); - $request->attributes->set('mandatory', 'mandatory'); - $controller = array(new NullableController(), 'action'); - $this->assertEquals(array(null, null, 'value', 'mandatory'), $resolver->getArguments($request, $controller)); + return array( + array('foo', \Error::class, 'Class \'foo\' not found'), + array('oof::bar', \Error::class, 'Class \'oof\' not found'), + array(array('oof', 'bar'), \Error::class, 'Class \'oof\' not found'), + array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::staticsAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "staticsAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest", did you mean "staticAction"?'), + array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::privateAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "privateAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'), + array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::protectedAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "protectedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'), + array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::undefinedAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "undefinedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest". Available methods: "publicAction", "staticAction"'), + array('Symfony\Component\HttpKernel\Tests\Controller\ControllerTest', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Controller class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" cannot be called without a method name. You need to implement "__invoke" or use one of the available methods: "publicAction", "staticAction".'), + array(array($controller, 'staticsAction'), \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "staticsAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest", did you mean "staticAction"?'), + array(array($controller, 'privateAction'), \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "privateAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'), + array(array($controller, 'protectedAction'), \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "protectedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'), + array(array($controller, 'undefinedAction'), \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "undefinedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest". Available methods: "publicAction", "staticAction"'), + array($controller, \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Controller class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" cannot be called without a method name. You need to implement "__invoke" or use one of the available methods: "publicAction", "staticAction".'), + array(array('a' => 'foo', 'b' => 'bar'), \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Invalid array callable, expected array(controller, method).'), + ); } protected function createControllerResolver(LoggerInterface $logger = null) { return new ControllerResolver($logger); } +} - public function __invoke($foo, $bar = null) +function some_controller_function($foo, $foobar) +{ +} + +class ControllerTest +{ + public function __construct() { } - public function controllerMethod1($foo) + public function __toString() { + return ''; } - protected function controllerMethod2($foo, $bar = null) + public function publicAction() { } - protected function controllerMethod3($foo, $bar, $foobar) + private function privateAction() { } - protected static function controllerMethod4() + protected function protectedAction() { } - protected function controllerMethod5(Request $request) + public static function staticAction() { } } -function some_controller_function($foo, $foobar) +class InvokableController { -} - -class ControllerTest -{ - public function publicAction() + public function __invoke($foo, $bar = null) { } +} - private function privateAction() +abstract class TestAbstractController +{ + public static function staticAction() { + return 'foo'; } +} - protected function protectedAction() +class PrivateConstructorController +{ + private function __construct() { } public static function staticAction() { + return 'bar'; } } diff --git a/vendor/symfony/http-kernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php b/vendor/symfony/http-kernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php index bf0db5ad56..a667705f50 100644 --- a/vendor/symfony/http-kernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php +++ b/vendor/symfony/http-kernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php @@ -84,9 +84,6 @@ class ArgumentMetadataFactoryTest extends TestCase ), $arguments); } - /** - * @requires PHP 5.6 - */ public function testVariadicSignature() { $arguments = $this->factory->createArgumentMetadata(array(new VariadicController(), 'action')); @@ -97,9 +94,6 @@ class ArgumentMetadataFactoryTest extends TestCase ), $arguments); } - /** - * @requires PHP 7.0 - */ public function testBasicTypesSignature() { $arguments = $this->factory->createArgumentMetadata(array(new BasicTypesController(), 'action')); @@ -111,9 +105,6 @@ class ArgumentMetadataFactoryTest extends TestCase ), $arguments); } - /** - * @requires PHP 7.1 - */ public function testNullableTypesSignature() { $arguments = $this->factory->createArgumentMetadata(array(new NullableController(), 'action')); diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php index 3f51b13ce9..10b0585840 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/ConfigDataCollectorTest.php @@ -30,7 +30,6 @@ class ConfigDataCollectorTest extends TestCase $this->assertSame('test', $c->getEnv()); $this->assertTrue($c->isDebug()); $this->assertSame('config', $c->getName()); - $this->assertSame('testkernel', $c->getAppName()); $this->assertRegExp('~^'.preg_quote($c->getPhpVersion(), '~').'~', PHP_VERSION); $this->assertRegExp('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', PHP_VERSION); $this->assertSame(PHP_INT_SIZE * 8, $c->getPhpArchitecture()); @@ -42,15 +41,26 @@ class ConfigDataCollectorTest extends TestCase $this->assertSame(\extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN), $c->hasZendOpcache()); $this->assertSame(\extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN), $c->hasApcu()); } -} -class KernelForTest extends Kernel -{ - public function getName() + /** + * @group legacy + * @expectedDeprecation The "$name" argument in method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::__construct()" is deprecated since Symfony 4.2. + * @expectedDeprecation The "$version" argument in method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::__construct()" is deprecated since Symfony 4.2. + * @expectedDeprecation The method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::getApplicationName()" is deprecated since Symfony 4.2. + * @expectedDeprecation The method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::getApplicationVersion()" is deprecated since Symfony 4.2. + */ + public function testLegacy() { - return 'testkernel'; + $c = new ConfigDataCollector('name', null); + $c->collect(new Request(), new Response()); + + $this->assertSame('name', $c->getApplicationName()); + $this->assertNull($c->getApplicationVersion()); } +} +class KernelForTest extends Kernel +{ public function registerBundles() { } diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php index fd5ea11e72..57384a79ff 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/DumpDataCollectorTest.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\CliDumper; +use Symfony\Component\VarDumper\Server\Connection; /** * @author Nicolas Grekas <p@tchwork.com> @@ -56,6 +57,24 @@ class DumpDataCollectorTest extends TestCase $this->assertSame('a:2:{i:0;b:0;i:1;s:5:"UTF-8";}', $collector->serialize()); } + public function testDumpWithServerConnection() + { + $data = new Data(array(array(123))); + + // Server is up, server dumper is used + $serverDumper = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock(); + $serverDumper->expects($this->once())->method('write')->willReturn(true); + + $collector = new DumpDataCollector(null, null, null, null, $serverDumper); + $collector->dump($data); + + // Collect doesn't re-trigger dump + 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()); + } + public function testCollectDefault() { $data = new Data(array(array(123))); diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/LoggerDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/LoggerDataCollectorTest.php index 3dec3bd7f8..b5c7057fd6 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/LoggerDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/LoggerDataCollectorTest.php @@ -13,7 +13,11 @@ namespace Symfony\Component\HttpKernel\Tests\DataCollector; use PHPUnit\Framework\TestCase; use Symfony\Component\Debug\Exception\SilencedErrorContext; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector; +use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; class LoggerDataCollectorTest extends TestCase { @@ -41,6 +45,46 @@ class LoggerDataCollectorTest extends TestCase ), $compilerLogs['Unknown Compiler Pass']); } + public function testWithMasterRequest() + { + $masterRequest = new Request(); + $stack = new RequestStack(); + $stack->push($masterRequest); + + $logger = $this + ->getMockBuilder(DebugLoggerInterface::class) + ->setMethods(array('countErrors', 'getLogs', 'clear')) + ->getMock(); + $logger->expects($this->once())->method('countErrors')->with(null); + $logger->expects($this->exactly(2))->method('getLogs')->with(null)->will($this->returnValue(array())); + + $c = new LoggerDataCollector($logger, __DIR__.'/', $stack); + + $c->collect($masterRequest, new Response()); + $c->lateCollect(); + } + + public function testWithSubRequest() + { + $masterRequest = new Request(); + $subRequest = new Request(); + $stack = new RequestStack(); + $stack->push($masterRequest); + $stack->push($subRequest); + + $logger = $this + ->getMockBuilder(DebugLoggerInterface::class) + ->setMethods(array('countErrors', 'getLogs', 'clear')) + ->getMock(); + $logger->expects($this->once())->method('countErrors')->with($subRequest); + $logger->expects($this->exactly(2))->method('getLogs')->with($subRequest)->will($this->returnValue(array())); + + $c = new LoggerDataCollector($logger, __DIR__.'/', $stack); + + $c->collect($subRequest, new Response()); + $c->lateCollect(); + } + /** * @dataProvider getCollectTestData */ diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php index cce08e27c4..24904f7cca 100644 --- a/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php +++ b/vendor/symfony/http-kernel/Tests/DataCollector/RequestDataCollectorTest.php @@ -225,6 +225,8 @@ class RequestDataCollectorTest extends TestCase $cookie = $this->getCookieByName($response, 'sf_redirect'); $this->assertNotEmpty($cookie->getValue()); + $this->assertSame('lax', $cookie->getSameSite()); + $this->assertFalse($cookie->isSecure()); } public function testItCollectsTheRedirectionAndClearTheCookie() @@ -274,9 +276,9 @@ class RequestDataCollectorTest extends TestCase $response->setStatusCode(200); $response->headers->set('Content-Type', 'application/json'); $response->headers->set('X-Foo-Bar', null); - $response->headers->setCookie(new Cookie('foo', 'bar', 1, '/foo', 'localhost', true, true)); - $response->headers->setCookie(new Cookie('bar', 'foo', new \DateTime('@946684800'))); - $response->headers->setCookie(new Cookie('bazz', 'foo', '2000-12-12')); + $response->headers->setCookie(new Cookie('foo', 'bar', 1, '/foo', 'localhost', true, true, false, null)); + $response->headers->setCookie(new Cookie('bar', 'foo', new \DateTime('@946684800'), '/', null, false, true, false, null)); + $response->headers->setCookie(new Cookie('bazz', 'foo', '2000-12-12', '/', null, false, true, false, null)); return $response; } diff --git a/vendor/symfony/http-kernel/Tests/DataCollector/Util/ValueExporterTest.php b/vendor/symfony/http-kernel/Tests/DataCollector/Util/ValueExporterTest.php deleted file mode 100644 index 5fe92d60e0..0000000000 --- a/vendor/symfony/http-kernel/Tests/DataCollector/Util/ValueExporterTest.php +++ /dev/null @@ -1,51 +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\HttpKernel\Tests\DataCollector\Util; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpKernel\DataCollector\Util\ValueExporter; - -/** - * @group legacy - */ -class ValueExporterTest extends TestCase -{ - /** - * @var ValueExporter - */ - private $valueExporter; - - protected function setUp() - { - $this->valueExporter = new ValueExporter(); - } - - public function testDateTime() - { - $dateTime = new \DateTime('2014-06-10 07:35:40', new \DateTimeZone('UTC')); - $this->assertSame('Object(DateTime) - 2014-06-10T07:35:40+00:00', $this->valueExporter->exportValue($dateTime)); - } - - public function testDateTimeImmutable() - { - $dateTime = new \DateTimeImmutable('2014-06-10 07:35:40', new \DateTimeZone('UTC')); - $this->assertSame('Object(DateTimeImmutable) - 2014-06-10T07:35:40+00:00', $this->valueExporter->exportValue($dateTime)); - } - - public function testIncompleteClass() - { - $foo = new \__PHP_Incomplete_Class(); - $array = new \ArrayObject($foo); - $array['__PHP_Incomplete_Class_Name'] = 'AppBundle/Foo'; - $this->assertSame('__PHP_Incomplete_Class(AppBundle/Foo)', $this->valueExporter->exportValue($foo)); - } -} diff --git a/vendor/symfony/http-kernel/Tests/DependencyInjection/ControllerArgumentValueResolverPassTest.php b/vendor/symfony/http-kernel/Tests/DependencyInjection/ControllerArgumentValueResolverPassTest.php index df8977de0b..49bbd0f9c1 100644 --- a/vendor/symfony/http-kernel/Tests/DependencyInjection/ControllerArgumentValueResolverPassTest.php +++ b/vendor/symfony/http-kernel/Tests/DependencyInjection/ControllerArgumentValueResolverPassTest.php @@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass; +use Symfony\Component\Stopwatch\Stopwatch; class ControllerArgumentValueResolverPassTest extends TestCase { @@ -42,8 +43,69 @@ class ControllerArgumentValueResolverPassTest extends TestCase $container->register($id)->addTag('controller.argument_value_resolver', $tag); } + $container->setParameter('kernel.debug', false); + (new ControllerArgumentValueResolverPass())->process($container); $this->assertEquals($expected, $definition->getArgument(1)->getValues()); + + $this->assertFalse($container->hasDefinition('n1.traceable')); + $this->assertFalse($container->hasDefinition('n2.traceable')); + $this->assertFalse($container->hasDefinition('n3.traceable')); + } + + public function testInDebugWithStopWatchDefinition() + { + $services = array( + 'n3' => array(array()), + 'n1' => array(array('priority' => 200)), + 'n2' => array(array('priority' => 100)), + ); + + $expected = array( + new Reference('n1'), + new Reference('n2'), + new Reference('n3'), + ); + + $definition = new Definition(ArgumentResolver::class, array(null, array())); + $container = new ContainerBuilder(); + $container->register('debug.stopwatch', Stopwatch::class); + $container->setDefinition('argument_resolver', $definition); + + foreach ($services as $id => list($tag)) { + $container->register($id)->addTag('controller.argument_value_resolver', $tag); + } + + $container->setParameter('kernel.debug', true); + + (new ControllerArgumentValueResolverPass())->process($container); + $this->assertEquals($expected, $definition->getArgument(1)->getValues()); + + $this->assertTrue($container->hasDefinition('debug.n1')); + $this->assertTrue($container->hasDefinition('debug.n2')); + $this->assertTrue($container->hasDefinition('debug.n3')); + + $this->assertTrue($container->hasDefinition('n1')); + $this->assertTrue($container->hasDefinition('n2')); + $this->assertTrue($container->hasDefinition('n3')); + } + + public function testInDebugWithouStopWatchDefinition() + { + $expected = array(new Reference('n1')); + + $definition = new Definition(ArgumentResolver::class, array(null, array())); + $container = new ContainerBuilder(); + $container->register('n1')->addTag('controller.argument_value_resolver'); + $container->setDefinition('argument_resolver', $definition); + + $container->setParameter('kernel.debug', true); + + (new ControllerArgumentValueResolverPass())->process($container); + $this->assertEquals($expected, $definition->getArgument(1)->getValues()); + + $this->assertFalse($container->hasDefinition('debug.n1')); + $this->assertTrue($container->hasDefinition('n1')); } public function testReturningEmptyArrayWhenNoService() @@ -52,6 +114,8 @@ class ControllerArgumentValueResolverPassTest extends TestCase $container = new ContainerBuilder(); $container->setDefinition('argument_resolver', $definition); + $container->setParameter('kernel.debug', false); + (new ControllerArgumentValueResolverPass())->process($container); $this->assertEquals(array(), $definition->getArgument(1)->getValues()); } diff --git a/vendor/symfony/http-kernel/Tests/DependencyInjection/LazyLoadingFragmentHandlerTest.php b/vendor/symfony/http-kernel/Tests/DependencyInjection/LazyLoadingFragmentHandlerTest.php index 95baaa54c1..2bc84a53c8 100644 --- a/vendor/symfony/http-kernel/Tests/DependencyInjection/LazyLoadingFragmentHandlerTest.php +++ b/vendor/symfony/http-kernel/Tests/DependencyInjection/LazyLoadingFragmentHandlerTest.php @@ -18,31 +18,6 @@ use Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler; class LazyLoadingFragmentHandlerTest extends TestCase { - /** - * @group legacy - * @expectedDeprecation The Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler::addRendererService() method is deprecated since Symfony 3.3 and will be removed in 4.0. - */ - public function testRenderWithLegacyMapping() - { - $renderer = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface')->getMock(); - $renderer->expects($this->once())->method('getName')->will($this->returnValue('foo')); - $renderer->expects($this->any())->method('render')->will($this->returnValue(new Response())); - - $requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock(); - $requestStack->expects($this->any())->method('getCurrentRequest')->will($this->returnValue(Request::create('/'))); - - $container = $this->getMockBuilder('Symfony\Component\DependencyInjection\ContainerInterface')->getMock(); - $container->expects($this->once())->method('get')->will($this->returnValue($renderer)); - - $handler = new LazyLoadingFragmentHandler($container, $requestStack, false); - $handler->addRendererService('foo', 'foo'); - - $handler->render('/foo', 'foo'); - - // second call should not lazy-load anymore (see once() above on the get() method) - $handler->render('/foo', 'foo'); - } - public function testRender() { $renderer = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface')->getMock(); diff --git a/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php index ca121c7327..d03ea53a37 100644 --- a/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php +++ b/vendor/symfony/http-kernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php @@ -141,15 +141,15 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertEquals(array('foo:fooAction'), array_keys($locator)); - $this->assertInstanceof(ServiceClosureArgument::class, $locator['foo:fooAction']); + $this->assertEquals(array('foo::fooAction'), array_keys($locator)); + $this->assertInstanceof(ServiceClosureArgument::class, $locator['foo::fooAction']); - $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]); + $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]); $this->assertSame(ServiceLocator::class, $locator->getClass()); $this->assertFalse($locator->isPublic()); - $expected = array('bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, RegisterTestController::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE))); + $expected = array('bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'bar'))); $this->assertEquals($expected, $locator->getArgument(0)); } @@ -167,9 +167,9 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]); + $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]); - $expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, RegisterTestController::class))); + $expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE))); $this->assertEquals($expected, $locator->getArgument(0)); } @@ -186,9 +186,9 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]); + $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]); - $expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, RegisterTestController::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE))); + $expected = array('bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE))); $this->assertEquals($expected, $locator->getArgument(0)); } @@ -204,7 +204,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertSame(array('foo:fooAction'), array_keys($locator)); + $this->assertSame(array('foo::fooAction'), array_keys($locator)); } /** @@ -251,7 +251,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertSame(array('foo:barAction', 'foo:fooAction'), array_keys($locator)); + $this->assertSame(array('foo::barAction', 'foo::fooAction'), array_keys($locator)); } public function testArgumentWithNoTypeHintIsOk() @@ -301,7 +301,7 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $locator = $container->getDefinition((string) $locator['foo:fooAction']->getValues()[0]); + $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]); $expected = array('bar' => new ServiceClosureArgument(new Reference('foo'))); $this->assertEquals($expected, $locator->getArgument(0)); @@ -309,23 +309,49 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase public function provideBindings() { - return array(array(ControllerDummy::class), array('$bar')); + return array( + array(ControllerDummy::class.'$bar'), + array(ControllerDummy::class), + array('$bar'), + ); } - public function testDoNotBindScalarValueToControllerArgument() + /** + * @dataProvider provideBindScalarValueToControllerArgument + */ + public function testBindScalarValueToControllerArgument($bindingKey) { $container = new ContainerBuilder(); $resolver = $container->register('argument_resolver.service')->addArgument(array()); $container->register('foo', ArgumentWithoutTypeController::class) - ->setBindings(array('$someArg' => '%foo%')) + ->setBindings(array($bindingKey => '%foo%')) ->addTag('controller.service_arguments'); + $container->setParameter('foo', 'foo_val'); + $pass = new RegisterControllerArgumentLocatorsPass(); $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertEmpty($locator); + + $locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]); + + // assert the locator has a someArg key + $arguments = $locator->getArgument(0); + $this->assertArrayHasKey('someArg', $arguments); + $this->assertInstanceOf(ServiceClosureArgument::class, $arguments['someArg']); + // get the Reference that someArg points to + $reference = $arguments['someArg']->getValues()[0]; + // make sure this service *does* exist and returns the correct value + $this->assertTrue($container->has((string) $reference)); + $this->assertSame('foo_val', $container->get((string) $reference)); + } + + public function provideBindScalarValueToControllerArgument() + { + yield array('$someArg'); + yield array('string $someArg'); } public function testBindingsOnChildDefinitions() @@ -344,9 +370,9 @@ class RegisterControllerArgumentLocatorsPassTest extends TestCase $pass->process($container); $locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertInstanceOf(ServiceClosureArgument::class, $locator['child:fooAction']); + $this->assertInstanceOf(ServiceClosureArgument::class, $locator['child::fooAction']); - $locator = $container->getDefinition((string) $locator['child:fooAction']->getValues()[0])->getArgument(0); + $locator = $container->getDefinition((string) $locator['child::fooAction']->getValues()[0])->getArgument(0); $this->assertInstanceOf(ServiceClosureArgument::class, $locator['someArg']); $this->assertEquals(new Reference('parent'), $locator['someArg']->getValues()[0]); } @@ -407,7 +433,7 @@ class NonExistentClassOptionalController class ArgumentWithoutTypeController { - public function fooAction($someArg) + public function fooAction(string $someArg) { } } diff --git a/vendor/symfony/http-kernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php b/vendor/symfony/http-kernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php index 9cac968185..dfec38347d 100644 --- a/vendor/symfony/http-kernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php +++ b/vendor/symfony/http-kernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php @@ -36,49 +36,30 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase $controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertCount(2, $container->getDefinition((string) $controllers['c1:fooAction']->getValues()[0])->getArgument(0)); - $this->assertCount(1, $container->getDefinition((string) $controllers['c2:setTestCase']->getValues()[0])->getArgument(0)); - $this->assertCount(1, $container->getDefinition((string) $controllers['c2:fooAction']->getValues()[0])->getArgument(0)); + $this->assertCount(2, $container->getDefinition((string) $controllers['c1::fooAction']->getValues()[0])->getArgument(0)); + $this->assertCount(1, $container->getDefinition((string) $controllers['c2::setTestCase']->getValues()[0])->getArgument(0)); + $this->assertCount(1, $container->getDefinition((string) $controllers['c2::fooAction']->getValues()[0])->getArgument(0)); (new ResolveInvalidReferencesPass())->process($container); - $this->assertCount(1, $container->getDefinition((string) $controllers['c2:setTestCase']->getValues()[0])->getArgument(0)); - $this->assertSame(array(), $container->getDefinition((string) $controllers['c2:fooAction']->getValues()[0])->getArgument(0)); + $this->assertCount(1, $container->getDefinition((string) $controllers['c2::setTestCase']->getValues()[0])->getArgument(0)); + $this->assertSame(array(), $container->getDefinition((string) $controllers['c2::fooAction']->getValues()[0])->getArgument(0)); (new RemoveEmptyControllerArgumentLocatorsPass())->process($container); $controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0); - $this->assertSame(array('c1:fooAction'), array_keys($controllers)); - $this->assertSame(array('bar'), array_keys($container->getDefinition((string) $controllers['c1:fooAction']->getValues()[0])->getArgument(0))); + $this->assertSame(array('c1::fooAction', 'c1:fooAction'), array_keys($controllers)); + $this->assertSame(array('bar'), array_keys($container->getDefinition((string) $controllers['c1::fooAction']->getValues()[0])->getArgument(0))); $expectedLog = array( - 'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument resolver for controller "c2:fooAction": no corresponding services exist for the referenced types.', + 'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument resolver for controller "c2::fooAction": no corresponding services exist for the referenced types.', 'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.', ); $this->assertSame($expectedLog, $container->getCompiler()->getLog()); } - public function testSameIdClass() - { - $container = new ContainerBuilder(); - $resolver = $container->register('argument_resolver.service')->addArgument(array()); - - $container->register(RegisterTestController::class, RegisterTestController::class) - ->addTag('controller.service_arguments') - ; - - (new RegisterControllerArgumentLocatorsPass())->process($container); - (new RemoveEmptyControllerArgumentLocatorsPass())->process($container); - - $expected = array( - RegisterTestController::class.':fooAction', - RegisterTestController::class.'::fooAction', - ); - $this->assertEquals($expected, array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0))); - } - public function testInvoke() { $container = new ContainerBuilder(); @@ -92,35 +73,15 @@ class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase (new RemoveEmptyControllerArgumentLocatorsPass())->process($container); $this->assertEquals( - array('invokable:__invoke', 'invokable'), + array('invokable::__invoke', 'invokable:__invoke', 'invokable'), array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0)) ); } - - public function testInvokeSameIdClass() - { - $container = new ContainerBuilder(); - $resolver = $container->register('argument_resolver.service')->addArgument(array()); - - $container->register(InvokableRegisterTestController::class, InvokableRegisterTestController::class) - ->addTag('controller.service_arguments') - ; - - (new RegisterControllerArgumentLocatorsPass())->process($container); - (new RemoveEmptyControllerArgumentLocatorsPass())->process($container); - - $expected = array( - InvokableRegisterTestController::class.':__invoke', - InvokableRegisterTestController::class.'::__invoke', - InvokableRegisterTestController::class, - ); - $this->assertEquals($expected, array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0))); - } } class RemoveTestController1 { - public function fooAction(\stdClass $bar, ClassNotInContainer $baz) + public function fooAction(\stdClass $bar, ClassNotInContainer $baz = null) { } } @@ -131,7 +92,7 @@ class RemoveTestController2 { } - public function fooAction(ClassNotInContainer $bar) + public function fooAction(ClassNotInContainer $bar = null) { } } diff --git a/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php index 0b73075e7b..5251976e49 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/ExceptionListenerTest.php @@ -54,11 +54,13 @@ class ExceptionListenerTest extends TestCase $this->iniSet('error_log', file_exists('/dev/null') ? '/dev/null' : 'nul'); $l = new ExceptionListener('foo'); + $l->logKernelException($event); $l->onKernelException($event); $this->assertEquals(new Response('foo'), $event->getResponse()); try { + $l->logKernelException($event2); $l->onKernelException($event2); $this->fail('RuntimeException expected'); } catch (\RuntimeException $e) { @@ -75,11 +77,13 @@ class ExceptionListenerTest extends TestCase $logger = new TestLogger(); $l = new ExceptionListener('foo', $logger); + $l->logKernelException($event); $l->onKernelException($event); $this->assertEquals(new Response('foo'), $event->getResponse()); try { + $l->logKernelException($event2); $l->onKernelException($event2); $this->fail('RuntimeException expected'); } catch (\RuntimeException $e) { @@ -151,6 +155,25 @@ class ExceptionListenerTest extends TestCase $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'); } + + public function testNullController() + { + $listener = new ExceptionListener(null); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock(); + $kernel->expects($this->once())->method('handle')->will($this->returnCallback(function (Request $request) { + $controller = $request->attributes->get('_controller'); + + return $controller(); + })); + $request = Request::create('/'); + $event = new GetResponseForExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo')); + + $listener->onKernelException($event); + $this->assertNull($event->getResponse()); + + $listener->onKernelException($event); + $this->assertContains('Whoops, looks like something went wrong.', $event->getResponse()->getContent()); + } } class TestLogger extends Logger implements DebugLoggerInterface diff --git a/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php index ecbce409fb..92e7272965 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/RouterListenerTest.php @@ -70,12 +70,7 @@ class RouterListenerTest extends TestCase ); } - /** - * @param string $uri - * - * @return GetResponseEvent - */ - private function createGetResponseEventForUri($uri) + private function createGetResponseEventForUri(string $uri): GetResponseEvent { $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); $request = Request::create($uri); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php index 5492c3d784..a903fd5891 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/SaveSessionListenerTest.php @@ -19,6 +19,9 @@ use Symfony\Component\HttpKernel\Event\FilterResponseEvent; use Symfony\Component\HttpKernel\EventListener\SaveSessionListener; use Symfony\Component\HttpKernel\HttpKernelInterface; +/** + * @group legacy + */ class SaveSessionListenerTest extends TestCase { public function testOnlyTriggeredOnMasterRequest() diff --git a/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php index 1b95d19f9c..e6255a56e1 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/SessionListenerTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\Session; @@ -56,25 +57,73 @@ class SessionListenerTest extends TestCase $this->assertSame($session, $request->getSession()); } - public function testResponseIsPrivate() + public function testResponseIsPrivateIfSessionStarted() { $session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock(); $session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1)); $container = new Container(); - $container->set('session', $session); + $container->set('initialized_session', $session); $listener = new SessionListener($container); $kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock(); $request = new Request(); - $response = new Response(); $listener->onKernelRequest(new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); - $listener->onKernelResponse(new FilterResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response)); + + $response = new Response(); + $listener->onKernelResponse(new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response)); $this->assertTrue($response->headers->hasCacheControlDirective('private')); $this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate')); $this->assertSame('0', $response->headers->getCacheControlDirective('max-age')); + $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER)); + } + + public function testResponseIsStillPublicIfSessionStartedAndHeaderPresent() + { + $session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock(); + $session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1)); + + $container = new Container(); + $container->set('initialized_session', $session); + + $listener = new SessionListener($container); + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock(); + + $request = new Request(); + $listener->onKernelRequest(new GetResponseEvent($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)); + + $this->assertTrue($response->headers->hasCacheControlDirective('public')); + $this->assertFalse($response->headers->hasCacheControlDirective('private')); + $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate')); + $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage')); + $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER)); + } + + public function testUninitializedSession() + { + $kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock(); + $response = new Response(); + $response->setSharedMaxAge(60); + $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true'); + + $container = new ServiceLocator(array( + 'initialized_session' => function () {}, + )); + + $listener = new SessionListener($container); + $listener->onKernelResponse(new FilterResponseEvent($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')); + $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage')); + $this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER)); } public function testSurrogateMasterRequestIsPublic() @@ -83,6 +132,7 @@ class SessionListenerTest extends TestCase $session->expects($this->exactly(4))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1, 1, 1)); $container = new Container(); + $container->set('initialized_session', $session); $container->set('session', $session); $listener = new SessionListener($container); diff --git a/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php index 0d0985ca5d..cd52bd56e2 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/TestSessionListenerTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; -use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Session\SessionInterface; @@ -144,13 +143,14 @@ class TestSessionListenerTest extends TestCase $this->filterResponse(new Request()); } - public function testDoesNotImplementServiceSubscriberInterface() + public function testDoesNotThrowIfRequestDoesNotHaveASession() { - $this->assertTrue(interface_exists(ServiceSubscriberInterface::class)); - $this->assertTrue(class_exists(SessionListener::class)); - $this->assertTrue(class_exists(TestSessionListener::class)); - $this->assertFalse(is_subclass_of(SessionListener::class, ServiceSubscriberInterface::class), 'Implementing ServiceSubscriberInterface would create a dep on the DI component, which eg Silex cannot afford'); - $this->assertFalse(is_subclass_of(TestSessionListener::class, ServiceSubscriberInterface::class, 'Implementing ServiceSubscriberInterface would create a dep on the DI component, which eg Silex cannot afford')); + $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(); + $event = new FilterResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, new Response()); + + $this->listener->onKernelResponse($event); + + $this->assertTrue(true); } private function filterResponse(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, Response $response = null) diff --git a/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php b/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php index 23b833177a..c4cb9d053b 100644 --- a/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php +++ b/vendor/symfony/http-kernel/Tests/EventListener/TranslatorListenerTest.php @@ -17,6 +17,7 @@ use Symfony\Component\HttpKernel\Event\FinishRequestEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\EventListener\TranslatorListener; use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Contracts\Translation\TranslatorInterface; class TranslatorListenerTest extends TestCase { @@ -26,7 +27,7 @@ class TranslatorListenerTest extends TestCase protected function setUp() { - $this->translator = $this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock(); + $this->translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); $this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock(); $this->listener = new TranslatorListener($this->translator, $this->requestStack); } diff --git a/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php index b5def13ce3..ea82014952 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/MethodNotAllowedHttpExceptionTest.php @@ -12,6 +12,19 @@ class MethodNotAllowedHttpExceptionTest extends HttpExceptionTest $this->assertSame(array('Allow' => 'GET, PUT'), $exception->getHeaders()); } + public function testWithHeaderConstruct() + { + $headers = array( + 'Cache-Control' => 'public, s-maxage=1200', + ); + + $exception = new MethodNotAllowedHttpException(array('get'), null, null, null, $headers); + + $headers['Allow'] = 'GET'; + + $this->assertSame($headers, $exception->getHeaders()); + } + /** * @dataProvider headerDataProvider */ diff --git a/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php index e41a23d4e7..83cbdc2bcc 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/ServiceUnavailableHttpExceptionTest.php @@ -12,6 +12,19 @@ class ServiceUnavailableHttpExceptionTest extends HttpExceptionTest $this->assertSame(array('Retry-After' => 10), $exception->getHeaders()); } + public function testWithHeaderConstruct() + { + $headers = array( + 'Cache-Control' => 'public, s-maxage=1337', + ); + + $exception = new ServiceUnavailableHttpException(1337, null, null, null, $headers); + + $headers['Retry-After'] = 1337; + + $this->assertSame($headers, $exception->getHeaders()); + } + /** * @dataProvider headerDataProvider */ diff --git a/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php index 2079bb3380..6ec7f3d079 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/TooManyRequestsHttpExceptionTest.php @@ -12,6 +12,19 @@ class TooManyRequestsHttpExceptionTest extends HttpExceptionTest $this->assertSame(array('Retry-After' => 10), $exception->getHeaders()); } + public function testWithHeaderConstruct() + { + $headers = array( + 'Cache-Control' => 'public, s-maxage=69', + ); + + $exception = new TooManyRequestsHttpException(69, null, null, null, $headers); + + $headers['Retry-After'] = 69; + + $this->assertSame($headers, $exception->getHeaders()); + } + /** * @dataProvider headerDataProvider */ diff --git a/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php b/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php index 37a0028dc8..1e93d25b1a 100644 --- a/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php +++ b/vendor/symfony/http-kernel/Tests/Exception/UnauthorizedHttpExceptionTest.php @@ -12,6 +12,19 @@ class UnauthorizedHttpExceptionTest extends HttpExceptionTest $this->assertSame(array('WWW-Authenticate' => 'Challenge'), $exception->getHeaders()); } + public function testWithHeaderConstruct() + { + $headers = array( + 'Cache-Control' => 'public, s-maxage=1200', + ); + + $exception = new UnauthorizedHttpException('Challenge', null, null, null, $headers); + + $headers['WWW-Authenticate'] = 'Challenge'; + + $this->assertSame($headers, $exception->getHeaders()); + } + /** * @dataProvider headerDataProvider */ diff --git a/vendor/symfony/http-kernel/Tests/Fixtures/123/Kernel123.php b/vendor/symfony/http-kernel/Tests/Fixtures/123/Kernel123.php deleted file mode 100644 index d3a76684df..0000000000 --- a/vendor/symfony/http-kernel/Tests/Fixtures/123/Kernel123.php +++ /dev/null @@ -1,37 +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\HttpKernel\Tests\Fixtures\_123; - -use Symfony\Component\Config\Loader\LoaderInterface; -use Symfony\Component\HttpKernel\Kernel; - -class Kernel123 extends Kernel -{ - public function registerBundles() - { - return array(); - } - - public function registerContainerConfiguration(LoaderInterface $loader) - { - } - - public function getCacheDir() - { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/kernel123/cache/'.$this->environment; - } - - public function getLogDir() - { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/kernel123/logs'; - } -} diff --git a/vendor/symfony/http-kernel/Tests/Fixtures/KernelForTest.php b/vendor/symfony/http-kernel/Tests/Fixtures/KernelForTest.php index 9acee4cac5..9734594b6e 100644 --- a/vendor/symfony/http-kernel/Tests/Fixtures/KernelForTest.php +++ b/vendor/symfony/http-kernel/Tests/Fixtures/KernelForTest.php @@ -34,4 +34,14 @@ class KernelForTest extends Kernel { return $this->booted; } + + public function getCacheDir() + { + return $this->getProjectDir().'/Tests/Fixtures/cache.'.$this->environment; + } + + public function getLogDir() + { + return $this->getProjectDir().'/Tests/Fixtures/logs'; + } } diff --git a/vendor/symfony/http-kernel/Tests/Fixtures/KernelWithoutBundles.php b/vendor/symfony/http-kernel/Tests/Fixtures/KernelWithoutBundles.php index cee1b09fb2..0d0881d629 100644 --- a/vendor/symfony/http-kernel/Tests/Fixtures/KernelWithoutBundles.php +++ b/vendor/symfony/http-kernel/Tests/Fixtures/KernelWithoutBundles.php @@ -26,6 +26,11 @@ class KernelWithoutBundles extends Kernel { } + public function getProjectDir() + { + return __DIR__; + } + protected function build(ContainerBuilder $container) { $container->setParameter('test_executed', true); diff --git a/vendor/symfony/http-kernel/Tests/Fixtures/TestEventDispatcher.php b/vendor/symfony/http-kernel/Tests/Fixtures/TestEventDispatcher.php index ca2e6a693d..d5456fe5dc 100644 --- a/vendor/symfony/http-kernel/Tests/Fixtures/TestEventDispatcher.php +++ b/vendor/symfony/http-kernel/Tests/Fixtures/TestEventDispatcher.php @@ -11,10 +11,9 @@ namespace Symfony\Component\HttpKernel\Tests\Fixtures; -use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcherInterface; -use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher; -class TestEventDispatcher extends EventDispatcher implements TraceableEventDispatcherInterface +class TestEventDispatcher extends TraceableEventDispatcher { public function getCalledListeners() { @@ -29,4 +28,9 @@ class TestEventDispatcher extends EventDispatcher implements TraceableEventDispa public function reset() { } + + public function getOrphanedEvents() + { + return array(); + } } diff --git a/vendor/symfony/http-kernel/Tests/Fragment/EsiFragmentRendererTest.php b/vendor/symfony/http-kernel/Tests/Fragment/EsiFragmentRendererTest.php index 00d796d520..7ac1f4faa5 100644 --- a/vendor/symfony/http-kernel/Tests/Fragment/EsiFragmentRendererTest.php +++ b/vendor/symfony/http-kernel/Tests/Fragment/EsiFragmentRendererTest.php @@ -26,19 +26,7 @@ class EsiFragmentRendererTest extends TestCase $strategy->render('/', Request::create('/')); } - /** - * @group legacy - * @expectedDeprecation Passing non-scalar values as part of URI attributes to the ESI and SSI rendering strategies is deprecated %s. - */ - public function testRenderFallbackWithObjectAttributesIsDeprecated() - { - $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true), new UriSigner('foo')); - $request = Request::create('/'); - $reference = new ControllerReference('main_controller', array('foo' => new \stdClass()), array()); - $strategy->render($reference, $request); - } - - public function testRenderFallbackWithScalarIsNotDeprecated() + public function testRenderFallbackWithScalar() { $strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true), new UriSigner('foo')); $request = Request::create('/'); diff --git a/vendor/symfony/http-kernel/Tests/Fragment/FragmentHandlerTest.php b/vendor/symfony/http-kernel/Tests/Fragment/FragmentHandlerTest.php index a296aa0e18..0dfaa79682 100644 --- a/vendor/symfony/http-kernel/Tests/Fragment/FragmentHandlerTest.php +++ b/vendor/symfony/http-kernel/Tests/Fragment/FragmentHandlerTest.php @@ -88,7 +88,7 @@ class FragmentHandlerTest extends TestCase ; if ($arguments) { - \call_user_func_array(array($e, 'with'), $arguments); + $e->with(...$arguments); } $handler = new FragmentHandler($this->requestStack); diff --git a/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php b/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php index 80f9cd2b53..ceaa249ab6 100644 --- a/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/vendor/symfony/http-kernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -16,9 +16,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Controller\ArgumentResolver; use Symfony\Component\HttpKernel\Controller\ControllerReference; -use Symfony\Component\HttpKernel\Controller\ControllerResolverInterface; use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\KernelEvents; @@ -55,48 +53,6 @@ class InlineFragmentRendererTest extends TestCase $this->assertSame('foo', $strategy->render(new ControllerReference('main_controller', array('object' => $object), array()), Request::create('/'))->getContent()); } - /** - * @group legacy - */ - public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheControllerLegacy() - { - $resolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolver')->setMethods(array('getController'))->getMock(); - $resolver - ->expects($this->once()) - ->method('getController') - ->will($this->returnValue(function (\stdClass $object, Bar $object1) { - return new Response($object1->getBar()); - })) - ; - - $kernel = new HttpKernel(new EventDispatcher(), $resolver, new RequestStack()); - $renderer = new InlineFragmentRenderer($kernel); - - $response = $renderer->render(new ControllerReference('main_controller', array('object' => new \stdClass(), 'object1' => new Bar()), array()), Request::create('/')); - $this->assertEquals('bar', $response->getContent()); - } - - /** - * @group legacy - */ - public function testRenderWithObjectsAsAttributesPassedAsObjectsInTheController() - { - $resolver = $this->getMockBuilder(ControllerResolverInterface::class)->getMock(); - $resolver - ->expects($this->once()) - ->method('getController') - ->will($this->returnValue(function (\stdClass $object, Bar $object1) { - return new Response($object1->getBar()); - })) - ; - - $kernel = new HttpKernel(new EventDispatcher(), $resolver, new RequestStack(), new ArgumentResolver()); - $renderer = new InlineFragmentRenderer($kernel); - - $response = $renderer->render(new ControllerReference('main_controller', array('object' => new \stdClass(), 'object1' => new Bar()), array()), Request::create('/')); - $this->assertEquals('bar', $response->getContent()); - } - public function testRenderWithTrustedHeaderDisabled() { Request::setTrustedProxies(array(), 0); diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php index 863ad76147..846caee4cc 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/EsiTest.php @@ -234,7 +234,7 @@ class EsiTest extends TestCase if (\is_array($response)) { $cache->expects($this->any()) ->method('handle') - ->will(\call_user_func_array(array($this, 'onConsecutiveCalls'), $response)) + ->will($this->onConsecutiveCalls(...$response)) ; } else { $cache->expects($this->any()) diff --git a/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php b/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php index 26ef6cb2b8..1f1fbf8499 100644 --- a/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpCache/SsiTest.php @@ -201,7 +201,7 @@ class SsiTest extends TestCase if (\is_array($response)) { $cache->expects($this->any()) ->method('handle') - ->will(\call_user_func_array(array($this, 'onConsecutiveCalls'), $response)) + ->will($this->onConsecutiveCalls(...$response)) ; } else { $cache->expects($this->any()) diff --git a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php index 4b9ec69d1e..129fa704be 100644 --- a/vendor/symfony/http-kernel/Tests/HttpKernelTest.php +++ b/vendor/symfony/http-kernel/Tests/HttpKernelTest.php @@ -23,6 +23,7 @@ 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; use Symfony\Component\HttpKernel\HttpKernel; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -111,24 +112,6 @@ class HttpKernelTest extends TestCase $this->assertEquals('POST', $response->headers->get('Allow')); } - /** - * @group legacy - * @dataProvider getStatusCodes - */ - public function testLegacyHandleWhenAnExceptionIsHandledWithASpecificStatusCode($responseStatusCode, $expectedStatusCode) - { - $dispatcher = new EventDispatcher(); - $dispatcher->addListener(KernelEvents::EXCEPTION, function ($event) use ($responseStatusCode, $expectedStatusCode) { - $event->setResponse(new Response('', $responseStatusCode, array('X-Status-Code' => $expectedStatusCode))); - }); - - $kernel = $this->getHttpKernel($dispatcher, function () { throw new \RuntimeException(); }); - $response = $kernel->handle(new Request()); - - $this->assertEquals($expectedStatusCode, $response->getStatusCode()); - $this->assertFalse($response->headers->has('X-Status-Code')); - } - public function getStatusCodes() { return array( @@ -229,15 +212,23 @@ class HttpKernelTest extends TestCase $this->assertResponseEquals(new Response('foo'), $kernel->handle(new Request())); } - /** - * @expectedException \LogicException - */ public function testHandleWhenTheControllerDoesNotReturnAResponse() { $dispatcher = new EventDispatcher(); $kernel = $this->getHttpKernel($dispatcher, function () { return 'foo'; }); - $kernel->handle(new Request()); + try { + $kernel->handle(new Request()); + + $this->fail('The kernel should throw an exception.'); + } catch (ControllerDoesNotReturnResponseException $e) { + } + + $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); } public function testHandleWhenTheControllerDoesNotReturnAResponseButAViewIsRegistered() @@ -283,7 +274,7 @@ class HttpKernelTest extends TestCase $oldArguments = $event->getArguments(); $newController = function ($id) use ($oldController, $oldArguments) { - $response = \call_user_func_array($oldController, $oldArguments); + $response = $oldController(...$oldArguments); $response->headers->set('X-Id', $id); diff --git a/vendor/symfony/http-kernel/Tests/KernelTest.php b/vendor/symfony/http-kernel/Tests/KernelTest.php index ab0b8cfb6e..2b581398c5 100644 --- a/vendor/symfony/http-kernel/Tests/KernelTest.php +++ b/vendor/symfony/http-kernel/Tests/KernelTest.php @@ -19,7 +19,6 @@ use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; -use Symfony\Component\HttpKernel\Config\EnvParametersResource; use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass; use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -34,7 +33,7 @@ class KernelTest extends TestCase public static function tearDownAfterClass() { $fs = new Filesystem(); - $fs->remove(__DIR__.'/Fixtures/cache'); + $fs->remove(__DIR__.'/Fixtures/var'); } public function testConstructor() @@ -68,15 +67,15 @@ class KernelTest extends TestCase public function testInitializeContainerClearsOldContainers() { $fs = new Filesystem(); - $legacyContainerDir = __DIR__.'/Fixtures/cache/custom/ContainerA123456'; + $legacyContainerDir = __DIR__.'/Fixtures/var/cache/custom/ContainerA123456'; $fs->mkdir($legacyContainerDir); touch($legacyContainerDir.'.legacy'); $kernel = new CustomProjectDirKernel(); $kernel->boot(); - $containerDir = __DIR__.'/Fixtures/cache/custom/'.substr(\get_class($kernel->getContainer()), 0, 16); - $this->assertTrue(unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta')); + $containerDir = __DIR__.'/Fixtures/var/cache/custom/'.substr(\get_class($kernel->getContainer()), 0, 16); + $this->assertTrue(unlink(__DIR__.'/Fixtures/var/cache/custom/TestsSymfony_Component_HttpKernel_Tests_CustomProjectDirKernelCustomDebugContainer.php.meta')); $this->assertFileExists($containerDir); $this->assertFileNotExists($containerDir.'.legacy'); @@ -124,20 +123,6 @@ class KernelTest extends TestCase $this->assertTrue($kernel->isBooted()); } - /** - * @group legacy - */ - public function testClassCacheIsLoaded() - { - $kernel = $this->getKernel(array('initializeBundles', 'initializeContainer', 'doLoadClassCache')); - $kernel->loadClassCache('name', '.extension'); - $kernel->expects($this->once()) - ->method('doLoadClassCache') - ->with('name', '.extension'); - - $kernel->boot(); - } - public function testClassCacheIsNotLoadedByDefault() { $kernel = $this->getKernel(array('initializeBundles', 'initializeContainer', 'doLoadClassCache')); @@ -147,53 +132,6 @@ class KernelTest extends TestCase $kernel->boot(); } - /** - * @group legacy - */ - public function testClassCacheIsNotLoadedWhenKernelIsNotBooted() - { - $kernel = $this->getKernel(array('initializeBundles', 'initializeContainer', 'doLoadClassCache')); - $kernel->loadClassCache(); - $kernel->expects($this->never()) - ->method('doLoadClassCache'); - } - - public function testEnvParametersResourceIsAdded() - { - $container = new ContainerBuilder(); - $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest') - ->disableOriginalConstructor() - ->setMethods(array('getContainerBuilder', 'prepareContainer', 'getCacheDir', 'getLogDir')) - ->getMock(); - $kernel->expects($this->any()) - ->method('getContainerBuilder') - ->will($this->returnValue($container)); - $kernel->expects($this->any()) - ->method('prepareContainer') - ->will($this->returnValue(null)); - $kernel->expects($this->any()) - ->method('getCacheDir') - ->will($this->returnValue(sys_get_temp_dir())); - $kernel->expects($this->any()) - ->method('getLogDir') - ->will($this->returnValue(sys_get_temp_dir())); - - $reflection = new \ReflectionClass(\get_class($kernel)); - $method = $reflection->getMethod('buildContainer'); - $method->setAccessible(true); - $method->invoke($kernel); - - $found = false; - foreach ($container->getResources() as $resource) { - if ($resource instanceof EnvParametersResource) { - $found = true; - break; - } - } - - $this->assertTrue($found); - } - public function testBootKernelSeveralTimesOnlyInitializesBundlesOnce() { $kernel = $this->getKernel(array('initializeBundles', 'initializeContainer')); @@ -357,6 +295,9 @@ EOF; $this->assertEquals($expected, $output); } + /** + * @group legacy + */ public function testGetRootDir() { $kernel = new KernelForTest('test', true); @@ -364,6 +305,9 @@ EOF; $this->assertEquals(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures', realpath($kernel->getRootDir())); } + /** + * @group legacy + */ public function testGetName() { $kernel = new KernelForTest('test', true); @@ -371,6 +315,9 @@ EOF; $this->assertEquals('Fixtures', $kernel->getName()); } + /** + * @group legacy + */ public function testOverrideGetName() { $kernel = new KernelForOverrideName('test', true); @@ -421,7 +368,7 @@ EOF; $kernel ->expects($this->once()) ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle')))) + ->will($this->returnValue($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'))) ; $kernel->locateResource('@Bundle1Bundle/config/routing.xml'); @@ -433,80 +380,19 @@ EOF; $kernel ->expects($this->once()) ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle')))) + ->will($this->returnValue($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'))) ; $this->assertEquals(__DIR__.'/Fixtures/Bundle1Bundle/foo.txt', $kernel->locateResource('@Bundle1Bundle/foo.txt')); } - /** - * @group legacy - */ - public function testLocateResourceReturnsTheFirstThatMatchesWithParent() - { - $parent = $this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'); - $child = $this->getBundle(__DIR__.'/Fixtures/Bundle2Bundle'); - - $kernel = $this->getKernel(array('getBundle')); - $kernel - ->expects($this->exactly(2)) - ->method('getBundle') - ->will($this->returnValue(array($child, $parent))) - ; - - $this->assertEquals(__DIR__.'/Fixtures/Bundle2Bundle/foo.txt', $kernel->locateResource('@ParentAABundle/foo.txt')); - $this->assertEquals(__DIR__.'/Fixtures/Bundle1Bundle/bar.txt', $kernel->locateResource('@ParentAABundle/bar.txt')); - } - - /** - * @group legacy - */ - public function testLocateResourceReturnsAllMatches() - { - $parent = $this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'); - $child = $this->getBundle(__DIR__.'/Fixtures/Bundle2Bundle'); - - $kernel = $this->getKernel(array('getBundle')); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->will($this->returnValue(array($child, $parent))) - ; - - $this->assertEquals(array( - __DIR__.'/Fixtures/Bundle2Bundle/foo.txt', - __DIR__.'/Fixtures/Bundle1Bundle/foo.txt', ), - $kernel->locateResource('@Bundle1Bundle/foo.txt', null, false)); - } - - /** - * @group legacy - */ - public function testLocateResourceReturnsAllMatchesBis() - { - $kernel = $this->getKernel(array('getBundle')); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->will($this->returnValue(array( - $this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'), - $this->getBundle(__DIR__.'/Foobar'), - ))) - ; - - $this->assertEquals( - array(__DIR__.'/Fixtures/Bundle1Bundle/foo.txt'), - $kernel->locateResource('@Bundle1Bundle/foo.txt', null, false) - ); - } - public function testLocateResourceIgnoresDirOnNonResource() { $kernel = $this->getKernel(array('getBundle')); $kernel ->expects($this->once()) ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle')))) + ->will($this->returnValue($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle'))) ; $this->assertEquals( @@ -521,7 +407,7 @@ EOF; $kernel ->expects($this->once()) ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/FooBundle', null, null, 'FooBundle')))) + ->will($this->returnValue($this->getBundle(__DIR__.'/Fixtures/FooBundle', null, null, 'FooBundle'))) ; $this->assertEquals( @@ -530,73 +416,13 @@ EOF; ); } - /** - * @group legacy - */ - public function testLocateResourceReturnsTheDirOneForResourcesAndBundleOnes() - { - $kernel = $this->getKernel(array('getBundle')); - $kernel - ->expects($this->once()) - ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle', null, null, 'Bundle1Bundle')))) - ; - - $this->assertEquals(array( - __DIR__.'/Fixtures/Resources/Bundle1Bundle/foo.txt', - __DIR__.'/Fixtures/Bundle1Bundle/Resources/foo.txt', ), - $kernel->locateResource('@Bundle1Bundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources', false) - ); - } - - /** - * @group legacy - */ - public function testLocateResourceOverrideBundleAndResourcesFolders() - { - $parent = $this->getBundle(__DIR__.'/Fixtures/BaseBundle', null, 'BaseBundle', 'BaseBundle'); - $child = $this->getBundle(__DIR__.'/Fixtures/ChildBundle', 'ParentBundle', 'ChildBundle', 'ChildBundle'); - - $kernel = $this->getKernel(array('getBundle')); - $kernel - ->expects($this->exactly(4)) - ->method('getBundle') - ->will($this->returnValue(array($child, $parent))) - ; - - $this->assertEquals(array( - __DIR__.'/Fixtures/Resources/ChildBundle/foo.txt', - __DIR__.'/Fixtures/ChildBundle/Resources/foo.txt', - __DIR__.'/Fixtures/BaseBundle/Resources/foo.txt', - ), - $kernel->locateResource('@BaseBundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources', false) - ); - - $this->assertEquals( - __DIR__.'/Fixtures/Resources/ChildBundle/foo.txt', - $kernel->locateResource('@BaseBundle/Resources/foo.txt', __DIR__.'/Fixtures/Resources') - ); - - try { - $kernel->locateResource('@BaseBundle/Resources/hide.txt', __DIR__.'/Fixtures/Resources', false); - $this->fail('Hidden resources should raise an exception when returning an array of matching paths'); - } catch (\RuntimeException $e) { - } - - try { - $kernel->locateResource('@BaseBundle/Resources/hide.txt', __DIR__.'/Fixtures/Resources', true); - $this->fail('Hidden resources should raise an exception when returning the first matching path'); - } catch (\RuntimeException $e) { - } - } - public function testLocateResourceOnDirectories() { $kernel = $this->getKernel(array('getBundle')); $kernel ->expects($this->exactly(2)) ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/FooBundle', null, null, 'FooBundle')))) + ->will($this->returnValue($this->getBundle(__DIR__.'/Fixtures/FooBundle', null, null, 'FooBundle'))) ; $this->assertEquals( @@ -612,7 +438,7 @@ EOF; $kernel ->expects($this->exactly(2)) ->method('getBundle') - ->will($this->returnValue(array($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle', null, null, 'Bundle1Bundle')))) + ->will($this->returnValue($this->getBundle(__DIR__.'/Fixtures/Bundle1Bundle', null, null, 'Bundle1Bundle'))) ; $this->assertEquals( @@ -626,103 +452,6 @@ EOF; } /** - * @group legacy - */ - public function testInitializeBundles() - { - $parent = $this->getBundle(null, null, 'ParentABundle'); - $child = $this->getBundle(null, 'ParentABundle', 'ChildABundle'); - - // use test kernel so we can access getBundleMap() - $kernel = $this->getKernelForTest(array('registerBundles')); - $kernel - ->expects($this->once()) - ->method('registerBundles') - ->will($this->returnValue(array($parent, $child))) - ; - $kernel->boot(); - - $map = $kernel->getBundleMap(); - $this->assertEquals(array($child, $parent), $map['ParentABundle']); - } - - /** - * @group legacy - */ - public function testInitializeBundlesSupportInheritanceCascade() - { - $grandparent = $this->getBundle(null, null, 'GrandParentBBundle'); - $parent = $this->getBundle(null, 'GrandParentBBundle', 'ParentBBundle'); - $child = $this->getBundle(null, 'ParentBBundle', 'ChildBBundle'); - - // use test kernel so we can access getBundleMap() - $kernel = $this->getKernelForTest(array('registerBundles')); - $kernel - ->expects($this->once()) - ->method('registerBundles') - ->will($this->returnValue(array($grandparent, $parent, $child))) - ; - $kernel->boot(); - - $map = $kernel->getBundleMap(); - $this->assertEquals(array($child, $parent, $grandparent), $map['GrandParentBBundle']); - $this->assertEquals(array($child, $parent), $map['ParentBBundle']); - $this->assertEquals(array($child), $map['ChildBBundle']); - } - - /** - * @group legacy - * @expectedException \LogicException - * @expectedExceptionMessage Bundle "ChildCBundle" extends bundle "FooBar", which is not registered. - */ - public function testInitializeBundlesThrowsExceptionWhenAParentDoesNotExists() - { - $child = $this->getBundle(null, 'FooBar', 'ChildCBundle'); - $kernel = $this->getKernel(array(), array($child)); - $kernel->boot(); - } - - /** - * @group legacy - */ - public function testInitializeBundlesSupportsArbitraryBundleRegistrationOrder() - { - $grandparent = $this->getBundle(null, null, 'GrandParentCBundle'); - $parent = $this->getBundle(null, 'GrandParentCBundle', 'ParentCBundle'); - $child = $this->getBundle(null, 'ParentCBundle', 'ChildCBundle'); - - // use test kernel so we can access getBundleMap() - $kernel = $this->getKernelForTest(array('registerBundles')); - $kernel - ->expects($this->once()) - ->method('registerBundles') - ->will($this->returnValue(array($parent, $grandparent, $child))) - ; - $kernel->boot(); - - $map = $kernel->getBundleMap(); - $this->assertEquals(array($child, $parent, $grandparent), $map['GrandParentCBundle']); - $this->assertEquals(array($child, $parent), $map['ParentCBundle']); - $this->assertEquals(array($child), $map['ChildCBundle']); - } - - /** - * @group legacy - * @expectedException \LogicException - * @expectedExceptionMessage Bundle "ParentCBundle" is directly extended by two bundles "ChildC2Bundle" and "ChildC1Bundle". - */ - public function testInitializeBundlesThrowsExceptionWhenABundleIsDirectlyExtendedByTwoBundles() - { - $parent = $this->getBundle(null, null, 'ParentCBundle'); - $child1 = $this->getBundle(null, 'ParentCBundle', 'ChildC1Bundle'); - $child2 = $this->getBundle(null, 'ParentCBundle', 'ChildC2Bundle'); - - $kernel = $this->getKernel(array(), array($parent, $child1, $child2)); - $kernel->boot(); - } - - /** - * @group legacy * @expectedException \LogicException * @expectedExceptionMessage Trying to register two bundles with the same name "DuplicateName" */ @@ -735,19 +464,6 @@ EOF; $kernel->boot(); } - /** - * @group legacy - * @expectedException \LogicException - * @expectedExceptionMessage Bundle "CircularRefBundle" can not extend itself. - */ - public function testInitializeBundleThrowsExceptionWhenABundleExtendsItself() - { - $circularRef = $this->getBundle(null, 'CircularRefBundle', 'CircularRefBundle'); - - $kernel = $this->getKernel(array(), array($circularRef)); - $kernel->boot(); - } - public function testTerminateReturnsSilentlyIfKernelIsNotBooted() { $kernel = $this->getKernel(array('getHttpKernel')); @@ -799,59 +515,32 @@ EOF; $this->assertTrue($kernel->getContainer()->getParameter('test_executed')); } - public function testKernelRootDirNameStartingWithANumber() - { - $dir = __DIR__.'/Fixtures/123'; - require_once $dir.'/Kernel123.php'; - $kernel = new \Symfony\Component\HttpKernel\Tests\Fixtures\_123\Kernel123('dev', true); - $this->assertEquals('_123', $kernel->getName()); - } - - /** - * @group legacy - * @expectedDeprecation The "Symfony\Component\HttpKernel\Kernel::getEnvParameters()" method is deprecated as of 3.3 and will be removed in 4.0. Use the %cenv()%c syntax to get the value of any environment variable from configuration files instead. - * @expectedDeprecation The support of special environment variables that start with SYMFONY__ (such as "SYMFONY__FOO__BAR") is deprecated as of 3.3 and will be removed in 4.0. Use the %cenv()%c syntax instead to get the value of environment variables in configuration files. - */ - public function testSymfonyEnvironmentVariables() - { - $_SERVER['SYMFONY__FOO__BAR'] = 'baz'; - - $kernel = $this->getKernel(); - $method = new \ReflectionMethod($kernel, 'getEnvParameters'); - $method->setAccessible(true); - - $envParameters = $method->invoke($kernel); - $this->assertSame('baz', $envParameters['foo.bar']); - - unset($_SERVER['SYMFONY__FOO__BAR']); - } - public function testProjectDirExtension() { $kernel = new CustomProjectDirKernel(); $kernel->boot(); - $this->assertSame('foo', $kernel->getProjectDir()); - $this->assertSame('foo', $kernel->getContainer()->getParameter('kernel.project_dir')); + $this->assertSame(__DIR__.'/Fixtures', $kernel->getProjectDir()); + $this->assertSame(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures', $kernel->getContainer()->getParameter('kernel.project_dir')); } public function testKernelReset() { - (new Filesystem())->remove(__DIR__.'/Fixtures/cache'); + (new Filesystem())->remove(__DIR__.'/Fixtures/var/cache'); $kernel = new CustomProjectDirKernel(); $kernel->boot(); $containerClass = \get_class($kernel->getContainer()); $containerFile = (new \ReflectionClass($kernel->getContainer()))->getFileName(); - unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta'); + unlink(__DIR__.'/Fixtures/var/cache/custom/TestsSymfony_Component_HttpKernel_Tests_CustomProjectDirKernelCustomDebugContainer.php.meta'); $kernel = new CustomProjectDirKernel(); $kernel->boot(); $this->assertInstanceOf($containerClass, $kernel->getContainer()); $this->assertFileExists($containerFile); - unlink(__DIR__.'/Fixtures/cache/custom/FixturesCustomDebugProjectContainer.php.meta'); + unlink(__DIR__.'/Fixtures/var/cache/custom/TestsSymfony_Component_HttpKernel_Tests_CustomProjectDirKernelCustomDebugContainer.php.meta'); $kernel = new CustomProjectDirKernel(function ($container) { $container->register('foo', 'stdClass')->setPublic(true); }); $kernel->boot(); @@ -1019,11 +708,10 @@ class CustomProjectDirKernel extends Kernel private $buildContainer; private $httpKernel; - public function __construct(\Closure $buildContainer = null, HttpKernelInterface $httpKernel = null, $name = 'custom') + public function __construct(\Closure $buildContainer = null, HttpKernelInterface $httpKernel = null, $env = 'custom') { - parent::__construct($name, true); + parent::__construct($env, true); - $this->baseDir = 'foo'; $this->buildContainer = $buildContainer; $this->httpKernel = $httpKernel; } @@ -1039,11 +727,6 @@ class CustomProjectDirKernel extends Kernel public function getProjectDir() { - return $this->baseDir; - } - - public function getRootDir() - { return __DIR__.'/Fixtures'; } diff --git a/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php b/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php index a1db1d9c0e..e64c622c37 100644 --- a/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php +++ b/vendor/symfony/http-kernel/Tests/Profiler/FileProfilerStorageTest.php @@ -22,7 +22,7 @@ class FileProfilerStorageTest extends TestCase protected function setUp() { - $this->tmpDir = sys_get_temp_dir().'/sf2_profiler_file_storage'; + $this->tmpDir = sys_get_temp_dir().'/sf_profiler_file_storage'; if (is_dir($this->tmpDir)) { self::cleanDir(); } diff --git a/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php b/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php index cff133c1aa..2f7e8dd284 100644 --- a/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php +++ b/vendor/symfony/http-kernel/Tests/Profiler/ProfilerTest.php @@ -84,7 +84,7 @@ class ProfilerTest extends TestCase protected function setUp() { - $this->tmp = tempnam(sys_get_temp_dir(), 'sf2_profiler'); + $this->tmp = tempnam(sys_get_temp_dir(), 'sf_profiler'); if (file_exists($this->tmp)) { @unlink($this->tmp); } diff --git a/vendor/symfony/http-kernel/UriSigner.php b/vendor/symfony/http-kernel/UriSigner.php index 28459b4ecd..de73039b34 100644 --- a/vendor/symfony/http-kernel/UriSigner.php +++ b/vendor/symfony/http-kernel/UriSigner.php @@ -25,7 +25,7 @@ class UriSigner * @param string $secret A secret * @param string $parameter Query string parameter to use */ - public function __construct($secret, $parameter = '_hash') + public function __construct(string $secret, string $parameter = '_hash') { $this->secret = $secret; $this->parameter = $parameter; diff --git a/vendor/symfony/http-kernel/composer.json b/vendor/symfony/http-kernel/composer.json index 9ad3877ba1..8228377e04 100644 --- a/vendor/symfony/http-kernel/composer.json +++ b/vendor/symfony/http-kernel/composer.json @@ -16,38 +16,39 @@ } ], "require": { - "php": "^5.5.9|>=7.0.8", - "symfony/event-dispatcher": "~2.8|~3.0|~4.0", - "symfony/http-foundation": "~3.4.12|~4.0.12|^4.1.1", - "symfony/debug": "~2.8|~3.0|~4.0", + "php": "^7.1.3", + "symfony/contracts": "^1.0", + "symfony/event-dispatcher": "~4.1", + "symfony/http-foundation": "^4.1.1", + "symfony/debug": "~3.4|~4.0", "symfony/polyfill-ctype": "~1.8", "psr/log": "~1.0" }, "require-dev": { - "symfony/browser-kit": "~2.8|~3.0|~4.0", - "symfony/class-loader": "~2.8|~3.0", - "symfony/config": "~2.8|~3.0|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/css-selector": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "^3.4.10|^4.0.10", - "symfony/dom-crawler": "~2.8|~3.0|~4.0", - "symfony/expression-language": "~2.8|~3.0|~4.0", - "symfony/finder": "~2.8|~3.0|~4.0", - "symfony/process": "~2.8|~3.0|~4.0", + "symfony/browser-kit": "~3.4|~4.0", + "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/dom-crawler": "~3.4|~4.0", + "symfony/expression-language": "~3.4|~4.0", + "symfony/finder": "~3.4|~4.0", + "symfony/process": "~3.4|~4.0", "symfony/routing": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0", - "symfony/templating": "~2.8|~3.0|~4.0", - "symfony/translation": "~2.8|~3.0|~4.0", - "symfony/var-dumper": "~3.3|~4.0", + "symfony/stopwatch": "~3.4|~4.0", + "symfony/templating": "~3.4|~4.0", + "symfony/translation": "~4.2", + "symfony/var-dumper": "^4.1.1", "psr/cache": "~1.0" }, "provide": { "psr/log-implementation": "1.0" }, "conflict": { - "symfony/config": "<2.8", - "symfony/dependency-injection": "<3.4.10|<4.0.10,>=4", - "symfony/var-dumper": "<3.3", + "symfony/config": "<3.4", + "symfony/dependency-injection": "<4.2", + "symfony/translation": "<4.2", + "symfony/var-dumper": "<4.1.1", "twig/twig": "<1.34|<2.4,>=2" }, "suggest": { @@ -55,7 +56,6 @@ "symfony/config": "", "symfony/console": "", "symfony/dependency-injection": "", - "symfony/finder": "", "symfony/var-dumper": "" }, "autoload": { @@ -67,7 +67,7 @@ "minimum-stability": "dev", "extra": { "branch-alias": { - "dev-master": "3.4-dev" + "dev-master": "4.2-dev" } } } diff --git a/vendor/symfony/http-kernel/phpunit.xml.dist b/vendor/symfony/http-kernel/phpunit.xml.dist index e0de769dd7..3fc07707f2 100644 --- a/vendor/symfony/http-kernel/phpunit.xml.dist +++ b/vendor/symfony/http-kernel/phpunit.xml.dist @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" backupGlobals="false" colors="true" bootstrap="vendor/autoload.php" diff --git a/vendor/symfony/polyfill-apcu/Apcu.php b/vendor/symfony/polyfill-apcu/Apcu.php deleted file mode 100644 index 95a65459a5..0000000000 --- a/vendor/symfony/polyfill-apcu/Apcu.php +++ /dev/null @@ -1,106 +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\Polyfill\Apcu; - -/** - * Apcu for Zend Server Data Cache. - * - * @author Kate Gray <opensource@codebykate.com> - * @author Nicolas Grekas <p@tchwork.com> - * - * @internal - */ -final class Apcu -{ - public static function apcu_add($key, $var = null, $ttl = 0) - { - if (!\is_array($key)) { - return apc_add($key, $var, $ttl); - } - - $errors = array(); - foreach ($key as $k => $v) { - if (!apc_add($k, $v, $ttl)) { - $errors[$k] = -1; - } - } - - return $errors; - } - - public static function apcu_store($key, $var = null, $ttl = 0) - { - if (!\is_array($key)) { - return apc_store($key, $var, $ttl); - } - - $errors = array(); - foreach ($key as $k => $v) { - if (!apc_store($k, $v, $ttl)) { - $errors[$k] = -1; - } - } - - return $errors; - } - - public static function apcu_exists($keys) - { - if (!\is_array($keys)) { - return apc_exists($keys); - } - - $existing = array(); - foreach ($keys as $k) { - if (apc_exists($k)) { - $existing[$k] = true; - } - } - - return $existing; - } - - public static function apcu_fetch($key, &$success = null) - { - if (!\is_array($key)) { - return apc_fetch($key, $success); - } - - $succeeded = true; - $values = array(); - foreach ($key as $k) { - $v = apc_fetch($k, $success); - if ($success) { - $values[$k] = $v; - } else { - $succeeded = false; - } - } - $success = $succeeded; - - return $values; - } - - public static function apcu_delete($key) - { - if (!\is_array($key)) { - return apc_delete($key); - } - - $success = true; - foreach ($key as $k) { - $success = apc_delete($k) && $success; - } - - return $success; - } -} diff --git a/vendor/symfony/polyfill-apcu/README.md b/vendor/symfony/polyfill-apcu/README.md deleted file mode 100644 index e614bcab51..0000000000 --- a/vendor/symfony/polyfill-apcu/README.md +++ /dev/null @@ -1,12 +0,0 @@ -Symfony Polyfill / APCu -======================== - -This component provides `apcu_*` functions and the `APCUIterator` class to users of the legacy APC extension. - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-apcu/bootstrap.php b/vendor/symfony/polyfill-apcu/bootstrap.php deleted file mode 100644 index 305183b6a3..0000000000 --- a/vendor/symfony/polyfill-apcu/bootstrap.php +++ /dev/null @@ -1,48 +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. - */ - -use Symfony\Polyfill\Apcu as p; - -if (!extension_loaded('apc') && !extension_loaded('apcu')) { - return; -} - -if (!function_exists('apcu_add')) { - if (extension_loaded('Zend Data Cache')) { - function apcu_add($key, $var = null, $ttl = 0) { return p\Apcu::apcu_add($key, $var, $ttl); } - function apcu_delete($key) { return p\Apcu::apcu_delete($key); } - function apcu_exists($keys) { return p\Apcu::apcu_exists($keys); } - function apcu_fetch($key, &$success = null) { return p\Apcu::apcu_fetch($key, $success); } - function apcu_store($key, $var = null, $ttl = 0) { return p\Apcu::apcu_store($key, $var, $ttl); } - } else { - function apcu_add($key, $var = null, $ttl = 0) { return apc_add($key, $var, $ttl); } - function apcu_delete($key) { return apc_delete($key); } - function apcu_exists($keys) { return apc_exists($keys); } - function apcu_fetch($key, &$success = null) { return apc_fetch($key, $success); } - function apcu_store($key, $var = null, $ttl = 0) { return apc_store($key, $var, $ttl); } - } - function apcu_cache_info($limited = false) { return apc_cache_info('user', $limited); } - function apcu_cas($key, $old, $new) { return apc_cas($key, $old, $new); } - function apcu_clear_cache() { return apc_clear_cache('user'); } - function apcu_dec($key, $step = 1, &$success = false) { return apc_dec($key, $step, $success); } - function apcu_inc($key, $step = 1, &$success = false) { return apc_inc($key, $step, $success); } - function apcu_sma_info($limited = false) { return apc_sma_info($limited); } -} - -if (!class_exists('APCUIterator', false) && class_exists('APCIterator', false)) { - class APCUIterator extends APCIterator - { - public function __construct($search = null, $format = APC_ITER_ALL, $chunk_size = 100, $list = APC_LIST_ACTIVE) - { - parent::__construct('user', $search, $format, $chunk_size, $list); - } - } -} diff --git a/vendor/symfony/polyfill-apcu/composer.json b/vendor/symfony/polyfill-apcu/composer.json deleted file mode 100644 index ebe40e18ed..0000000000 --- a/vendor/symfony/polyfill-apcu/composer.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "symfony/polyfill-apcu", - "type": "library", - "description": "Symfony polyfill backporting apcu_* functions to lower PHP versions", - "keywords": ["polyfill", "shim", "compatibility", "portable", "apcu"], - "homepage": "https://symfony.com", - "license": "MIT", - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "require": { - "php": ">=5.3.3" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Apcu\\": "" }, - "files": [ "bootstrap.php" ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - } -} diff --git a/vendor/symfony/polyfill-php70/Php70.php b/vendor/symfony/polyfill-php70/Php70.php deleted file mode 100644 index 7f1ad08a46..0000000000 --- a/vendor/symfony/polyfill-php70/Php70.php +++ /dev/null @@ -1,74 +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\Polyfill\Php70; - -/** - * @author Nicolas Grekas <p@tchwork.com> - * - * @internal - */ -final class Php70 -{ - public static function intdiv($dividend, $divisor) - { - $dividend = self::intArg($dividend, __FUNCTION__, 1); - $divisor = self::intArg($divisor, __FUNCTION__, 2); - - if (0 === $divisor) { - throw new \DivisionByZeroError('Division by zero'); - } - if (-1 === $divisor && ~PHP_INT_MAX === $dividend) { - throw new \ArithmeticError('Division of PHP_INT_MIN by -1 is not an integer'); - } - - return ($dividend - ($dividend % $divisor)) / $divisor; - } - - public static function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) - { - $count = 0; - $result = (string) $subject; - if (0 === $limit = self::intArg($limit, __FUNCTION__, 3)) { - return $result; - } - - foreach ($patterns as $pattern => $callback) { - $result = preg_replace_callback($pattern, $callback, $result, $limit, $c); - $count += $c; - } - - return $result; - } - - public static function error_clear_last() - { - static $handler; - if (!$handler) { - $handler = function () { return false; }; - } - set_error_handler($handler); - @trigger_error(''); - restore_error_handler(); - } - - private static function intArg($value, $caller, $pos) - { - if (\is_int($value)) { - return $value; - } - if (!\is_numeric($value) || PHP_INT_MAX <= ($value += 0) || ~PHP_INT_MAX >= $value) { - throw new \TypeError(sprintf('%s() expects parameter %d to be integer, %s given', $caller, $pos, \gettype($value))); - } - - return (int) $value; - } -} diff --git a/vendor/symfony/polyfill-php70/README.md b/vendor/symfony/polyfill-php70/README.md deleted file mode 100644 index 04988c6f93..0000000000 --- a/vendor/symfony/polyfill-php70/README.md +++ /dev/null @@ -1,28 +0,0 @@ -Symfony Polyfill / Php70 -======================== - -This component provides features unavailable in releases prior to PHP 7.0: - -- [`intdiv`](http://php.net/intdiv) -- [`preg_replace_callback_array`](http://php.net/preg_replace_callback_array) -- [`error_clear_last`](http://php.net/error_clear_last) -- `random_bytes` and `random_int` (from [paragonie/random_compat](https://github.com/paragonie/random_compat)) -- [`*Error` throwable classes](http://php.net/Error) -- [`PHP_INT_MIN`](http://php.net/manual/en/reserved.constants.php#constant.php-int-min) -- `SessionUpdateTimestampHandlerInterface` - -More information can be found in the -[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md). - -Compatibility notes -=================== - -To write portable code between PHP5 and PHP7, some care must be taken: -- `\*Error` exceptions must be caught before `\Exception`; -- after calling `error_clear_last()`, the result of `$e = error_get_last()` must be - verified using `isset($e['message'][0])` instead of `null !== $e`. - -License -======= - -This library is released under the [MIT license](LICENSE). diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php b/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php deleted file mode 100644 index 6819124462..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/ArithmeticError.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -class ArithmeticError extends Error -{ -} diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php b/vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php deleted file mode 100644 index acb125080f..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/AssertionError.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -class AssertionError extends Error -{ -} diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php b/vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php deleted file mode 100644 index c99278b31d..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/DivisionByZeroError.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -class DivisionByZeroError extends Error -{ -} diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/Error.php b/vendor/symfony/polyfill-php70/Resources/stubs/Error.php deleted file mode 100644 index 405847fb89..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/Error.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -class Error extends Exception -{ -} diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php b/vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php deleted file mode 100644 index 2dd447dd43..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/ParseError.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -class ParseError extends Error -{ -} diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php b/vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php deleted file mode 100644 index 0cc02c8f92..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/SessionUpdateTimestampHandlerInterface.php +++ /dev/null @@ -1,23 +0,0 @@ -<?php - -interface SessionUpdateTimestampHandlerInterface -{ - /** - * Checks if a session identifier already exists or not. - * - * @param string $key - * - * @return bool - */ - public function validateId($key); - - /** - * Updates the timestamp of a session when its data didn't change. - * - * @param string $key - * @param string $val - * - * @return bool - */ - public function updateTimestamp($key, $val); -} diff --git a/vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php b/vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php deleted file mode 100644 index 2bed1b4831..0000000000 --- a/vendor/symfony/polyfill-php70/Resources/stubs/TypeError.php +++ /dev/null @@ -1,5 +0,0 @@ -<?php - -class TypeError extends Error -{ -} diff --git a/vendor/symfony/polyfill-php70/bootstrap.php b/vendor/symfony/polyfill-php70/bootstrap.php deleted file mode 100644 index 445c39839c..0000000000 --- a/vendor/symfony/polyfill-php70/bootstrap.php +++ /dev/null @@ -1,27 +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. - */ - -use Symfony\Polyfill\Php70 as p; - -if (PHP_VERSION_ID < 70000) { - if (!defined('PHP_INT_MIN')) { - define('PHP_INT_MIN', ~PHP_INT_MAX); - } - if (!function_exists('intdiv')) { - function intdiv($dividend, $divisor) { return p\Php70::intdiv($dividend, $divisor); } - } - if (!function_exists('preg_replace_callback_array')) { - function preg_replace_callback_array(array $patterns, $subject, $limit = -1, &$count = 0) { return p\Php70::preg_replace_callback_array($patterns, $subject, $limit, $count); } - } - if (!function_exists('error_clear_last')) { - function error_clear_last() { return p\Php70::error_clear_last(); } - } -} diff --git a/vendor/symfony/polyfill-php70/composer.json b/vendor/symfony/polyfill-php70/composer.json deleted file mode 100644 index 13dcf94a62..0000000000 --- a/vendor/symfony/polyfill-php70/composer.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "symfony/polyfill-php70", - "type": "library", - "description": "Symfony polyfill backporting some PHP 7.0+ 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", - "paragonie/random_compat": "~1.0|~2.0|~9.99" - }, - "autoload": { - "psr-4": { "Symfony\\Polyfill\\Php70\\": "" }, - "files": [ "bootstrap.php" ], - "classmap": [ "Resources/stubs" ] - }, - "minimum-stability": "dev", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - } -} diff --git a/vendor/symfony/var-exporter/.gitignore b/vendor/symfony/var-exporter/.gitignore new file mode 100644 index 0000000000..5414c2c655 --- /dev/null +++ b/vendor/symfony/var-exporter/.gitignore @@ -0,0 +1,3 @@ +composer.lock +phpunit.xml +vendor/ diff --git a/vendor/symfony/var-exporter/CHANGELOG.md b/vendor/symfony/var-exporter/CHANGELOG.md new file mode 100644 index 0000000000..9aa4a8b310 --- /dev/null +++ b/vendor/symfony/var-exporter/CHANGELOG.md @@ -0,0 +1,7 @@ +CHANGELOG +========= + +4.2.0 +----- + + * added the component diff --git a/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php b/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php new file mode 100644 index 0000000000..4cebe44b0f --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/ClassNotFoundException.php @@ -0,0 +1,20 @@ +<?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\VarExporter\Exception; + +class ClassNotFoundException extends \Exception implements ExceptionInterface +{ + public function __construct(string $class, \Throwable $previous = null) + { + parent::__construct(sprintf('Class "%s" not found.', $class), 0, $previous); + } +} diff --git a/vendor/symfony/var-exporter/Exception/ExceptionInterface.php b/vendor/symfony/var-exporter/Exception/ExceptionInterface.php new file mode 100644 index 0000000000..adfaed47c0 --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/ExceptionInterface.php @@ -0,0 +1,16 @@ +<?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\VarExporter\Exception; + +interface ExceptionInterface extends \Throwable +{ +} diff --git a/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php b/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php new file mode 100644 index 0000000000..7ca4884596 --- /dev/null +++ b/vendor/symfony/var-exporter/Exception/NotInstantiableTypeException.php @@ -0,0 +1,20 @@ +<?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\VarExporter\Exception; + +class NotInstantiableTypeException extends \Exception implements ExceptionInterface +{ + public function __construct(string $type) + { + parent::__construct(sprintf('Type "%s" is not instantiable.', $type)); + } +} diff --git a/vendor/symfony/var-exporter/Instantiator.php b/vendor/symfony/var-exporter/Instantiator.php new file mode 100644 index 0000000000..0061d76e78 --- /dev/null +++ b/vendor/symfony/var-exporter/Instantiator.php @@ -0,0 +1,94 @@ +<?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\VarExporter; + +use Symfony\Component\VarExporter\Exception\ExceptionInterface; +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\Registry; + +/** + * A utility class to create objects without calling their constructor. + * + * @author Nicolas Grekas <p@tchwork.com> + */ +final class Instantiator +{ + /** + * Creates an object and sets its properties without calling its constructor nor any other methods. + * + * For example: + * + * // creates an empty instance of Foo + * Instantiator::instantiate(Foo::class); + * + * // creates a Foo instance and sets one of its properties + * Instantiator::instantiate(Foo::class, ['propertyName' => $propertyValue]); + * + * // creates a Foo instance and sets a private property defined on its parent Bar class + * Instantiator::instantiate(Foo::class, [], [ + * Bar::class => ['privateBarProperty' => $propertyValue], + * ]); + * + * Instances of ArrayObject, ArrayIterator and SplObjectHash can be created + * by using the special "\0" property name to define their internal value: + * + * // creates an SplObjectHash where $info1 is attached to $obj1, etc. + * Instantiator::instantiate(SplObjectStorage::class, ["\0" => [$obj1, $info1, $obj2, $info2...]]); + * + * // creates an ArrayObject populated with $inputArray + * Instantiator::instantiate(ArrayObject::class, ["\0" => [$inputArray]]); + * + * @param string $class The class of the instance to create + * @param array $properties The properties to set on the instance + * @param array $privateProperties The private properties to set on the instance, + * keyed by their declaring class + * + * @return object The created instance + * + * @throws ExceptionInterface When the instance cannot be created + */ + public static function instantiate(string $class, array $properties = array(), array $privateProperties = array()) + { + $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); + + if (Registry::$cloneable[$class]) { + $wrappedInstance = array(clone Registry::$prototypes[$class]); + } elseif (Registry::$instantiableWithoutConstructor[$class]) { + $wrappedInstance = array($reflector->newInstanceWithoutConstructor()); + } elseif (null === Registry::$prototypes[$class]) { + throw new NotInstantiableTypeException($class); + } elseif ($reflector->implementsInterface('Serializable')) { + $wrappedInstance = array(unserialize('C:'.\strlen($class).':"'.$class.'":0:{}')); + } else { + $wrappedInstance = array(unserialize('O:'.\strlen($class).':"'.$class.'":0:{}')); + } + + if ($properties) { + $privateProperties[$class] = isset($privateProperties[$class]) ? $properties + $privateProperties[$class] : $properties; + } + + foreach ($privateProperties as $class => $properties) { + if (!$properties) { + continue; + } + foreach ($properties as $name => $value) { + // because they're also used for "unserialization", hydrators + // deal with array of instances, so we need to wrap values + $properties[$name] = array($value); + } + (Hydrator::$hydrators[$class] ?? Hydrator::getHydrator($class))($properties, $wrappedInstance); + } + + return $wrappedInstance[0]; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Exporter.php b/vendor/symfony/var-exporter/Internal/Exporter.php new file mode 100644 index 0000000000..bbb409e194 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Exporter.php @@ -0,0 +1,392 @@ +<?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\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +class Exporter +{ + /** + * Prepares an array of values for VarExporter. + * + * For performance this method is public and has no type-hints. + * + * @param array &$values + * @param \SplObjectStorage $objectsPool + * @param array &$refsPool + * @param int &$objectsCount + * @param bool &$valuesAreStatic + * + * @return int + * + * @throws NotInstantiableTypeException When a value cannot be serialized + */ + public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount, &$valuesAreStatic) + { + $refs = $values; + foreach ($values as $k => $value) { + if (\is_resource($value)) { + throw new NotInstantiableTypeException(\get_resource_type($value).' resource'); + } + $refs[$k] = $objectsPool; + + if ($isRef = !$valueIsStatic = $values[$k] !== $objectsPool) { + $values[$k] = &$value; // Break hard references to make $values completely + unset($value); // independent from the original structure + $refs[$k] = $value = $values[$k]; + if ($value instanceof Reference && 0 > $value->id) { + $valuesAreStatic = false; + ++$value->count; + continue; + } + $refsPool[] = array(&$refs[$k], $value, &$value); + $refs[$k] = $values[$k] = new Reference(-\count($refsPool), $value); + } + + if (\is_array($value)) { + if ($value) { + $value = self::prepare($value, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); + } + goto handle_value; + } elseif (!\is_object($value) && !$value instanceof \__PHP_Incomplete_Class) { + goto handle_value; + } + + $valueIsStatic = false; + if (isset($objectsPool[$value])) { + ++$objectsCount; + $value = new Reference($objectsPool[$value][0]); + goto handle_value; + } + + $class = \get_class($value); + $properties = array(); + $sleep = null; + $arrayValue = (array) $value; + $reflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); + $proto = Registry::$prototypes[$class]; + + if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) { + // ArrayIterator and ArrayObject need special care because their "flags" + // option changes the behavior of the (array) casting operator. + $properties = self::getArrayObjectProperties($value, $arrayValue, $proto); + + // populates Registry::$prototypes[$class] with a new instance + Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]); + } elseif ($value instanceof \SplObjectStorage && Registry::$cloneable[$class] && null !== $proto) { + // By implementing Serializable, SplObjectStorage breaks + // internal references; let's deal with it on our own. + foreach (clone $value as $v) { + $properties[] = $v; + $properties[] = $value[$v]; + } + $properties = array('SplObjectStorage' => array("\0" => $properties)); + } elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class) { + ++$objectsCount; + $objectsPool[$value] = array($id = \count($objectsPool), serialize($value), array(), 0); + $value = new Reference($id); + goto handle_value; + } + + if (\method_exists($class, '__sleep')) { + if (!\is_array($sleep = $value->__sleep())) { + trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', E_USER_NOTICE); + $value = null; + goto handle_value; + } + foreach ($sleep as $name) { + if (\property_exists($value, $name) && !$reflector->hasProperty($name)) { + $arrayValue[$name] = $value->$name; + } + } + $sleep = array_flip($sleep); + } + + $proto = (array) $proto; + + foreach ($arrayValue as $name => $v) { + $i = 0; + $n = (string) $name; + if ('' === $n || "\0" !== $n[0]) { + $c = 'stdClass'; + } elseif ('*' === $n[1]) { + $n = substr($n, 3); + $c = $reflector->getProperty($n)->class; + if ('Error' === $c) { + $c = 'TypeError'; + } elseif ('Exception' === $c) { + $c = 'ErrorException'; + } + } else { + $i = strpos($n, "\0", 2); + $c = substr($n, 1, $i - 1); + $n = substr($n, 1 + $i); + } + if (null !== $sleep) { + if (!isset($sleep[$n]) || ($i && $c !== $class)) { + continue; + } + $sleep[$n] = false; + } + if (!\array_key_exists($name, $proto) || $proto[$name] !== $v) { + $properties[$c][$n] = $v; + } + } + if ($sleep) { + foreach ($sleep as $n => $v) { + if (false !== $v) { + trigger_error(sprintf('serialize(): "%s" returned as member variable from __sleep() but does not exist', $n), E_USER_NOTICE); + } + } + } + + $objectsPool[$value] = array($id = \count($objectsPool)); + $properties = self::prepare($properties, $objectsPool, $refsPool, $objectsCount, $valueIsStatic); + ++$objectsCount; + $objectsPool[$value] = array($id, $class, $properties, \method_exists($class, '__wakeup') ? $objectsCount : 0); + + $value = new Reference($id); + + handle_value: + if ($isRef) { + unset($value); // Break the hard reference created above + } elseif (!$valueIsStatic) { + $values[$k] = $value; + } + $valuesAreStatic = $valueIsStatic && $valuesAreStatic; + } + + return $values; + } + + public static function export($value, $indent = '') + { + switch (true) { + case \is_int($value) || \is_float($value): return var_export($value, true); + case array() === $value: return '[]'; + case false === $value: return 'false'; + case true === $value: return 'true'; + case null === $value: return 'null'; + case '' === $value: return "''"; + } + + if ($value instanceof Reference) { + if (0 <= $value->id) { + return '$o['.$value->id.']'; + } + if (!$value->count) { + return self::export($value->value, $indent); + } + $value = -$value->id; + + return '&$r['.$value.']'; + } + $subIndent = $indent.' '; + + if (\is_string($value)) { + $code = var_export($value, true); + + if (false !== strpos($value, "\n") || false !== strpos($value, "\r")) { + $code = strtr($code, array( + "\r\n" => "'.\"\\r\\n\"\n".$subIndent.".'", + "\r" => "'.\"\\r\"\n".$subIndent.".'", + "\n" => "'.\"\\n\"\n".$subIndent.".'", + )); + } + + if (false !== strpos($value, "\0")) { + $code = str_replace('\' . "\0" . \'', '\'."\0".\'', $code); + $code = str_replace('".\'\'."', '', $code); + } + + if (false !== strpos($code, "''.")) { + $code = str_replace("''.", '', $code); + } + + if (".''" === substr($code, -3)) { + $code = rtrim(substr($code, 0, -3)); + } + + return $code; + } + + if (\is_array($value)) { + $j = -1; + $code = ''; + foreach ($value as $k => $v) { + $code .= $subIndent; + if (!\is_int($k) || 1 !== $k - $j) { + $code .= self::export($k, $subIndent).' => '; + } + if (\is_int($k)) { + $j = $k; + } + $code .= self::export($v, $subIndent).",\n"; + } + + return "[\n".$code.$indent.']'; + } + + if ($value instanceof Values) { + $code = $subIndent."\$r = [],\n"; + foreach ($value->values as $k => $v) { + $code .= $subIndent.'$r['.$k.'] = '.self::export($v, $subIndent).",\n"; + } + + return "[\n".$code.$indent.']'; + } + + if ($value instanceof Registry) { + return self::exportRegistry($value, $indent, $subIndent); + } + + if ($value instanceof Hydrator) { + return self::exportHydrator($value, $indent, $subIndent); + } + + throw new \UnexpectedValueException(sprintf('Cannot export value of type "%s".', \is_object($value) ? \get_class($value) : \gettype($value))); + } + + private static function exportRegistry(Registry $value, string $indent, string $subIndent): string + { + $code = ''; + $serializables = array(); + $seen = array(); + $prototypesAccess = 0; + $factoriesAccess = 0; + $r = '\\'.Registry::class; + $j = -1; + + foreach ($value as $k => $class) { + if (':' === ($class[1] ?? null)) { + $serializables[$k] = $class; + continue; + } + if (!Registry::$instantiableWithoutConstructor[$class]) { + if (is_subclass_of($class, 'Serializable')) { + $serializables[$k] = 'C:'.\strlen($class).':"'.$class.'":0:{}'; + } else { + $serializables[$k] = 'O:'.\strlen($class).':"'.$class.'":0:{}'; + } + if (is_subclass_of($class, 'Throwable')) { + $eol = is_subclass_of($class, 'Error') ? "\0Error\0" : "\0Exception\0"; + $serializables[$k] = substr_replace($serializables[$k], '1:{s:'.(5 + \strlen($eol)).':"'.$eol.'trace";a:0:{}}', -4); + } + continue; + } + $code .= $subIndent.(1 !== $k - $j ? $k.' => ' : ''); + $j = $k; + $eol = ",\n"; + $c = '['.self::export($class).']'; + + if ($seen[$class] ?? false) { + if (Registry::$cloneable[$class]) { + ++$prototypesAccess; + $code .= 'clone $p'.$c; + } else { + ++$factoriesAccess; + $code .= '$f'.$c.'()'; + } + } else { + $seen[$class] = true; + if (Registry::$cloneable[$class]) { + $code .= 'clone ('.($prototypesAccess++ ? '$p' : '($p = &'.$r.'::$prototypes)').$c.' ?? '.$r.'::p'; + } else { + $code .= '('.($factoriesAccess++ ? '$f' : '($f = &'.$r.'::$factories)').$c.' ?? '.$r.'::f'; + $eol = '()'.$eol; + } + $code .= '('.substr($c, 1, -1).'))'; + } + $code .= $eol; + } + + if (1 === $prototypesAccess) { + $code = str_replace('($p = &'.$r.'::$prototypes)', $r.'::$prototypes', $code); + } + if (1 === $factoriesAccess) { + $code = str_replace('($f = &'.$r.'::$factories)', $r.'::$factories', $code); + } + if ('' !== $code) { + $code = "\n".$code.$indent; + } + + if ($serializables) { + $code = $r.'::unserialize(['.$code.'], '.self::export($serializables, $indent).')'; + } else { + $code = '['.$code.']'; + } + + return '$o = '.$code; + } + + private static function exportHydrator(Hydrator $value, string $indent, string $subIndent): string + { + $code = ''; + foreach ($value->properties as $class => $properties) { + $code .= $subIndent.' '.self::export($class).' => '.self::export($properties, $subIndent.' ').",\n"; + } + + $code = array( + self::export($value->registry, $subIndent), + self::export($value->values, $subIndent), + '' !== $code ? "[\n".$code.$subIndent.']' : '[]', + self::export($value->value, $subIndent), + self::export($value->wakeups, $subIndent), + ); + + return '\\'.\get_class($value)."::hydrate(\n".$subIndent.implode(",\n".$subIndent, $code)."\n".$indent.')'; + } + + /** + * @param \ArrayIterator|\ArrayObject $value + * @param \ArrayIterator|\ArrayObject $proto + */ + private static function getArrayObjectProperties($value, array &$arrayValue, $proto): array + { + $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject'; + $reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector); + + $properties = array( + $arrayValue, + $reflector->getMethod('getFlags')->invoke($value), + $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator', + ); + + $reflector = $reflector->getMethod('setFlags'); + $reflector->invoke($proto, \ArrayObject::STD_PROP_LIST); + + if ($properties[1] & \ArrayObject::STD_PROP_LIST) { + $reflector->invoke($value, 0); + $properties[0] = (array) $value; + } else { + $reflector->invoke($value, \ArrayObject::STD_PROP_LIST); + $arrayValue = (array) $value; + } + $reflector->invoke($value, $properties[1]); + + if (array(array(), 0, 'ArrayIterator') === $properties) { + $properties = array(); + } else { + if ('ArrayIterator' === $properties[2]) { + unset($properties[2]); + } + $properties = array($reflector->class => array("\0" => $properties)); + } + + return $properties; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Hydrator.php b/vendor/symfony/var-exporter/Internal/Hydrator.php new file mode 100644 index 0000000000..0de27743d9 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Hydrator.php @@ -0,0 +1,142 @@ +<?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\VarExporter\Internal; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +class Hydrator +{ + public static $hydrators = array(); + + public $registry; + public $values; + public $properties; + public $value; + public $wakeups; + + public function __construct(?Registry $registry, ?Values $values, array $properties, $value, array $wakeups) + { + $this->registry = $registry; + $this->values = $values; + $this->properties = $properties; + $this->value = $value; + $this->wakeups = $wakeups; + } + + public static function hydrate($objects, $values, $properties, $value, $wakeups) + { + foreach ($properties as $class => $vars) { + (self::$hydrators[$class] ?? self::getHydrator($class))($vars, $objects); + } + foreach ($wakeups as $i) { + $objects[$i]->__wakeup(); + } + + return $value; + } + + public static function getHydrator($class) + { + if ('stdClass' === $class) { + return self::$hydrators[$class] = static function ($properties, $objects) { + foreach ($properties as $name => $values) { + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } + + $classReflector = Registry::$reflectors[$class] ?? Registry::getClassReflector($class); + + if (!$classReflector->isInternal()) { + return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, $class); + } + + if ($classReflector->name !== $class) { + return self::$hydrators[$classReflector->name] ?? self::getHydrator($classReflector->name); + } + + switch ($class) { + case 'ArrayIterator': + case 'ArrayObject': + $constructor = \Closure::fromCallable(array($classReflector->getConstructor(), 'invokeArgs')); + + return self::$hydrators[$class] = static function ($properties, $objects) use ($constructor) { + foreach ($properties as $name => $values) { + if ("\0" !== $name) { + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + } + foreach ($properties["\0"] ?? array() as $i => $v) { + $constructor($objects[$i], $v); + } + }; + + case 'ErrorException': + return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \ErrorException { + }); + + case 'TypeError': + return self::$hydrators[$class] = (self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'))->bindTo(null, new class() extends \Error { + }); + + case 'SplObjectStorage': + return self::$hydrators[$class] = static function ($properties, $objects) { + foreach ($properties as $name => $values) { + if ("\0" === $name) { + foreach ($values as $i => $v) { + for ($j = 0; $j < \count($v); ++$j) { + $objects[$i]->attach($v[$j], $v[++$j]); + } + } + continue; + } + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } + + $propertySetters = array(); + foreach ($classReflector->getProperties() as $propertyReflector) { + if (!$propertyReflector->isStatic()) { + $propertyReflector->setAccessible(true); + $propertySetters[$propertyReflector->name] = \Closure::fromCallable(array($propertyReflector, 'setValue')); + } + } + + if (!$propertySetters) { + return self::$hydrators[$class] = self::$hydrators['stdClass'] ?? self::getHydrator('stdClass'); + } + + return self::$hydrators[$class] = static function ($properties, $objects) use ($propertySetters) { + foreach ($properties as $name => $values) { + if ($setValue = $propertySetters[$name] ?? null) { + foreach ($values as $i => $v) { + $setValue($objects[$i], $v); + } + continue; + } + foreach ($values as $i => $v) { + $objects[$i]->$name = $v; + } + } + }; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Reference.php b/vendor/symfony/var-exporter/Internal/Reference.php new file mode 100644 index 0000000000..e371c07b88 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Reference.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\VarExporter\Internal; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +class Reference +{ + public $id; + public $value; + public $count = 0; + + public function __construct(int $id, $value = null) + { + $this->id = $id; + $this->value = $value; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Registry.php b/vendor/symfony/var-exporter/Internal/Registry.php new file mode 100644 index 0000000000..487a8566e2 --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Registry.php @@ -0,0 +1,142 @@ +<?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\VarExporter\Internal; + +use Symfony\Component\VarExporter\Exception\ClassNotFoundException; +use Symfony\Component\VarExporter\Exception\NotInstantiableTypeException; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +class Registry +{ + public static $reflectors = array(); + public static $prototypes = array(); + public static $factories = array(); + public static $cloneable = array(); + public static $instantiableWithoutConstructor = array(); + + public function __construct(array $classes) + { + foreach ($classes as $i => $class) { + $this->$i = $class; + } + } + + public static function unserialize($objects, $serializables) + { + $unserializeCallback = ini_set('unserialize_callback_func', __CLASS__.'::getClassReflector'); + + try { + foreach ($serializables as $k => $v) { + $objects[$k] = unserialize($v); + } + } finally { + ini_set('unserialize_callback_func', $unserializeCallback); + } + + return $objects; + } + + public static function p($class) + { + self::getClassReflector($class, true, true); + + return self::$prototypes[$class]; + } + + public static function f($class) + { + $reflector = self::$reflectors[$class] ?? self::getClassReflector($class, true, false); + + return self::$factories[$class] = \Closure::fromCallable(array($reflector, 'newInstanceWithoutConstructor')); + } + + public static function getClassReflector($class, $instantiableWithoutConstructor = false, $cloneable = null) + { + if (!\class_exists($class) && !\interface_exists($class, false) && !\trait_exists($class, false)) { + throw new ClassNotFoundException($class); + } + $reflector = new \ReflectionClass($class); + + if ($instantiableWithoutConstructor) { + $proto = $reflector->newInstanceWithoutConstructor(); + } elseif (!$reflector->isInstantiable()) { + throw new NotInstantiableTypeException($class); + } elseif ($reflector->name !== $class) { + $reflector = self::$reflectors[$name = $reflector->name] ?? self::getClassReflector($name, $instantiableWithoutConstructor, $cloneable); + self::$cloneable[$class] = self::$cloneable[$name]; + self::$instantiableWithoutConstructor[$class] = self::$instantiableWithoutConstructor[$name]; + self::$prototypes[$class] = self::$prototypes[$name]; + + return self::$reflectors[$class] = $reflector; + } else { + try { + $proto = $reflector->newInstanceWithoutConstructor(); + $instantiableWithoutConstructor = true; + } catch (\ReflectionException $e) { + $proto = $reflector->implementsInterface('Serializable') ? 'C:' : 'O:'; + if ('C:' === $proto && !$reflector->getMethod('unserialize')->isInternal()) { + $proto = null; + } elseif (false === $proto = @unserialize($proto.\strlen($class).':"'.$class.'":0:{}')) { + throw new NotInstantiableTypeException($class); + } + } + if (null !== $proto && !$proto instanceof \Throwable) { + try { + if (!$proto instanceof \Serializable && !\method_exists($class, '__sleep')) { + serialize($proto); + } elseif ($instantiableWithoutConstructor) { + serialize($reflector->newInstanceWithoutConstructor()); + } else { + serialize(unserialize(($proto instanceof \Serializable ? 'C:' : 'O:').\strlen($class).':"'.$class.'":0:{}')); + } + } catch (\Exception $e) { + throw new NotInstantiableTypeException($class, $e); + } + } + } + + if (null === $cloneable) { + if (($proto instanceof \Reflector || $proto instanceof \ReflectionGenerator || $proto instanceof \ReflectionType || $proto instanceof \IteratorIterator || $proto instanceof \RecursiveIteratorIterator) && (!$proto instanceof \Serializable && !\method_exists($proto, '__wakeup'))) { + throw new NotInstantiableTypeException($class); + } + + $cloneable = $reflector->isCloneable() && !$reflector->hasMethod('__clone'); + } + + self::$cloneable[$class] = $cloneable; + self::$instantiableWithoutConstructor[$class] = $instantiableWithoutConstructor; + self::$prototypes[$class] = $proto; + + if ($proto instanceof \Throwable) { + static $setTrace; + + if (null === $setTrace) { + $setTrace = array( + new \ReflectionProperty(\Error::class, 'trace'), + new \ReflectionProperty(\Exception::class, 'trace'), + ); + $setTrace[0]->setAccessible(true); + $setTrace[1]->setAccessible(true); + $setTrace[0] = \Closure::fromCallable(array($setTrace[0], 'setValue')); + $setTrace[1] = \Closure::fromCallable(array($setTrace[1], 'setValue')); + } + + $setTrace[$proto instanceof \Exception]($proto, array()); + } + + return self::$reflectors[$class] = $reflector; + } +} diff --git a/vendor/symfony/var-exporter/Internal/Values.php b/vendor/symfony/var-exporter/Internal/Values.php new file mode 100644 index 0000000000..21ae04e68b --- /dev/null +++ b/vendor/symfony/var-exporter/Internal/Values.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\VarExporter\Internal; + +/** + * @author Nicolas Grekas <p@tchwork.com> + * + * @internal + */ +class Values +{ + public $values; + + public function __construct(array $values) + { + $this->values = $values; + } +} diff --git a/vendor/symfony/polyfill-php70/LICENSE b/vendor/symfony/var-exporter/LICENSE index 24fa32c2e9..ad399a798d 100644 --- a/vendor/symfony/polyfill-php70/LICENSE +++ b/vendor/symfony/var-exporter/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2018 Fabien Potencier +Copyright (c) 2018 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/vendor/symfony/var-exporter/README.md b/vendor/symfony/var-exporter/README.md new file mode 100644 index 0000000000..c3a072127e --- /dev/null +++ b/vendor/symfony/var-exporter/README.md @@ -0,0 +1,37 @@ +VarExporter Component +===================== + +The VarExporter component allows exporting any serializable PHP data structure to +plain PHP code. While doing so, it preserves all the semantics associated with +the serialization mechanism of PHP (`__wakeup`, `__sleep`, `Serializable`). + +It also provides an instantiator that allows creating and populating objects +without calling their constructor nor any other methods. + +The reason to use this component *vs* `serialize()` or +[igbinary](https://github.com/igbinary/igbinary) is performance: thanks to +OPcache, the resulting code is significantly faster and more memory efficient +than using `unserialize()` or `igbinary_unserialize()`. + +Unlike `var_export()`, this works on any serializable PHP value. + +It also provides a few improvements over `var_export()`/`serialize()`: + + * the output is PSR-2 compatible; + * the output can be re-indented without messing up with `\r` or `\n` in the data + * missing classes throw a `ClassNotFoundException` instead of being unserialized to + `PHP_Incomplete_Class` objects; + * references involving `SplObjectStorage`, `ArrayObject` or `ArrayIterator` + instances are preserved; + * `Reflection*`, `IteratorIterator` and `RecursiveIteratorIterator` classes + throw an exception when being serialized (their unserialized version is broken + anyway, see https://bugs.php.net/76737). + +Resources +--------- + + * [Documentation](https://symfony.com/doc/current/components/var_exporter/introduction.html) + * [Contributing](https://symfony.com/doc/current/contributing/index.html) + * [Report issues](https://github.com/symfony/symfony/issues) and + [send Pull Requests](https://github.com/symfony/symfony/pulls) + in the [main Symfony repository](https://github.com/symfony/symfony) diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/array-iterator.php b/vendor/symfony/var-exporter/Tests/Fixtures/array-iterator.php new file mode 100644 index 0000000000..c59573315d --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/array-iterator.php @@ -0,0 +1,22 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['ArrayIterator'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('ArrayIterator')), + ], + null, + [ + 'ArrayIterator' => [ + "\0" => [ + [ + [ + 123, + ], + 1, + ], + ], + ], + ], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/array-object-custom.php b/vendor/symfony/var-exporter/Tests/Fixtures/array-object-custom.php new file mode 100644 index 0000000000..35303f8222 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/array-object-custom.php @@ -0,0 +1,22 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\MyArrayObject'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyArrayObject')), + ], + null, + [ + 'ArrayObject' => [ + "\0" => [ + [ + [ + 234, + ], + 1, + ], + ], + ], + ], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/array-object.php b/vendor/symfony/var-exporter/Tests/Fixtures/array-object.php new file mode 100644 index 0000000000..a461c6ed97 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/array-object.php @@ -0,0 +1,29 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (($p = &\Symfony\Component\VarExporter\Internal\Registry::$prototypes)['ArrayObject'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('ArrayObject')), + clone $p['ArrayObject'], + ], + null, + [ + 'ArrayObject' => [ + "\0" => [ + [ + [ + 1, + $o[0], + ], + 0, + ], + ], + ], + 'stdClass' => [ + 'foo' => [ + $o[1], + ], + ], + ], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/bool.php b/vendor/symfony/var-exporter/Tests/Fixtures/bool.php new file mode 100644 index 0000000000..438d99ecc0 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/bool.php @@ -0,0 +1,3 @@ +<?php + +return true; diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/clone.php b/vendor/symfony/var-exporter/Tests/Fixtures/clone.php new file mode 100644 index 0000000000..d3447805e1 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/clone.php @@ -0,0 +1,15 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + (($f = &\Symfony\Component\VarExporter\Internal\Registry::$factories)['Symfony\\Component\\VarExporter\\Tests\\MyCloneable'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\MyCloneable'))(), + ($f['Symfony\\Component\\VarExporter\\Tests\\MyNotCloneable'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\MyNotCloneable'))(), + ], + null, + [], + [ + $o[0], + $o[1], + ], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/datetime.php b/vendor/symfony/var-exporter/Tests/Fixtures/datetime.php new file mode 100644 index 0000000000..1c916458c4 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/datetime.php @@ -0,0 +1,25 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['DateTime'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('DateTime')), + ], + null, + [ + 'stdClass' => [ + 'date' => [ + '1970-01-01 00:00:00.000000', + ], + 'timezone_type' => [ + 1, + ], + 'timezone' => [ + '+00:00', + ], + ], + ], + $o[0], + [ + 1 => 0, + ] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/error.php b/vendor/symfony/var-exporter/Tests/Fixtures/error.php new file mode 100644 index 0000000000..1362d0ea4d --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/error.php @@ -0,0 +1,30 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + (\Symfony\Component\VarExporter\Internal\Registry::$factories['Error'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Error'))(), + ], + null, + [ + 'TypeError' => [ + 'file' => [ + \dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', + ], + 'line' => [ + 234, + ], + ], + 'Error' => [ + 'trace' => [ + [ + 'file' => \dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', + 'line' => 123, + ], + ], + ], + ], + $o[0], + [ + 1 => 0, + ] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/external-references.php b/vendor/symfony/var-exporter/Tests/Fixtures/external-references.php new file mode 100644 index 0000000000..0405b59a8f --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/external-references.php @@ -0,0 +1,7 @@ +<?php + +return [ + [ + 123, + ], +]; diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/final-array-iterator.php b/vendor/symfony/var-exporter/Tests/Fixtures/final-array-iterator.php new file mode 100644 index 0000000000..9bdb2b3662 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/final-array-iterator.php @@ -0,0 +1,11 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ + 'C:54:"Symfony\\Component\\VarExporter\\Tests\\FinalArrayIterator":49:{a:2:{i:0;i:123;i:1;s:21:"x:i:0;a:0:{};m:a:0:{}";}}', + ]), + null, + [], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/final-error.php b/vendor/symfony/var-exporter/Tests/Fixtures/final-error.php new file mode 100644 index 0000000000..dc260dc024 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/final-error.php @@ -0,0 +1,22 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ + 'O:46:"Symfony\\Component\\VarExporter\\Tests\\FinalError":1:{s:12:"'."\0".'Error'."\0".'trace";a:0:{}}', + ]), + null, + [ + 'TypeError' => [ + 'file' => [ + \dirname(__DIR__).\DIRECTORY_SEPARATOR.'VarExporterTest.php', + ], + 'line' => [ + 123, + ], + ], + ], + $o[0], + [ + 1 => 0, + ] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/final-stdclass.php b/vendor/symfony/var-exporter/Tests/Fixtures/final-stdclass.php new file mode 100644 index 0000000000..335e009371 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/final-stdclass.php @@ -0,0 +1,11 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + (\Symfony\Component\VarExporter\Internal\Registry::$factories['Symfony\\Component\\VarExporter\\Tests\\FinalStdClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::f('Symfony\\Component\\VarExporter\\Tests\\FinalStdClass'))(), + ], + null, + [], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/hard-references-recursive.php b/vendor/symfony/var-exporter/Tests/Fixtures/hard-references-recursive.php new file mode 100644 index 0000000000..e62d0f2aa2 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/hard-references-recursive.php @@ -0,0 +1,16 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [], + [ + $r = [], + $r[1] = [ + &$r[1], + ], + ], + [], + [ + &$r[1], + ], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/hard-references.php b/vendor/symfony/var-exporter/Tests/Fixtures/hard-references.php new file mode 100644 index 0000000000..3ddbb41d26 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/hard-references.php @@ -0,0 +1,18 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['stdClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('stdClass')), + ], + [ + $r = [], + $r[1] = $o[0], + ], + [], + [ + &$r[1], + &$r[1], + $o[0], + ], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/incomplete-class.php b/vendor/symfony/var-exporter/Tests/Fixtures/incomplete-class.php new file mode 100644 index 0000000000..c381f5242b --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/incomplete-class.php @@ -0,0 +1,11 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ + 'O:20:"SomeNotExistingClass":0:{}', + ]), + null, + [], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/multiline-string.php b/vendor/symfony/var-exporter/Tests/Fixtures/multiline-string.php new file mode 100644 index 0000000000..540fef0002 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/multiline-string.php @@ -0,0 +1,8 @@ +<?php + +return [ + "\0\0\r\n" + .'A' => 'B'."\r" + .'C'."\n" + ."\n", +]; diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/private.php b/vendor/symfony/var-exporter/Tests/Fixtures/private.php new file mode 100644 index 0000000000..a9e28416e5 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/private.php @@ -0,0 +1,26 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (($p = &\Symfony\Component\VarExporter\Internal\Registry::$prototypes)['Symfony\\Component\\VarExporter\\Tests\\MyPrivateValue'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyPrivateValue')), + clone ($p['Symfony\\Component\\VarExporter\\Tests\\MyPrivateChildValue'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyPrivateChildValue')), + ], + null, + [ + 'Symfony\\Component\\VarExporter\\Tests\\MyPrivateValue' => [ + 'prot' => [ + 123, + 123, + ], + 'priv' => [ + 234, + 234, + ], + ], + ], + [ + $o[0], + $o[1], + ], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/serializable.php b/vendor/symfony/var-exporter/Tests/Fixtures/serializable.php new file mode 100644 index 0000000000..fcf32278b0 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/serializable.php @@ -0,0 +1,14 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = \Symfony\Component\VarExporter\Internal\Registry::unserialize([], [ + 'C:50:"Symfony\\Component\\VarExporter\\Tests\\MySerializable":3:{123}', + ]), + null, + [], + [ + $o[0], + $o[0], + ], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/simple-array.php b/vendor/symfony/var-exporter/Tests/Fixtures/simple-array.php new file mode 100644 index 0000000000..50bb70dbe2 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/simple-array.php @@ -0,0 +1,8 @@ +<?php + +return [ + 123, + [ + 'abc', + ], +]; diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/spl-object-storage.php b/vendor/symfony/var-exporter/Tests/Fixtures/spl-object-storage.php new file mode 100644 index 0000000000..5e854a4959 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/spl-object-storage.php @@ -0,0 +1,21 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (($p = &\Symfony\Component\VarExporter\Internal\Registry::$prototypes)['SplObjectStorage'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('SplObjectStorage')), + clone ($p['stdClass'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('stdClass')), + ], + null, + [ + 'SplObjectStorage' => [ + "\0" => [ + [ + $o[1], + 345, + ], + ], + ], + ], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/var-on-sleep.php b/vendor/symfony/var-exporter/Tests/Fixtures/var-on-sleep.php new file mode 100644 index 0000000000..9fd44bd590 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/var-on-sleep.php @@ -0,0 +1,17 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\GoodNight'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\GoodNight')), + ], + null, + [ + 'stdClass' => [ + 'good' => [ + 'night', + ], + ], + ], + $o[0], + [] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/wakeup-refl.php b/vendor/symfony/var-exporter/Tests/Fixtures/wakeup-refl.php new file mode 100644 index 0000000000..1fee610a49 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/wakeup-refl.php @@ -0,0 +1,13 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (\Symfony\Component\VarExporter\Internal\Registry::$prototypes['Symfony\\Component\\VarExporter\\Tests\\MyWakeup'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyWakeup')), + ], + null, + [], + $o[0], + [ + 1 => 0, + ] +); diff --git a/vendor/symfony/var-exporter/Tests/Fixtures/wakeup.php b/vendor/symfony/var-exporter/Tests/Fixtures/wakeup.php new file mode 100644 index 0000000000..89d4cebb5a --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/Fixtures/wakeup.php @@ -0,0 +1,25 @@ +<?php + +return \Symfony\Component\VarExporter\Internal\Hydrator::hydrate( + $o = [ + clone (($p = &\Symfony\Component\VarExporter\Internal\Registry::$prototypes)['Symfony\\Component\\VarExporter\\Tests\\MyWakeup'] ?? \Symfony\Component\VarExporter\Internal\Registry::p('Symfony\\Component\\VarExporter\\Tests\\MyWakeup')), + clone $p['Symfony\\Component\\VarExporter\\Tests\\MyWakeup'], + ], + null, + [ + 'stdClass' => [ + 'sub' => [ + $o[1], + 123, + ], + 'baz' => [ + 1 => 123, + ], + ], + ], + $o[0], + [ + 1 => 1, + 0, + ] +); diff --git a/vendor/symfony/var-exporter/Tests/InstantiatorTest.php b/vendor/symfony/var-exporter/Tests/InstantiatorTest.php new file mode 100644 index 0000000000..2cb8e7a359 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/InstantiatorTest.php @@ -0,0 +1,75 @@ +<?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\VarExporter\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarExporter\Instantiator; + +class InstantiatorTest extends TestCase +{ + /** + * @expectedException \Symfony\Component\VarExporter\Exception\ClassNotFoundException + * @expectedExceptionMessage Class "SomeNotExistingClass" not found. + */ + public function testNotFoundClass() + { + Instantiator::instantiate('SomeNotExistingClass'); + } + + /** + * @dataProvider provideFailingInstantiation + * @expectedException \Symfony\Component\VarExporter\Exception\NotInstantiableTypeException + * @expectedExceptionMessageRegexp Type ".*" is not instantiable. + */ + public function testFailingInstantiation(string $class) + { + Instantiator::instantiate($class); + } + + public function provideFailingInstantiation() + { + yield array('ReflectionClass'); + yield array('SplHeap'); + yield array('Throwable'); + yield array('Closure'); + yield array('SplFileInfo'); + } + + public function testInstantiate() + { + $this->assertEquals((object) array('p' => 123), Instantiator::instantiate('stdClass', array('p' => 123))); + $this->assertEquals((object) array('p' => 123), Instantiator::instantiate('STDcLASS', array('p' => 123))); + $this->assertEquals(new \ArrayObject(array(123)), Instantiator::instantiate(\ArrayObject::class, array("\0" => array(array(123))))); + + $expected = array( + "\0".__NAMESPACE__."\Bar\0priv" => 123, + "\0".__NAMESPACE__."\Foo\0priv" => 234, + ); + + $this->assertSame($expected, (array) Instantiator::instantiate(Bar::class, array('priv' => 123), array(Foo::class => array('priv' => 234)))); + + $e = Instantiator::instantiate('Exception', array('foo' => 123, 'trace' => array(234))); + + $this->assertSame(123, $e->foo); + $this->assertSame(array(234), $e->getTrace()); + } +} + +class Foo +{ + private $priv; +} + +class Bar extends Foo +{ + private $priv; +} diff --git a/vendor/symfony/var-exporter/Tests/VarExporterTest.php b/vendor/symfony/var-exporter/Tests/VarExporterTest.php new file mode 100644 index 0000000000..f509617686 --- /dev/null +++ b/vendor/symfony/var-exporter/Tests/VarExporterTest.php @@ -0,0 +1,322 @@ +<?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\VarExporter\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\VarDumper\Test\VarDumperTestTrait; +use Symfony\Component\VarExporter\Internal\Registry; +use Symfony\Component\VarExporter\VarExporter; + +class VarExporterTest extends TestCase +{ + use VarDumperTestTrait; + + /** + * @expectedException \Symfony\Component\VarExporter\Exception\ClassNotFoundException + * @expectedExceptionMessage Class "SomeNotExistingClass" not found. + */ + public function testPhpIncompleteClassesAreForbidden() + { + $unserializeCallback = ini_set('unserialize_callback_func', 'var_dump'); + try { + Registry::unserialize(array(), array('O:20:"SomeNotExistingClass":0:{}')); + } finally { + $this->assertSame('var_dump', ini_set('unserialize_callback_func', $unserializeCallback)); + } + } + + /** + * @dataProvider provideFailingSerialization + * @expectedException \Symfony\Component\VarExporter\Exception\NotInstantiableTypeException + * @expectedExceptionMessageRegexp Type ".*" is not instantiable. + */ + public function testFailingSerialization($value) + { + $expectedDump = $this->getDump($value); + try { + VarExporter::export($value); + } finally { + $this->assertDumpEquals(rtrim($expectedDump), $value); + } + } + + public function provideFailingSerialization() + { + yield array(hash_init('md5')); + yield array(new \ReflectionClass('stdClass')); + yield array((new \ReflectionFunction(function (): int {}))->getReturnType()); + yield array(new \ReflectionGenerator((function () { yield 123; })())); + yield array(function () {}); + yield array(function () { yield 123; }); + yield array(new \SplFileInfo(__FILE__)); + yield array($h = fopen(__FILE__, 'r')); + yield array(array($h)); + + $a = new class() { + }; + + yield array($a); + + $a = array(null, $h); + $a[0] = &$a; + + yield array($a); + } + + /** + * @dataProvider provideExport + */ + public function testExport(string $testName, $value, bool $staticValueExpected = false) + { + $dumpedValue = $this->getDump($value); + $isStaticValue = true; + $marshalledValue = VarExporter::export($value, $isStaticValue); + + $this->assertSame($staticValueExpected, $isStaticValue); + if ('var-on-sleep' !== $testName) { + $this->assertDumpEquals($dumpedValue, $value); + } + + $dump = "<?php\n\nreturn ".$marshalledValue.";\n"; + $dump = str_replace(var_export(__FILE__, true), "\\dirname(__DIR__).\\DIRECTORY_SEPARATOR.'VarExporterTest.php'", $dump); + $fixtureFile = __DIR__.'/Fixtures/'.$testName.'.php'; + $this->assertStringEqualsFile($fixtureFile, $dump); + + if ('incomplete-class' === $testName || 'external-references' === $testName) { + return; + } + $marshalledValue = include $fixtureFile; + + if (!$isStaticValue) { + if ($value instanceof MyWakeup) { + $value->bis = null; + } + $this->assertDumpEquals($value, $marshalledValue); + } else { + $this->assertSame($value, $marshalledValue); + } + } + + public function provideExport() + { + yield array('multiline-string', array("\0\0\r\nA" => "B\rC\n\n"), true); + + yield array('bool', true, true); + yield array('simple-array', array(123, array('abc')), true); + yield array('datetime', \DateTime::createFromFormat('U', 0)); + + $value = new \ArrayObject(); + $value[0] = 1; + $value->foo = new \ArrayObject(); + $value[1] = $value; + + yield array('array-object', $value); + + yield array('array-iterator', new \ArrayIterator(array(123), 1)); + yield array('array-object-custom', new MyArrayObject(array(234))); + + $value = new MySerializable(); + + yield array('serializable', array($value, $value)); + + $value = new MyWakeup(); + $value->sub = new MyWakeup(); + $value->sub->sub = 123; + $value->sub->bis = 123; + $value->sub->baz = 123; + + yield array('wakeup', $value); + + yield array('clone', array(new MyCloneable(), new MyNotCloneable())); + + yield array('private', array(new MyPrivateValue(123, 234), new MyPrivateChildValue(123, 234))); + + $value = new \SplObjectStorage(); + $value[new \stdClass()] = 345; + + yield array('spl-object-storage', $value); + + yield array('incomplete-class', unserialize('O:20:"SomeNotExistingClass":0:{}')); + + $value = array((object) array()); + $value[1] = &$value[0]; + $value[2] = $value[0]; + + yield array('hard-references', $value); + + $value = array(); + $value[0] = &$value; + + yield array('hard-references-recursive', $value); + + static $value = array(123); + + yield array('external-references', array(&$value), true); + + unset($value); + + $value = new \Error(); + + $rt = new \ReflectionProperty('Error', 'trace'); + $rt->setAccessible(true); + $rt->setValue($value, array('file' => __FILE__, 'line' => 123)); + + $rl = new \ReflectionProperty('Error', 'line'); + $rl->setAccessible(true); + $rl->setValue($value, 234); + + yield array('error', $value); + + yield array('var-on-sleep', new GoodNight()); + + $value = new FinalError(false); + $rt->setValue($value, array()); + $rl->setValue($value, 123); + + yield array('final-error', $value); + + yield array('final-array-iterator', new FinalArrayIterator()); + + yield array('final-stdclass', new FinalStdClass()); + + $value = new MyWakeup(); + $value->bis = new \ReflectionClass($value); + + yield array('wakeup-refl', $value); + } +} + +class MySerializable implements \Serializable +{ + public function serialize() + { + return '123'; + } + + public function unserialize($data) + { + // no-op + } +} + +class MyWakeup +{ + public $sub; + public $bis; + public $baz; + public $def = 234; + + public function __sleep() + { + return array('sub', 'baz'); + } + + public function __wakeup() + { + if (123 === $this->sub) { + $this->bis = 123; + $this->baz = 123; + } + } +} + +class MyCloneable +{ + public function __clone() + { + throw new \Exception('__clone should never be called'); + } +} + +class MyNotCloneable +{ + private function __clone() + { + throw new \Exception('__clone should never be called'); + } +} + +class MyPrivateValue +{ + protected $prot; + private $priv; + + public function __construct($prot, $priv) + { + $this->prot = $prot; + $this->priv = $priv; + } +} + +class MyPrivateChildValue extends MyPrivateValue +{ +} + +class MyArrayObject extends \ArrayObject +{ + private $unused = 123; + + public function __construct(array $array) + { + parent::__construct($array, 1); + } + + public function setFlags($flags) + { + throw new \BadMethodCallException('Calling MyArrayObject::setFlags() is forbidden'); + } +} + +class GoodNight +{ + public function __sleep() + { + $this->good = 'night'; + + return array('good'); + } +} + +final class FinalError extends \Error +{ + public function __construct(bool $throw = true) + { + if ($throw) { + throw new \BadMethodCallException('Should not be called.'); + } + } +} + +final class FinalArrayIterator extends \ArrayIterator +{ + public function serialize() + { + return serialize(array(123, parent::serialize())); + } + + public function unserialize($data) + { + if ('' === $data) { + throw new \InvalidArgumentException('Serialized data is empty.'); + } + list(, $data) = unserialize($data); + parent::unserialize($data); + } +} + +final class FinalStdClass extends \stdClass +{ + public function __clone() + { + throw new \BadMethodCallException('Should not be called.'); + } +} diff --git a/vendor/symfony/var-exporter/VarExporter.php b/vendor/symfony/var-exporter/VarExporter.php new file mode 100644 index 0000000000..ffe44a3db1 --- /dev/null +++ b/vendor/symfony/var-exporter/VarExporter.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\VarExporter; + +use Symfony\Component\VarExporter\Exception\ExceptionInterface; +use Symfony\Component\VarExporter\Internal\Exporter; +use Symfony\Component\VarExporter\Internal\Hydrator; +use Symfony\Component\VarExporter\Internal\Registry; +use Symfony\Component\VarExporter\Internal\Values; + +/** + * Exports serializable PHP values to PHP code. + * + * VarExporter allows serializing PHP data structures to plain PHP code (like var_export()) + * while preserving all the semantics associated with serialize() (unlike var_export()). + * + * By leveraging OPcache, the generated PHP code is faster than doing the same with unserialize(). + * + * @author Nicolas Grekas <p@tchwork.com> + */ +final class VarExporter +{ + /** + * Exports a serializable PHP value to PHP code. + * + * @param mixed $value The value to export + * @param bool &$isStaticValue Set to true after execution if the provided value is static, false otherwise + * + * @return string The value exported as PHP code + * + * @throws ExceptionInterface When the provided value cannot be serialized + */ + public static function export($value, bool &$isStaticValue = null): string + { + $isStaticValue = true; + + if (!\is_object($value) && !(\is_array($value) && $value) && !$value instanceof \__PHP_Incomplete_Class && !\is_resource($value)) { + return Exporter::export($value); + } + + $objectsPool = new \SplObjectStorage(); + $refsPool = array(); + $objectsCount = 0; + + try { + $value = Exporter::prepare(array($value), $objectsPool, $refsPool, $objectsCount, $isStaticValue)[0]; + } finally { + $references = array(); + foreach ($refsPool as $i => $v) { + if ($v[0]->count) { + $references[1 + $i] = $v[2]; + } + $v[0] = $v[1]; + } + } + + if ($isStaticValue) { + return Exporter::export($value); + } + + $classes = array(); + $values = array(); + $wakeups = array(); + foreach ($objectsPool as $i => $v) { + list(, $classes[], $values[], $wakeup) = $objectsPool[$v]; + if ($wakeup) { + $wakeups[$wakeup] = $i; + } + } + ksort($wakeups); + + $properties = array(); + foreach ($values as $i => $vars) { + foreach ($vars as $class => $values) { + foreach ($values as $name => $v) { + $properties[$class][$name][$i] = $v; + } + } + } + + if ($classes || $references) { + $value = new Hydrator(new Registry($classes), $references ? new Values($references) : null, $properties, $value, $wakeups); + } else { + $isStaticValue = true; + } + + return Exporter::export($value); + } +} diff --git a/vendor/symfony/var-exporter/composer.json b/vendor/symfony/var-exporter/composer.json new file mode 100644 index 0000000000..b982d3bfd7 --- /dev/null +++ b/vendor/symfony/var-exporter/composer.json @@ -0,0 +1,36 @@ +{ + "name": "symfony/var-exporter", + "type": "library", + "description": "A blend of var_export() + serialize() to turn any serializable data structure to plain PHP code", + "keywords": ["export", "serialize", "instantiate", "hydrate", "construct", "clone"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": "^7.1.3" + }, + "require-dev": { + "symfony/var-dumper": "^4.1.1" + }, + "autoload": { + "psr-4": { "Symfony\\Component\\VarExporter\\": "" }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "minimum-stability": "dev", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + } +} diff --git a/vendor/symfony/var-exporter/phpunit.xml.dist b/vendor/symfony/var-exporter/phpunit.xml.dist new file mode 100644 index 0000000000..96e2110022 --- /dev/null +++ b/vendor/symfony/var-exporter/phpunit.xml.dist @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd" + backupGlobals="false" + colors="true" + bootstrap="vendor/autoload.php" + failOnRisky="true" + failOnWarning="true" +> + <php> + <ini name="error_reporting" value="-1" /> + </php> + + <testsuites> + <testsuite name="Symfony VarExporter Component Test Suite"> + <directory>./Tests/</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>./</directory> + <exclude> + <directory>./Resources</directory> + <directory>./Tests</directory> + <directory>./vendor</directory> + </exclude> + </whitelist> + </filter> +</phpunit> diff --git a/vendor/webuni/commonmark-table-extension/composer.json b/vendor/webuni/commonmark-table-extension/composer.json index 32493e0fe4..bd22350961 100644 --- a/vendor/webuni/commonmark-table-extension/composer.json +++ b/vendor/webuni/commonmark-table-extension/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^5.6|^7.0", - "league/commonmark": "^0.16|^0.17" + "league/commonmark": "^0.16|^0.17|^0.18" }, "require-dev": { "phpunit/phpunit": "^5.4|^6.0", @@ -32,7 +32,7 @@ }, "extra": { "branch-alias": { - "dev-master": "0.8-dev" + "dev-master": "0.9-dev" } } } |
