From b30f4c1537147cc592374b6ef635a337fe476be5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 12 Jun 2020 13:14:22 +0200 Subject: [PATCH 01/59] bumped Symfony version to 3.4.43 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 1f0e29b97cef5..7fad1ee281311 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.42'; - const VERSION_ID = 30442; + const VERSION = '3.4.43-DEV'; + const VERSION_ID = 30443; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 42; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 43; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From fcc0e2c143caba8cf5ff0dda363af7e60d1be92f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 13 Jun 2020 17:55:52 +0200 Subject: [PATCH 02/59] [FrameworkBundle] preserve dots in query-string when redirecting --- .../Controller/RedirectController.php | 3 +- .../Controller/RedirectControllerTest.php | 43 ++++++++----------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php index 244e8a0f355a3..05e39a27a0a6a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/RedirectController.php @@ -128,8 +128,7 @@ public function urlRedirectAction(Request $request, $path, $permanent = false, $ $scheme = $request->getScheme(); } - $qs = $request->getQueryString(); - if ($qs) { + if ($qs = $request->server->get('QUERY_STRING') ?: $request->getQueryString()) { if (false === strpos($path, '?')) { $qs = '?'.$qs; } else { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 4bd0212e6953d..78d41a2f2bc7e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -220,9 +220,9 @@ public function pathQueryParamsProvider() return [ ['http://www.example.com/base/redirect-path', '/redirect-path', ''], ['http://www.example.com/base/redirect-path?foo=bar', '/redirect-path?foo=bar', ''], - ['http://www.example.com/base/redirect-path?foo=bar', '/redirect-path', 'foo=bar'], - ['http://www.example.com/base/redirect-path?foo=bar&abc=example', '/redirect-path?foo=bar', 'abc=example'], - ['http://www.example.com/base/redirect-path?foo=bar&abc=example&baz=def', '/redirect-path?foo=bar', 'abc=example&baz=def'], + ['http://www.example.com/base/redirect-path?f.o=bar', '/redirect-path', 'f.o=bar'], + ['http://www.example.com/base/redirect-path?f.o=bar&a.c=example', '/redirect-path?f.o=bar', 'a.c=example'], + ['http://www.example.com/base/redirect-path?f.o=bar&a.c=example&b.z=def', '/redirect-path?f.o=bar', 'a.c=example&b.z=def'], ]; } @@ -246,29 +246,20 @@ public function testPathQueryParams($expectedUrl, $path, $queryString) private function createRequestObject($scheme, $host, $port, $baseUrl, $queryString = '') { - $request = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock(); - $request - ->expects($this->any()) - ->method('getScheme') - ->willReturn($scheme); - $request - ->expects($this->any()) - ->method('getHost') - ->willReturn($host); - $request - ->expects($this->any()) - ->method('getPort') - ->willReturn($port); - $request - ->expects($this->any()) - ->method('getBaseUrl') - ->willReturn($baseUrl); - $request - ->expects($this->any()) - ->method('getQueryString') - ->willReturn($queryString); - - return $request; + if ('' !== $queryString) { + parse_str($queryString, $query); + } else { + $query = []; + } + + return new Request($query, [], [], [], [], [ + 'HTTPS' => 'https' === $scheme, + 'HTTP_HOST' => $host.($port ? ':'.$port : ''), + 'SERVER_PORT' => $port, + 'SCRIPT_FILENAME' => $baseUrl, + 'REQUEST_URI' => $baseUrl, + 'QUERY_STRING' => $queryString, + ]); } private function createRedirectController($httpPort = null, $httpsPort = null) From b746dd900cf50a545064e51f5178be8e0b2aab4c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 14 Jun 2020 14:27:25 +0200 Subject: [PATCH 03/59] [DI] tighten detection of local dirs to prevent false positives --- .../Component/DependencyInjection/Dumper/PhpDumper.php | 7 ++++--- .../DependencyInjection/Tests/Dumper/PhpDumperTest.php | 2 +- .../DependencyInjection/Tests/Fixtures/php/services12.php | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 3bfa0c318891e..c66c3bcf7c2cc 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -191,7 +191,7 @@ public function dump(array $options = []) $regex = preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#').$regex; } while (0 < --$i); - $this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#'; + $this->targetDirRegex = '#(^|file://|[:;, \|\r\n])'.preg_quote($dir[0], '#').$regex.'#'; } } @@ -1993,11 +1993,12 @@ private function isHotPath(Definition $definition) private function export($value) { if (null !== $this->targetDirRegex && \is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) { - $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; $suffix = $matches[0][1] + \strlen($matches[0][0]); + $matches[0][1] += \strlen($matches[1][0]); + $prefix = $matches[0][1] ? $this->doExport(substr($value, 0, $matches[0][1]), true).'.' : ''; $suffix = isset($value[$suffix]) ? '.'.$this->doExport(substr($value, $suffix), true) : ''; $dirname = $this->asFiles ? '$this->containerDir' : '__DIR__'; - $offset = 1 + $this->targetDirMaxMatches - \count($matches); + $offset = 2 + $this->targetDirMaxMatches - \count($matches); if ($this->asFiles || 0 < $offset) { $dirname = sprintf('$this->targetDirs[%d]', $offset); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index b2cbb3caf6283..946d09c74852f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -98,7 +98,7 @@ public function testDumpRelativeDir() $container = new ContainerBuilder(); $container->setDefinition('test', $definition); - $container->setParameter('foo', 'wiz'.\dirname(__DIR__)); + $container->setParameter('foo', 'file://'.\dirname(__DIR__)); $container->setParameter('bar', __DIR__); $container->setParameter('baz', '%bar%/PhpDumperTest.php'); $container->setParameter('buz', \dirname(\dirname(__DIR__))); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php index 0e8f581e8ab7a..eb21559686fb1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services12.php @@ -67,7 +67,7 @@ public function isFrozen() */ protected function getTestService() { - return $this->services['test'] = new \stdClass(('wiz'.$this->targetDirs[1]), [('wiz'.$this->targetDirs[1]) => ($this->targetDirs[2].'/')]); + return $this->services['test'] = new \stdClass(('file://'.$this->targetDirs[1]), [('file://'.$this->targetDirs[1]) => ($this->targetDirs[2].'/')]); } public function getParameter($name) @@ -131,7 +131,7 @@ public function getParameterBag() private function getDynamicParameter($name) { switch ($name) { - case 'foo': $value = ('wiz'.$this->targetDirs[1]); break; + case 'foo': $value = ('file://'.$this->targetDirs[1]); break; case 'buz': $value = $this->targetDirs[2]; break; default: throw new InvalidArgumentException(sprintf('The dynamic parameter "%s" must be defined.', $name)); } From 7af34697715018bc7c6510289907e003d129e19c Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Tue, 24 Mar 2020 21:48:50 +0100 Subject: [PATCH 04/59] [VarDumper] Fix CliDumper coloration When using AbstractDumper::DUMP_LIGHT_ARRAY --- .../Component/VarDumper/Dumper/CliDumper.php | 3 +- .../VarDumper/Tests/Dumper/CliDumperTest.php | 52 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index 946df78257bae..881241ab3e878 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -268,7 +268,8 @@ public function enterHash(Cursor $cursor, $type, $class, $hasChild) } elseif (Cursor::HASH_RESOURCE === $type) { $prefix = $this->style('note', $class.' resource').($hasChild ? ' {' : ' '); } else { - $prefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? $this->style('note', 'array:'.$class).' [' : '['; + $unstyledPrefix = $class && !(self::DUMP_LIGHT_ARRAY & $this->flags) ? 'array:'.$class : ''; + $prefix = $this->style('note', $unstyledPrefix).($unstyledPrefix ? ' [' : '['); } if ($cursor->softRefCount || 0 < $cursor->softRefHandle) { diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php index 7656e09259264..e7efaae95cec3 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/CliDumperTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\AbstractDumper; use Symfony\Component\VarDumper\Dumper\CliDumper; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; use Twig\Environment; @@ -572,6 +573,57 @@ public function testIncompleteClass() ); } + public function provideDumpArrayWithColor() + { + yield [ + ['foo' => 'bar'], + 0, +<< "\e[1;38;5;113mbar\e[0;38;5;208m"\e[m +\e[0;38;5;208m]\e[m + +EOTXT + ]; + + yield [[], AbstractDumper::DUMP_LIGHT_ARRAY, "\e[0;38;5;208m\e[38;5;38m\e[0;38;5;208m[]\e[m\n"]; + + yield [ + ['foo' => 'bar'], + AbstractDumper::DUMP_LIGHT_ARRAY, + << "\e[1;38;5;113mbar\e[0;38;5;208m"\e[m +\e[0;38;5;208m]\e[m + +EOTXT + ]; + + yield [[], 0, "\e[0;38;5;208m\e[38;5;38m\e[0;38;5;208m[]\e[m\n"]; + } + + /** + * @dataProvider provideDumpArrayWithColor + */ + public function testDumpArrayWithColor($value, $flags, $expectedOut) + { + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->markTestSkipped('Windows console does not support coloration'); + } + + $out = ''; + $dumper = new CliDumper(function ($line, $depth) use (&$out) { + if ($depth >= 0) { + $out .= str_repeat(' ', $depth).$line."\n"; + } + }, null, $flags); + $dumper->setColors(true); + $cloner = new VarCloner(); + $dumper->dump($cloner->cloneVar($value)); + + $this->assertSame($expectedOut, $out); + } + private function getSpecialVars() { foreach (array_keys($GLOBALS) as $var) { From 8c4b49613ac32c238a794f987dc474ded1df4809 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 17:42:01 +0200 Subject: [PATCH 05/59] [Cache] fix compat with DBAL v3 --- .../Component/Cache/Traits/PdoTrait.php | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php index 1aa87cd3f1a11..d453904d44a81 100644 --- a/src/Symfony/Component/Cache/Traits/PdoTrait.php +++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php @@ -366,25 +366,31 @@ private function getConnection() if ($this->conn instanceof \PDO) { $this->driver = $this->conn->getAttribute(\PDO::ATTR_DRIVER_NAME); } else { - switch ($this->driver = $this->conn->getDriver()->getName()) { - case 'mysqli': - case 'pdo_mysql': - case 'drizzle_pdo_mysql': + $driver = $this->conn->getDriver(); + + switch (true) { + case $driver instanceof \Doctrine\DBAL\Driver\AbstractMySQLDriver: + case $driver instanceof \Doctrine\DBAL\Driver\DrizzlePDOMySql\Driver: + case $driver instanceof \Doctrine\DBAL\Driver\Mysqli\Driver: + case $driver instanceof \Doctrine\DBAL\Driver\PDOMySql\Driver: $this->driver = 'mysql'; break; - case 'pdo_sqlite': + case $driver instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver: $this->driver = 'sqlite'; break; - case 'pdo_pgsql': + case $driver instanceof \Doctrine\DBAL\Driver\PDOPgSql\Driver: $this->driver = 'pgsql'; break; - case 'oci8': - case 'pdo_oracle': + case $driver instanceof \Doctrine\DBAL\Driver\OCI8\Driver: + case $driver instanceof \Doctrine\DBAL\Driver\PDOOracle\Driver: $this->driver = 'oci'; break; - case 'pdo_sqlsrv': + case $driver instanceof \Doctrine\DBAL\Driver\SQLSrv\Driver: $this->driver = 'sqlsrv'; break; + default: + $this->driver = \get_class($driver); + break; } } } From c143aacd811d0cab4e3351cb77d7d3e37c031c16 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 13 Jun 2020 10:25:25 +0200 Subject: [PATCH 06/59] [3.4] Small update in our internal terminology --- .../Handler/FingersCrossed/NotFoundActivationStrategy.php | 6 +++--- .../DependencyInjection/AddAnnotatedClassesToCachePass.php | 4 ++-- .../Component/Intl/Data/Generator/CurrencyDataGenerator.php | 4 ++-- .../Component/Intl/Data/Generator/RegionDataGenerator.php | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php index ed41929a2cef3..e5ccf1afc57b4 100644 --- a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/NotFoundActivationStrategy.php @@ -23,7 +23,7 @@ */ class NotFoundActivationStrategy extends ErrorLevelActivationStrategy { - private $blacklist; + private $exclude; private $requestStack; public function __construct(RequestStack $requestStack, array $excludedUrls, $actionLevel) @@ -31,7 +31,7 @@ public function __construct(RequestStack $requestStack, array $excludedUrls, $ac parent::__construct($actionLevel); $this->requestStack = $requestStack; - $this->blacklist = '{('.implode('|', $excludedUrls).')}i'; + $this->exclude = '{('.implode('|', $excludedUrls).')}i'; } public function isHandlerActivated(array $record) @@ -45,7 +45,7 @@ public function isHandlerActivated(array $record) && 404 == $record['context']['exception']->getStatusCode() && ($request = $this->requestStack->getMasterRequest()) ) { - return !preg_match($this->blacklist, $request->getPathInfo()); + return !preg_match($this->exclude, $request->getPathInfo()); } return $isActivated; diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php index 8bb03bd0c78d0..b59949379dd07 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/AddAnnotatedClassesToCachePass.php @@ -136,10 +136,10 @@ private function patternsToRegexps($patterns) private function matchAnyRegexps($class, $regexps) { - $blacklisted = false !== strpos($class, 'Test'); + $isTest = false !== strpos($class, 'Test'); foreach ($regexps as $regex) { - if ($blacklisted && false === strpos($regex, 'Test')) { + if ($isTest && false === strpos($regex, 'Test')) { continue; } diff --git a/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php index b4543428ebb60..a5ed6d10268f2 100644 --- a/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/CurrencyDataGenerator.php @@ -25,7 +25,7 @@ */ class CurrencyDataGenerator extends AbstractDataGenerator { - private static $blacklist = [ + private static $denylist = [ 'XBA' => true, // European Composite Unit 'XBB' => true, // European Monetary Unit 'XBC' => true, // European Unit of Account (XBC) @@ -136,7 +136,7 @@ private function generateSymbolNamePairs(ArrayAccessibleResourceBundle $rootBund $symbolNamePairs = iterator_to_array($rootBundle['Currencies']); // Remove unwanted currencies - $symbolNamePairs = array_diff_key($symbolNamePairs, self::$blacklist); + $symbolNamePairs = array_diff_key($symbolNamePairs, self::$denylist); return $symbolNamePairs; } diff --git a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php index bab85b11b15d5..b50a585de6779 100644 --- a/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php @@ -27,7 +27,7 @@ */ class RegionDataGenerator extends AbstractDataGenerator { - private static $blacklist = [ + private static $denylist = [ // Look like countries, but are sub-continents 'QO' => true, // Outlying Oceania 'EU' => true, // European Union @@ -50,7 +50,7 @@ class RegionDataGenerator extends AbstractDataGenerator public static function isValidCountryCode($region) { - if (isset(self::$blacklist[$region])) { + if (isset(self::$denylist[$region])) { return false; } From 968d6c4276bb1540786bc4ba6ef2a49f913f8b10 Mon Sep 17 00:00:00 2001 From: kick-the-bucket Date: Thu, 4 Jun 2020 11:26:35 +0300 Subject: [PATCH 07/59] [PhpUnitBridge] Streamline ansi/no-ansi of composer according to phpunit --colors option --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index eae4cc3125147..90efc97658a0d 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -106,15 +106,21 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ } } + if (in_array('--colors=never', $argv, true) || (isset($argv[$i = array_search('never', $argv, true) - 1]) && '--colors' === $argv[$i])) { + $COMPOSER .= ' --no-ansi'; + } else { + $COMPOSER .= ' --ansi'; + } + $info += array( 'versions' => array(), 'requires' => array('php' => '*'), ); if (1 === \count($info['versions'])) { - $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi -s dev phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); + $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress -s dev phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); } else { - $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); + $passthruOrFail("$COMPOSER create-project --ignore-platform-reqs --no-install --prefer-dist --no-scripts --no-plugins --no-progress phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); } @copy("phpunit-$PHPUNIT_VERSION/phpunit.xsd", 'phpunit.xsd'); @@ -144,7 +150,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99"); $q = '\\' === DIRECTORY_SEPARATOR ? '"' : ''; // --no-suggest is not in the list to keep compat with composer 1.0, which is shipped with Ubuntu 16.04LTS - $exit = proc_close(proc_open("$q$COMPOSER install --no-dev --prefer-dist --no-progress --ansi$q", array(), $p, getcwd())); + $exit = proc_close(proc_open("$q$COMPOSER install --no-dev --prefer-dist --no-progress$q", array(), $p, getcwd())); putenv('COMPOSER_ROOT_VERSION'.(false !== $prevRoot ? '='.$prevRoot : '')); if ($exit) { exit($exit); From e09372bcbf3de62acf139c203f4492b6c8e41d07 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 15 Jun 2020 16:43:28 +0200 Subject: [PATCH 08/59] [3.4] Fix support for PHP8 union types --- .../Resource/ReflectionClassResource.php | 6 ++- .../LazyProxy/ProxyHelper.php | 42 ++++++++++++------- .../OptionsResolver/OptionsResolver.php | 2 +- .../PropertyAccess/PropertyAccessor.php | 3 +- .../Extractor/ReflectionExtractor.php | 42 ++++++++++--------- .../Normalizer/AbstractNormalizer.php | 2 +- .../VarDumper/Caster/ReflectionCaster.php | 6 +-- 7 files changed, 60 insertions(+), 43 deletions(-) diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index cfab1f6c10a65..294da3e10cef4 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -177,6 +177,7 @@ private function generateSignature(\ReflectionClass $class) if (!$parametersWithUndefinedConstants) { yield preg_replace('/^ @@.*/m', '', $m); } else { + $t = \PHP_VERSION_ID >= 70000 ? $m->getReturnType() : ''; $stack = [ $m->getDocComment(), $m->getName(), @@ -187,15 +188,16 @@ private function generateSignature(\ReflectionClass $class) $m->isPrivate(), $m->isProtected(), $m->returnsReference(), - \PHP_VERSION_ID >= 70000 && $m->hasReturnType() ? (\PHP_VERSION_ID >= 70100 ? $m->getReturnType()->getName() : (string) $m->getReturnType()) : '', + $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t, ]; foreach ($m->getParameters() as $p) { if (!isset($parametersWithUndefinedConstants[$p->name])) { $stack[] = (string) $p; } else { + $t = \PHP_VERSION_ID >= 70000 ? $p->getType() : ''; $stack[] = $p->isOptional(); - $stack[] = \PHP_VERSION_ID >= 70000 && $p->hasType() ? (\PHP_VERSION_ID >= 70100 ? $p->getType()->getName() : (string) $p->getType()) : ''; + $stack[] = $t instanceof \ReflectionNamedType ? $t->getName() : (string) $t; $stack[] = $p->isPassedByReference(); $stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : ''; $stack[] = $p->getName(); diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php b/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php index cb19c729c100c..bfa65f56f0a44 100644 --- a/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php +++ b/src/Symfony/Component/DependencyInjection/LazyProxy/ProxyHelper.php @@ -39,26 +39,36 @@ public static function getTypeHint(\ReflectionFunctionAbstract $r, \ReflectionPa if (!$type) { return null; } - if (!\is_string($type)) { - $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); - if ($type->isBuiltin()) { - return $noBuiltin ? null : $name; + $types = []; + + foreach ($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type] as $type) { + $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; + + if (!\is_string($type) && $type->isBuiltin()) { + if (!$noBuiltin) { + $types[] = $name; + } + continue; } - } - $lcName = strtolower($name); - $prefix = $noBuiltin ? '' : '\\'; - if ('self' !== $lcName && 'parent' !== $lcName) { - return $prefix.$name; - } - if (!$r instanceof \ReflectionMethod) { - return null; - } - if ('self' === $lcName) { - return $prefix.$r->getDeclaringClass()->name; + $lcName = strtolower($name); + $prefix = $noBuiltin ? '' : '\\'; + + if ('self' !== $lcName && 'parent' !== $lcName) { + $types[] = '' !== $prefix ? $prefix.$name : $name; + continue; + } + if (!$r instanceof \ReflectionMethod) { + continue; + } + if ('self' === $lcName) { + $types[] = $prefix.$r->getDeclaringClass()->name; + } else { + $types[] = ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null; + } } - return ($parent = $r->getDeclaringClass()->getParentClass()) ? $prefix.$parent->name : null; + return $types ? implode('|', $types) : null; } } diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 7354caf8a6fe7..ffb101e512ff8 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -1076,7 +1076,7 @@ private function getParameterClassName(\ReflectionParameter $parameter) return ($class = $parameter->getClass()) ? $class->name : null; } - if (!($type = $parameter->getType()) || $type->isBuiltin()) { + if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) { return null; } diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 99aa9a3ebc32a..07e0204cd26c0 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -519,8 +519,9 @@ private function readProperty($zval, $property) // handle uninitialized properties in PHP >= 7.4 if (\PHP_VERSION_ID >= 70400 && preg_match('/^Typed property ([\w\\\]+)::\$(\w+) must not be accessed before initialization$/', $e->getMessage(), $matches)) { $r = new \ReflectionProperty($matches[1], $matches[2]); + $type = ($type = $r->getType()) instanceof \ReflectionNamedType ? $type->getName() : (string) $type; - throw new AccessException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $r->getType()->getName()), 0, $e); + throw new AccessException(sprintf('The property "%s::$%s" is not readable because it is typed "%s". You should initialize it or declare a default value instead.', $r->getDeclaringClass()->getName(), $r->getName(), $type), 0, $e); } throw $e; diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 3306946a9b337..cbcb349d2e110 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -187,26 +187,26 @@ private function extractFromMutator($class, $property) $type = $this->extractFromReflectionType($reflectionType, $reflectionMethod); // HHVM reports variadics with "array" but not builtin type hints - if (!$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type->getBuiltinType()) { + if (1 === \count($type) && !$reflectionType->isBuiltin() && Type::BUILTIN_TYPE_ARRAY === $type[0]->getBuiltinType()) { return null; } } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $reflectionParameter, $info)) { if (Type::BUILTIN_TYPE_ARRAY === $info[1]) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true); + $type = [new Type(Type::BUILTIN_TYPE_ARRAY, $reflectionParameter->allowsNull(), null, true)]; } elseif (Type::BUILTIN_TYPE_CALLABLE === $info[1]) { - $type = new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull()); + $type = [new Type(Type::BUILTIN_TYPE_CALLABLE, $reflectionParameter->allowsNull())]; } else { - $type = new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod)); + $type = [new Type(Type::BUILTIN_TYPE_OBJECT, $reflectionParameter->allowsNull(), $this->resolveTypeName($info[1], $reflectionMethod))]; } } else { return null; } - if (\in_array($prefix, $this->arrayMutatorPrefixes)) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type); + if (1 === \count($type) && \in_array($prefix, $this->arrayMutatorPrefixes)) { + $type = [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), $type[0])]; } - return [$type]; + return $type; } /** @@ -225,7 +225,7 @@ private function extractFromAccessor($class, $property) } if ($this->supportsParameterType && $reflectionType = $reflectionMethod->getReturnType()) { - return [$this->extractFromReflectionType($reflectionType, $reflectionMethod)]; + return $this->extractFromReflectionType($reflectionType, $reflectionMethod); } return \in_array($prefix, ['is', 'can']) ? [new Type(Type::BUILTIN_TYPE_BOOL)] : null; @@ -234,24 +234,28 @@ private function extractFromAccessor($class, $property) /** * Extracts data from the PHP 7 reflection type. * - * @return Type + * @return Type[] */ private function extractFromReflectionType(\ReflectionType $reflectionType, \ReflectionMethod $reflectionMethod) { - $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : $reflectionType->__toString(); + $types = []; $nullable = $reflectionType->allowsNull(); - if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { - $type = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); - } elseif ('void' === $phpTypeOrClass) { - $type = new Type(Type::BUILTIN_TYPE_NULL, $nullable); - } elseif ($reflectionType->isBuiltin()) { - $type = new Type($phpTypeOrClass, $nullable); - } else { - $type = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) { + $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; + + if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { + $types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); + } elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) { + $types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable); + } elseif ($reflectionType->isBuiltin()) { + $types[] = new Type($phpTypeOrClass, $nullable); + } else { + $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); + } } - return $type; + return $types; } private function resolveTypeName($name, \ReflectionMethod $reflectionMethod) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 71b1e38d37bd4..e88b5a2110b8b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -388,7 +388,7 @@ protected function denormalizeParameter(\ReflectionClass $class, \ReflectionPara try { if (\PHP_VERSION_ID < 70100 && null !== $parameterClass = $parameter->getClass()) { $parameterClass = $parameterClass->name; - } elseif (\PHP_VERSION_ID >= 70100 && ($parameterType = $parameter->getType()) && !$parameterType->isBuiltin()) { + } elseif (\PHP_VERSION_ID >= 70100 && ($parameterType = $parameter->getType()) instanceof \ReflectionNamedType && !$parameterType->isBuiltin()) { $parameterClass = $parameterType->getName(); new \ReflectionClass($parameterClass); // throws a \ReflectionException if the class doesn't exist } else { diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index 067da6bbd3d9d..31de78e961db0 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -91,7 +91,7 @@ public static function castType(\ReflectionType $c, array $a, Stub $stub, $isNes $prefix = Caster::PREFIX_VIRTUAL; $a += [ - $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : $c->__toString(), + $prefix.'name' => $c instanceof \ReflectionNamedType ? $c->getName() : (string) $c, $prefix.'allowsNull' => $c->allowsNull(), $prefix.'isBuiltin' => $c->isBuiltin(), ]; @@ -178,7 +178,7 @@ public static function castFunctionAbstract(\ReflectionFunctionAbstract $c, arra if (isset($a[$prefix.'returnType'])) { $v = $a[$prefix.'returnType']; - $v = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); + $v = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; $a[$prefix.'returnType'] = new ClassStub($a[$prefix.'returnType']->allowsNull() ? '?'.$v : $v, [class_exists($v, false) || interface_exists($v, false) || trait_exists($v, false) ? $v : '', '']); } if (isset($a[$prefix.'class'])) { @@ -247,7 +247,7 @@ public static function castParameter(\ReflectionParameter $c, array $a, Stub $st if (method_exists($c, 'getType')) { if ($v = $c->getType()) { - $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : $v->__toString(); + $a[$prefix.'typeHint'] = $v instanceof \ReflectionNamedType ? $v->getName() : (string) $v; } } elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $c, $v)) { $a[$prefix.'typeHint'] = $v[1]; From 8bbbdbe74576639224d7019d90d80f4f2a4b5737 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 18 Jun 2020 21:30:53 +0200 Subject: [PATCH 09/59] Fix --- .../Component/Config/Resource/ReflectionClassResource.php | 2 +- .../DependencyInjection/Compiler/FactoryReturnTypePass.php | 2 +- .../HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php | 2 +- src/Symfony/Component/OptionsResolver/OptionsResolver.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index 294da3e10cef4..79b21fbf4c218 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -197,7 +197,7 @@ private function generateSignature(\ReflectionClass $class) } else { $t = \PHP_VERSION_ID >= 70000 ? $p->getType() : ''; $stack[] = $p->isOptional(); - $stack[] = $t instanceof \ReflectionNamedType ? $t->getName() : (string) $t; + $stack[] = $t instanceof \ReflectionNamedType ? ((string) $t->allowsNull()).$t->getName() : (string) $t; $stack[] = $p->isPassedByReference(); $stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : ''; $stack[] = $p->getName(); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php b/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php index d688fb59fd1fd..6b1277e26a6bc 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/FactoryReturnTypePass.php @@ -93,7 +93,7 @@ private function updateDefinition(ContainerBuilder $container, $id, Definition $ $returnType = $m->getReturnType(); if (null !== $returnType && !$returnType->isBuiltin()) { - $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString(); + $returnType = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : (string) $returnType; if (null !== $class) { $declaringClass = $m->getDeclaringClass()->getName(); if ('self' === strtolower($returnType)) { diff --git a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php index 2548a2a083c39..14e7ca3d11405 100644 --- a/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php +++ b/src/Symfony/Component/HttpKernel/ControllerMetadata/ArgumentMetadataFactory.php @@ -105,7 +105,7 @@ private function getType(\ReflectionParameter $parameter, \ReflectionFunctionAbs if (!$type = $parameter->getType()) { return null; } - $name = $type instanceof \ReflectionNamedType ? $type->getName() : $type->__toString(); + $name = $type instanceof \ReflectionNamedType ? $type->getName() : (string) $type; if ('array' === $name && !$type->isBuiltin()) { // Special case for HHVM with variadics return null; diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index ffb101e512ff8..7354caf8a6fe7 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -1076,7 +1076,7 @@ private function getParameterClassName(\ReflectionParameter $parameter) return ($class = $parameter->getClass()) ? $class->name : null; } - if (!($type = $parameter->getType()) instanceof \ReflectionNamedType || $type->isBuiltin()) { + if (!($type = $parameter->getType()) || $type->isBuiltin()) { return null; } From 2ca8ecdb7461377ffc1a572d9e80c64bdd1eb70a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 18 Jun 2020 22:18:19 +0200 Subject: [PATCH 10/59] Added Unit tests for php 8 union types. --- .../Tests/Compiler/AutowirePassTest.php | 68 +++++++++++++++++++ .../Fixtures/includes/autowiring_classes.php | 4 ++ .../Fixtures/includes/uniontype_classes.php | 24 +++++++ .../Extractor/ReflectionExtractor.php | 7 +- .../Extractor/ReflectionExtractorTest.php | 20 ++++++ .../Tests/Fixtures/Php80Dummy.php | 26 +++++++ 6 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index e11154889c297..2482db631403b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -254,6 +254,25 @@ public function testTypeNotGuessableNoServicesFound() $pass->process($container); } + /** + * @requires PHP 8 + */ + public function testTypeNotGuessableUnionType() + { + $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); + $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\UnionClasses::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA|Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB" but this class was not found.'); + $container = new ContainerBuilder(); + + $container->register(CollisionA::class); + $container->register(CollisionB::class); + + $aDefinition = $container->register('a', UnionClasses::class); + $aDefinition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + } + public function testTypeNotGuessableWithTypeSet() { $container = new ContainerBuilder(); @@ -350,6 +369,40 @@ public function testOptionalParameter() $this->assertEquals(Foo::class, $definition->getArgument(2)); } + /** + * @requires PHP 8 + */ + public function testParameterWithNullUnionIsSkipped() + { + $container = new ContainerBuilder(); + + $optDefinition = $container->register('opt', UnionNull::class); + $optDefinition->setAutowired(true); + + (new AutowirePass())->process($container); + + $definition = $container->getDefinition('opt'); + $this->assertNull($definition->getArgument(0)); + } + + /** + * @requires PHP 8 + */ + public function testParameterWithNullUnionIsAutowired() + { + $container = new ContainerBuilder(); + + $container->register(CollisionInterface::class, CollisionA::class); + + $optDefinition = $container->register('opt', UnionNull::class); + $optDefinition->setAutowired(true); + + (new AutowirePass())->process($container); + + $definition = $container->getDefinition('opt'); + $this->assertEquals(CollisionInterface::class, $definition->getArgument(0)); + } + public function testDontTriggerAutowiring() { $container = new ContainerBuilder(); @@ -459,6 +512,21 @@ public function testScalarArgsCannotBeAutowired() (new AutowirePass())->process($container); } + /** + * @requires PHP 8 + */ + public function testUnionScalarArgsCannotBeAutowired() + { + $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); + $this->expectExceptionMessage('Cannot autowire service "union_scalars": argument "$timeout" of method "Symfony\Component\DependencyInjection\Tests\Compiler\UnionScalars::__construct()" is type-hinted "int|float", you should configure its value explicitly.'); + $container = new ContainerBuilder(); + + $container->register('union_scalars', UnionScalars::class) + ->setAutowired(true); + + (new AutowirePass())->process($container); + } + public function testNoTypeArgsCannotBeAutowired() { $this->expectException('Symfony\Component\DependencyInjection\Exception\AutowiringFailedException'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php index 8db7edf1a126e..42545c9c2b71c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php @@ -2,6 +2,10 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; +if (PHP_VERSION_ID >= 80000) { + require __DIR__.'/uniontype_classes.php'; +} + class Foo { } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php new file mode 100644 index 0000000000000..3a0c77c53941c --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php @@ -0,0 +1,24 @@ +getTypes() : [$reflectionType] as $type) { $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type; + if ('null' === $phpTypeOrClass) { + continue; + } if (Type::BUILTIN_TYPE_ARRAY === $phpTypeOrClass) { $types[] = new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true); - } elseif ('void' === $phpTypeOrClass || 'null' === $phpTypeOrClass) { + } elseif ('void' === $phpTypeOrClass) { $types[] = new Type(Type::BUILTIN_TYPE_NULL, $nullable); - } elseif ($reflectionType->isBuiltin()) { + } elseif ($type->isBuiltin()) { $types[] = new Type($phpTypeOrClass, $nullable); } else { $types[] = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $this->resolveTypeName($phpTypeOrClass, $reflectionMethod)); diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index 36fc9d55e37f8..bac036aa5bf90 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -204,6 +204,26 @@ public function php71TypesProvider() ]; } + /** + * @dataProvider php80TypesProvider + * @requires PHP 8 + */ + public function testExtractPhp80Type($property, array $type = null) + { + $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy', $property, [])); + } + + public function php80TypesProvider() + { + return [ + ['foo', [new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)]], + ['bar', [new Type(Type::BUILTIN_TYPE_INT, true)]], + ['timeout', [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_FLOAT)]], + ['optional', [new Type(Type::BUILTIN_TYPE_INT, true), new Type(Type::BUILTIN_TYPE_FLOAT, true)]], + ['string', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Stringable'), new Type(Type::BUILTIN_TYPE_STRING)]], + ]; + } + /** * @dataProvider getReadableProperties */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php new file mode 100644 index 0000000000000..484498f4a6c0e --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php80Dummy.php @@ -0,0 +1,26 @@ + Date: Thu, 18 Jun 2020 21:22:57 +0200 Subject: [PATCH 11/59] collect all transformation failures --- .../Validator/Constraints/FormValidator.php | 5 +- .../FormValidatorFunctionalTest.php | 60 +++++++++++++++++++ .../Constraints/FormValidatorTest.php | 34 ----------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 4447b2e54aa88..8f7acb35d86b7 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -147,7 +147,10 @@ public function validate($form, Constraint $formConstraint) foreach ($form as $child) { if (!$child->isSynchronized()) { $childrenSynchronized = false; - break; + + $fieldFormConstraint = new Form(); + $this->context->setNode($this->context->getValue(), $child, $this->context->getMetadata(), $this->context->getPropertyPath()); + $validator->atPath(sprintf('children[%s]', $child->getName()))->validate($child, $fieldFormConstraint); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php index b51b34bb32ab0..d4ca0cb1bfe21 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php @@ -13,6 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; @@ -329,6 +332,63 @@ public function testContextIsPopulatedWithFormBeingValidatedUsingGroupSequence() $this->assertCount(0, $violations); } + + public function testSubmitFormChoiceInvalid() + { + $form = $this->formFactory->create(DateType::class, null, [ + 'widget' => 'choice', + 'years' => [2021], + ]); + + $form->submit([ + 'year' => '2020', + 'month' => '13', + 'day' => '13', + ]); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertCount(2, $form->getErrors()); + $this->assertSame('This value is not valid.', $form->getErrors()[0]->getMessage()); + $this->assertSame($form->get('year'), $form->getErrors()[0]->getOrigin()); + $this->assertSame('This value is not valid.', $form->getErrors()[1]->getMessage()); + $this->assertSame($form->get('month'), $form->getErrors()[1]->getOrigin()); + } + + public function testDoNotAddInvalidMessageIfChildFormIsAlreadyNotSynchronized() + { + $formBuilder = $this->formFactory->createBuilder() + ->add('field1') + ->add('field2') + ->addModelTransformer(new CallbackTransformer( + function () { + }, + function () { + throw new TransformationFailedException('This value is invalid.'); + } + )); + $formBuilder->get('field2')->addModelTransformer(new CallbackTransformer( + function () { + }, + function () { + throw new TransformationFailedException('This value is invalid.'); + } + )); + $form = $formBuilder->getForm(); + + $form->submit([ + 'field1' => 'foo', + 'field2' => 'bar', + ]); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertCount(0, $form->getErrors()); + $this->assertTrue($form->get('field1')->isValid()); + $this->assertCount(0, $form->get('field1')->getErrors()); + $this->assertFalse($form->get('field2')->isValid()); + $this->assertCount(1, $form->get('field2')->getErrors()); + } } class Foo diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index f789fbe1e408d..69f4efac171fa 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -362,40 +362,6 @@ function () { throw new TransformationFailedException(); } ->assertRaised(); } - // https://github.com/symfony/symfony/issues/4359 - public function testDontMarkInvalidIfAnyChildIsNotSynchronized() - { - $object = new \stdClass(); - $object->child = 'bar'; - - $failingTransformer = new CallbackTransformer( - function ($data) { return $data; }, - function () { throw new TransformationFailedException(); } - ); - - $form = $this->getBuilder('name', '\stdClass') - ->setData($object) - ->addViewTransformer($failingTransformer) - ->setCompound(true) - ->setDataMapper(new PropertyPathMapper()) - ->add( - $this->getBuilder('child') - ->addViewTransformer($failingTransformer) - ) - ->getForm(); - - // Launch transformer - $form->submit(['child' => 'foo']); - - $this->assertTrue($form->isSubmitted()); - $this->assertFalse($form->isSynchronized()); - $this->expectNoValidate(); - - $this->validator->validate($form, new Form()); - - $this->assertNoViolation(); - } - public function testHandleGroupSequenceValidationGroups() { $object = new \stdClass(); From 223b405168f1355460b80203c9d3e42f57bda012 Mon Sep 17 00:00:00 2001 From: Alexander Schranz Date: Sun, 21 Jun 2020 18:44:56 +0200 Subject: [PATCH 12/59] Avoid accessibility errors on debug toolbar --- .../Resources/views/Profiler/toolbar_js.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig index 9da75d0559219..7366808d114d0 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar_js.html.twig @@ -1,4 +1,4 @@ -
+
{{ include('@WebProfiler/Profiler/base_js.html.twig') }} {{ include('@WebProfiler/Profiler/toolbar.css.twig', { 'position': position, 'floatable': true }) }} From afe596e16a0e161fce72236f412c97029ae130fc Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 22 Jun 2020 09:47:42 +0200 Subject: [PATCH 13/59] Relax tests to unlock change on master --- .../DependencyInjection/Compiler/CachePoolClearerPassTest.php | 3 +++ .../Component/Form/Tests/DependencyInjection/FormPassTest.php | 4 +++- .../DependencyInjection/AddConstraintValidatorsPassTest.php | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php index 728595ae9f2b1..e690aa8651e7d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolClearerPassTest.php @@ -32,9 +32,11 @@ public function testPoolRefsAreWeak() $container->setParameter('kernel.root_dir', 'foo'); $globalClearer = new Definition(Psr6CacheClearer::class); + $globalClearer->setPublic(true); $container->setDefinition('cache.global_clearer', $globalClearer); $publicPool = new Definition(); + $publicPool->setPublic(true); $publicPool->addArgument('namespace'); $publicPool->addTag('cache.pool', ['clearer' => 'clearer_alias']); $container->setDefinition('public.pool', $publicPool); @@ -46,6 +48,7 @@ public function testPoolRefsAreWeak() $container->setDefinition('private.pool', $privatePool); $clearer = new Definition(); + $clearer->setPublic(true); $container->setDefinition('clearer', $clearer); $container->setAlias('clearer_alias', 'clearer'); diff --git a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php index 64393a049840a..d3856a5c57543 100644 --- a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php +++ b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php @@ -57,12 +57,14 @@ public function testAddTaggedTypes() $extDefinition = $container->getDefinition('form.extension'); + $locator = $extDefinition->getArgument(0); + $this->assertTrue(!$locator->isPublic() || $locator->isPrivate()); $this->assertEquals( (new Definition(ServiceLocator::class, [[ __CLASS__.'_Type1' => new ServiceClosureArgument(new Reference('my.type1')), __CLASS__.'_Type2' => new ServiceClosureArgument(new Reference('my.type2')), ]]))->addTag('container.service_locator')->setPublic(false), - $extDefinition->getArgument(0) + $locator->setPublic(false) ); } diff --git a/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php b/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php index 9a2958364df17..45e73fc4341e3 100644 --- a/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php +++ b/src/Symfony/Component/Validator/Tests/DependencyInjection/AddConstraintValidatorsPassTest.php @@ -35,12 +35,14 @@ public function testThatConstraintValidatorServicesAreProcessed() $addConstraintValidatorsPass = new AddConstraintValidatorsPass(); $addConstraintValidatorsPass->process($container); + $locator = $container->getDefinition((string) $validatorFactory->getArgument(0)); + $this->assertTrue(!$locator->isPublic() || $locator->isPrivate()); $expected = (new Definition(ServiceLocator::class, [[ Validator1::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')), 'my_constraint_validator_alias1' => new ServiceClosureArgument(new Reference('my_constraint_validator_service1')), Validator2::class => new ServiceClosureArgument(new Reference('my_constraint_validator_service2')), ]]))->addTag('container.service_locator')->setPublic(false); - $this->assertEquals($expected, $container->getDefinition((string) $validatorFactory->getArgument(0))); + $this->assertEquals($expected, $locator->setPublic(false)); } public function testAbstractConstraintValidator() From 12ab96ec9b2c8520b62e545c0e66acfd081bc450 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 22 Jun 2020 10:53:03 +0200 Subject: [PATCH 14/59] [DI][FrameworkBundle] Remove whitelist occurrences --- .../DependencyInjection/Compiler/UnusedTagsPass.php | 8 ++++---- ...sed-tags-whitelist.php => check-unused-known-tags.php} | 2 +- .../DependencyInjection/Compiler/UnusedTagsPassTest.php | 8 ++++---- .../Component/DependencyInjection/ContainerBuilder.php | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) rename src/Symfony/Bundle/FrameworkBundle/Resources/bin/{check-unused-tags-whitelist.php => check-unused-known-tags.php} (82%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php index 3cbe534fb99ed..f49f6a18c041f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php @@ -21,7 +21,7 @@ */ class UnusedTagsPass implements CompilerPassInterface { - private $whitelist = [ + private $knownTags = [ 'annotations.cached_reader', 'auto_alias', 'cache.pool', @@ -70,11 +70,11 @@ class UnusedTagsPass implements CompilerPassInterface public function process(ContainerBuilder $container) { - $tags = array_unique(array_merge($container->findTags(), $this->whitelist)); + $tags = array_unique(array_merge($container->findTags(), $this->knownTags)); foreach ($container->findUnusedTags() as $tag) { - // skip whitelisted tags - if (\in_array($tag, $this->whitelist)) { + // skip known tags + if (\in_array($tag, $this->knownTags)) { continue; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php b/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php similarity index 82% rename from src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php rename to src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php index 7f24973cd8f14..ec9ae1f97c0ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php @@ -15,5 +15,5 @@ $target = dirname(__DIR__, 2).'/DependencyInjection/Compiler/UnusedTagsPass.php'; $contents = file_get_contents($target); -$contents = preg_replace('{private \$whitelist = \[(.+?)\];}sm', "private \$whitelist = [\n '".implode("',\n '", UnusedTagsPassUtils::getDefinedTags())."',\n ];", $contents); +$contents = preg_replace('{private \$knownTags = \[(.+?)\];}sm', "private \$knownTags = [\n '".implode("',\n '", UnusedTagsPassUtils::getDefinedTags())."',\n ];", $contents); file_put_contents($target, $contents); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php index a73cdd167133d..8343d0d997fc8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/UnusedTagsPassTest.php @@ -35,21 +35,21 @@ public function testProcess() $this->assertSame([sprintf('%s: Tag "kenrel.event_subscriber" was defined on service(s) "foo", "bar", but was never used. Did you mean "kernel.event_subscriber"?', UnusedTagsPass::class)], $container->getCompiler()->getLog()); } - public function testMissingWhitelistTags() + public function testMissingKnownTags() { if (\dirname((new \ReflectionClass(ContainerBuilder::class))->getFileName(), 3) !== \dirname(__DIR__, 5)) { $this->markTestSkipped('Tests are not run from the root symfony/symfony metapackage.'); } - $this->assertSame(UnusedTagsPassUtils::getDefinedTags(), $this->getWhitelistTags(), 'The src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php file must be updated; run src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-tags-whitelist.php.'); + $this->assertSame(UnusedTagsPassUtils::getDefinedTags(), $this->getKnownTags(), 'The src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php file must be updated; run src/Symfony/Bundle/FrameworkBundle/Resources/bin/check-unused-known-tags.php.'); } - private function getWhitelistTags() + private function getKnownTags() { // get tags in UnusedTagsPass $target = \dirname(__DIR__, 3).'/DependencyInjection/Compiler/UnusedTagsPass.php'; $contents = file_get_contents($target); - preg_match('{private \$whitelist = \[(.+?)\];}sm', $contents, $matches); + preg_match('{private \$knownTags = \[(.+?)\];}sm', $contents, $matches); $tags = array_values(array_filter(array_map(function ($str) { return trim(preg_replace('{^ +\'(.+)\',}', '$1', $str)); }, explode("\n", $matches[1])))); diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 7c9860b4dc47a..f6568b3ea3c77 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -1176,9 +1176,9 @@ private function createService(Definition $definition, array &$inlineServices, $ $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments); // don't trigger deprecations for internal uses // @deprecated since version 3.3, to be removed in 4.0 along with the deprecated class - $deprecationWhitelist = ['event_dispatcher' => ContainerAwareEventDispatcher::class]; + $deprecationAllowlist = ['event_dispatcher' => ContainerAwareEventDispatcher::class]; - if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationWhitelist[$id]) || $deprecationWhitelist[$id] !== $class)) { + if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ") && (!isset($deprecationAllowlist[$id]) || $deprecationAllowlist[$id] !== $class)) { @trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED); } } From 39c1a6373b52903d37106c784bd95ada48f6bb7e Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Mon, 22 Jun 2020 16:52:42 +0200 Subject: [PATCH 15/59] [VarDumper] Support for cURL handler objects. --- src/Symfony/Component/VarDumper/Caster/ResourceCaster.php | 5 +++++ src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php index 3cdb27c30879b..eb11aee1f0264 100644 --- a/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ResourceCaster.php @@ -20,6 +20,11 @@ */ class ResourceCaster { + /** + * @param \CurlHandle|resource $h + * + * @return array + */ public static function castCurl($h, array $a, Stub $stub, $isNested) { return curl_getinfo($h); diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index f424cc4866d21..2e1af1d77625a 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -117,7 +117,9 @@ abstract class AbstractCloner implements ClonerInterface 'DateTimeZone' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castTimeZone'], 'DatePeriod' => ['Symfony\Component\VarDumper\Caster\DateCaster', 'castPeriod'], + 'CurlHandle' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], ':curl' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castCurl'], + ':dba' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':dba persistent' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castDba'], ':gd' => ['Symfony\Component\VarDumper\Caster\ResourceCaster', 'castGd'], From 76a744ad91f979d87d021d1bb165db73204d1401 Mon Sep 17 00:00:00 2001 From: YaFou <33806646+YaFou@users.noreply.github.com> Date: Tue, 23 Jun 2020 08:49:14 +0200 Subject: [PATCH 16/59] [HttpFondation] Change file extension of "audio/mpeg" from "mpga" to "mp3" --- .../HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php index c0f9140c800a2..5a809a248630f 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php @@ -619,7 +619,7 @@ class MimeTypeExtensionGuesser implements ExtensionGuesserInterface 'audio/basic' => 'au', 'audio/midi' => 'mid', 'audio/mp4' => 'm4a', - 'audio/mpeg' => 'mpga', + 'audio/mpeg' => 'mp3', 'audio/ogg' => 'oga', 'audio/s3m' => 's3m', 'audio/silk' => 'sil', From 968bd0ffec807e153fb7dd6b642d8a5d6432f0db Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 23 Jun 2020 14:31:34 +0200 Subject: [PATCH 17/59] Fixed typo in test name --- .../Component/Console/Tests/Helper/QuestionHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 93b762c26186d..f1a7676a07e64 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -1014,7 +1014,7 @@ public function testTraversableAutocomplete() $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } - public function testDisableSttby() + public function testDisableStty() { if (!Terminal::hasSttyAvailable()) { $this->markTestSkipped('`stty` is required to test autocomplete functionality'); From 4a66a6098f6072df94edfbe074c15880db4931e2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 23 Jun 2020 10:33:22 +0200 Subject: [PATCH 18/59] fix handling typed properties as constraint options --- .../Component/Validator/Constraint.php | 2 +- .../Validator/Tests/ConstraintTest.php | 24 +++++++++++++++++++ .../Fixtures/ConstraintWithStaticProperty.php | 10 ++++++++ .../Fixtures/ConstraintWithTypedProperty.php | 10 ++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithTypedProperty.php diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php index 693689b912c34..ab2d8822903e4 100644 --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php @@ -108,7 +108,7 @@ public function __construct($options = null) $defaultOption = $this->getDefaultOption(); $invalidOptions = []; $missingOptions = array_flip((array) $this->getRequiredOptions()); - $knownOptions = get_object_vars($this); + $knownOptions = get_class_vars(static::class); // The "groups" option is added to the object lazily $knownOptions['groups'] = true; diff --git a/src/Symfony/Component/Validator/Tests/ConstraintTest.php b/src/Symfony/Component/Validator/Tests/ConstraintTest.php index 6c481b00888ed..26cc460d39c8a 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintTest.php @@ -13,10 +13,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Validator\Constraint; +use Symfony\Component\Validator\Exception\InvalidOptionsException; use Symfony\Component\Validator\Tests\Fixtures\ClassConstraint; use Symfony\Component\Validator\Tests\Fixtures\ConstraintA; use Symfony\Component\Validator\Tests\Fixtures\ConstraintB; use Symfony\Component\Validator\Tests\Fixtures\ConstraintC; +use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithStaticProperty; +use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithTypedProperty; use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithValue; use Symfony\Component\Validator\Tests\Fixtures\ConstraintWithValueAsDefault; @@ -245,4 +248,25 @@ public function testAnnotationSetUndefinedDefaultOption() $this->expectExceptionMessage('No default option is configured for constraint "Symfony\Component\Validator\Tests\Fixtures\ConstraintB".'); new ConstraintB(['value' => 1]); } + + public function testStaticPropertiesAreNoOptions() + { + $this->expectException(InvalidOptionsException::class); + + new ConstraintWithStaticProperty([ + 'foo' => 'bar', + ]); + } + + /** + * @requires PHP 7.4 + */ + public function testSetTypedProperty() + { + $constraint = new ConstraintWithTypedProperty([ + 'foo' => 'bar', + ]); + + $this->assertSame('bar', $constraint->foo); + } } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php b/src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php new file mode 100644 index 0000000000000..f8b21694089b3 --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/ConstraintWithStaticProperty.php @@ -0,0 +1,10 @@ + Date: Fri, 26 Jun 2020 14:15:21 +0200 Subject: [PATCH 19/59] fix guessing form types for DateTime types --- .../Validator/ValidatorTypeGuesser.php | 1 + .../Validator/ValidatorTypeGuesserTest.php | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php index 80ec926a94b29..17009d205dd3f 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorTypeGuesser.php @@ -97,6 +97,7 @@ public function guessTypeForConstraint(Constraint $constraint) case 'long': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\IntegerType', [], Guess::MEDIUM_CONFIDENCE); + case \DateTime::class: case '\DateTime': return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\DateType', [], Guess::MEDIUM_CONFIDENCE); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index 878bbfad21bc5..3ac27cdef73b4 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -12,9 +12,17 @@ namespace Symfony\Component\Form\Tests\Extension\Validator; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; +use Symfony\Component\Form\Extension\Core\Type\CollectionType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\IntegerType; +use Symfony\Component\Form\Extension\Core\Type\NumberType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; use Symfony\Component\Form\Guess\Guess; +use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Component\Form\Guess\ValueGuess; +use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Email; use Symfony\Component\Validator\Constraints\IsTrue; use Symfony\Component\Validator\Constraints\Length; @@ -59,6 +67,35 @@ protected function setUp() $this->guesser = new ValidatorTypeGuesser($this->metadataFactory); } + /** + * @dataProvider guessTypeProvider + */ + public function testGuessType(Constraint $constraint, TypeGuess $guess) + { + $this->metadata->addPropertyConstraint(self::TEST_PROPERTY, $constraint); + + $this->assertEquals($guess, $this->guesser->guessType(self::TEST_CLASS, self::TEST_PROPERTY)); + } + + public function guessTypeProvider() + { + return [ + [new Type('array'), new TypeGuess(CollectionType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('bool'), new TypeGuess(CheckboxType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('boolean'), new TypeGuess(CheckboxType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('double'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('float'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('numeric'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('real'), new TypeGuess(NumberType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('int'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('integer'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('long'), new TypeGuess(IntegerType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('string'), new TypeGuess(TextType::class, [], Guess::LOW_CONFIDENCE)], + [new Type(\DateTime::class), new TypeGuess(DateType::class, [], Guess::MEDIUM_CONFIDENCE)], + [new Type('\DateTime'), new TypeGuess(DateType::class, [], Guess::MEDIUM_CONFIDENCE)], + ]; + } + public function guessRequiredProvider() { return [ From 7cb29c8b4b2990a2555d739ec11d7b9d0d46aff8 Mon Sep 17 00:00:00 2001 From: Juan Mrad Date: Tue, 23 Jun 2020 11:04:58 -0500 Subject: [PATCH 20/59] [MimeType] Duplicated MimeType due to PHP Bug --- .../File/MimeType/FileinfoMimeTypeGuesser.php | 8 +++++++- .../HttpFoundation/Tests/File/Fixtures/test.docx | Bin 0 -> 6062 bytes .../Tests/File/MimeType/MimeTypeTest.php | 8 ++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/test.docx diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php index fc4bc45024b11..fa4c962d7dd82 100644 --- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php +++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php @@ -63,7 +63,13 @@ public function guess($path) if (!$finfo = new \finfo(FILEINFO_MIME_TYPE, $this->magicFile)) { return null; } + $mimeType = $finfo->file($path); - return $finfo->file($path); + if ($mimeType && 0 === (\strlen($mimeType) % 2)) { + $mimeStart = substr($mimeType, 0, \strlen($mimeType) >> 1); + $mimeType = $mimeStart.$mimeStart === $mimeType ? $mimeStart : $mimeType; + } + + return $mimeType; } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/test.docx b/src/Symfony/Component/HttpFoundation/Tests/File/Fixtures/test.docx new file mode 100644 index 0000000000000000000000000000000000000000..2e86b6fcea03c679370c996ba200ccb39d1dd83b GIT binary patch literal 6062 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 Inm-Hw4?2y0ApigX literal 0 HcmV?d00001 diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index 0418726b5b905..e38816687fec7 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -60,6 +60,14 @@ public function testGuessFileWithUnknownExtension() $this->assertEquals('application/octet-stream', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/.unknownextension')); } + /** + * @requires PHP 7.0 + */ + public function testGuessWithDuplicatedFileType() + { + $this->assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); + } + public function testGuessWithIncorrectPath() { $this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException'); From b344f6d7db29f8b6c52a9425af84c29c798b5ed6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 28 Jun 2020 17:22:27 +0200 Subject: [PATCH 21/59] Fix test that fails on old distros --- .../HttpFoundation/Tests/File/MimeType/MimeTypeTest.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php index e38816687fec7..aca05f2d96ca0 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php @@ -65,7 +65,13 @@ public function testGuessFileWithUnknownExtension() */ public function testGuessWithDuplicatedFileType() { - $this->assertEquals('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); + if ('application/zip' === MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')) { + $this->addToAssertionCount(1); + + return; + } + + $this->assertSame('application/vnd.openxmlformats-officedocument.wordprocessingml.document', MimeTypeGuesser::getInstance()->guess(__DIR__.'/../Fixtures/test.docx')); } public function testGuessWithIncorrectPath() From 776daf28b4e5240a830ff0c724604a4968e51b24 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 29 Jun 2020 12:48:16 +0200 Subject: [PATCH 22/59] fix validating lazy properties that evaluate to null --- .../Validator/Tests/Fixtures/EntityParent.php | 6 +++++ .../Validator/RecursiveValidatorTest.php | 27 +++++++++++++++++++ .../RecursiveContextualValidator.php | 4 +++ 3 files changed, 37 insertions(+) diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php index 4674f8b35a226..eb09e5a4b2375 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php @@ -18,6 +18,7 @@ class EntityParent implements EntityInterfaceA protected $firstName; private $internal; private $data = 'Data'; + private $child; /** * @NotNull @@ -28,4 +29,9 @@ public function getData() { return 'Data'; } + + public function getChild() + { + return $this->child; + } } diff --git a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php index 484236241c7fa..c9e30b458780f 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php @@ -21,6 +21,7 @@ use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Optional; use Symfony\Component\Validator\Constraints\Required; +use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\ConstraintValidatorFactory; use Symfony\Component\Validator\Context\ExecutionContextFactory; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -28,6 +29,7 @@ use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildA; use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildB; use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Tests\Fixtures\EntityParent; use Symfony\Component\Validator\Tests\Fixtures\EntityWithGroupedConstraintOnMethods; use Symfony\Component\Validator\Validator\RecursiveValidator; @@ -143,6 +145,31 @@ public function testGroupedMethodConstraintValidateInSequence() $this->assertInstanceOf(IsTrue::class, $violations->get(1)->getConstraint()); } + public function testValidConstraintOnGetterReturningNull() + { + $metadata = new ClassMetadata(EntityParent::class); + $metadata->addGetterConstraint('child', new Valid()); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validator->validate(new EntityParent()); + + $this->assertCount(0, $violations); + } + + public function testNotNullConstraintOnGetterReturningNull() + { + $metadata = new ClassMetadata(EntityParent::class); + $metadata->addGetterConstraint('child', new NotNull()); + + $this->metadataFactory->addMetadata($metadata); + + $violations = $this->validator->validate(new EntityParent()); + + $this->assertCount(1, $violations); + $this->assertInstanceOf(NotNull::class, $violations->get(0)->getConstraint()); + } + public function testAllConstraintValidateAllGroupsForNestedConstraints() { $this->metadata->addPropertyConstraint('data', new All(['constraints' => [ diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index 24206bfc27d92..a51e66d2906d0 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -680,6 +680,10 @@ private function validateGenericNode($value, $object, $cacheKey, MetadataInterfa if ($value instanceof LazyProperty) { $value = $value->getPropertyValue(); + + if (null === $value) { + return; + } } if (\is_array($value)) { From 5c5ea7500eea9c04b12f8d14adafb2f537b41e78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Tue, 30 Jun 2020 14:50:28 +0200 Subject: [PATCH 23/59] Removed comments and requirements relative to php <5.5 (not supported anymore) --- src/Symfony/Component/Console/Command/Command.php | 2 -- .../DateTimeToHtml5LocalDateTimeTransformerTest.php | 1 - src/Symfony/Component/HttpFoundation/Tests/CookieTest.php | 3 --- 3 files changed, 6 deletions(-) diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index 311fdb6a144ef..e39cc3ba41815 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -437,8 +437,6 @@ public function setName($name) * This feature should be used only when creating a long process command, * like a daemon. * - * PHP 5.5+ or the proctitle PECL library is required - * * @param string $title The process title * * @return $this diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php index 5fd6c69f5e11b..aef3e68829b13 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php @@ -63,7 +63,6 @@ public function testTransform($fromTz, $toTz, $from, $to) /** * @dataProvider transformProvider - * @requires PHP 5.5 */ public function testTransformDateTimeImmutable($fromTz, $toTz, $from, $to) { diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index 169f9178751d4..637cff0d09ae4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -115,9 +115,6 @@ public function testConstructorWithDateTime() $this->assertEquals($expire->format('U'), $cookie->getExpiresTime(), '->getExpiresTime() returns the expire date'); } - /** - * @requires PHP 5.5 - */ public function testConstructorWithDateTimeImmutable() { $expire = new \DateTimeImmutable(); From aeb46373410d168b995aeab34f725092616a67f0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Jun 2020 19:26:29 +0200 Subject: [PATCH 24/59] [ErrorHandler] fix throwing from __toString() --- src/Symfony/Component/Debug/ErrorHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index 40a4b1758ce7c..1e60b5ca9803d 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -401,7 +401,7 @@ public function handleError($type, $message, $file, $line) $scope = $this->scopedErrors & $type; if (4 < $numArgs = \func_num_args()) { - $context = $scope ? (func_get_arg(4) ?: []) : []; + $context = func_get_arg(4) ?: []; $backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM } else { $context = []; From 91f30e0b62dcc7bfa5c37c49cc2d25cfcab3419f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Jun 2020 19:58:29 +0200 Subject: [PATCH 25/59] [Bridge/Twig] Relax tests --- src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php index 273ca922d6fe8..3125b88aad7fd 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php @@ -82,6 +82,7 @@ public function testDump($context, $args, $expectedOutput, $debug = true) $this->assertStringStartsWith('