From c5b81904248ba3b773f9f53fcb07a1dd0d3b32a4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 3 Jan 2020 19:23:58 +0100 Subject: [PATCH 01/18] do not render preferred choices as selected --- .../views/Form/form_div_layout.html.twig | 4 ++- .../views/Form/foundation_5_layout.html.twig | 2 ++ .../AbstractBootstrap3LayoutTest.php | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index a97a38e520..b5f1d36cab 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -65,12 +65,14 @@ {%- endif -%} {%- if preferred_choices|length > 0 -%} {% set options = preferred_choices %} + {% set render_preferred_choices = true %} {{- block('choice_widget_options') -}} {%- if choices|length > 0 and separator is not none -%} {%- endif -%} {%- endif -%} {%- set options = choices -%} + {%- set render_preferred_choices = false -%} {{- block('choice_widget_options') -}} {%- endblock choice_widget_collapsed -%} @@ -83,7 +85,7 @@ {{- block('choice_widget_options') -}} {%- else -%} - + {%- endif -%} {% endfor %} {%- endblock choice_widget_options -%} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig index 83c5e30d80..e5d129736c 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig @@ -160,12 +160,14 @@ {%- endif %} {%- if preferred_choices|length > 0 -%} {% set options = preferred_choices %} + {% set render_preferred_choices = true %} {{- block('choice_widget_options') -}} {% if choices|length > 0 and separator is not none -%} {%- endif %} {%- endif -%} {% set options = choices -%} + {%- set render_preferred_choices = false -%} {{- block('choice_widget_options') -}} {%- endblock choice_widget_collapsed %} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 66654d9ce5..b46358d6dc 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -531,6 +531,31 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest ); } + public function testSingleChoiceWithSelectedPreferred() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [ + 'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b'], + 'preferred_choices' => ['&a'], + 'multiple' => false, + 'expanded' => false, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --', 'attr' => ['class' => 'my&class']], +'/select + [@name="name"] + [@class="my&class form-control"] + [not(@required)] + [ + ./option[@value="&a"][not(@selected)][.="[trans]Choice&A[/trans]"] + /following-sibling::option[@disabled="disabled"][not(@selected)][.="-- sep --"] + /following-sibling::option[@value="&a"][@selected="selected"][.="[trans]Choice&A[/trans]"] + /following-sibling::option[@value="&b"][.="[trans]Choice&B[/trans]"] + ] + [count(./option)=4] +' + ); + } + public function testSingleChoiceWithPreferredAndNoSeparator() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [ From 2ef8771ad7a90366b31e24f986d23e686bc1ef41 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 4 Jan 2020 19:57:41 +0100 Subject: [PATCH 02/18] [Security\Guard] Fix missing typehints --- .../Security/Guard/Firewall/GuardAuthenticationListener.php | 2 +- .../Security/Guard/Provider/GuardAuthenticationProvider.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php index 25de3ce440..94a1efb469 100644 --- a/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php +++ b/src/Symfony/Component/Security/Guard/Firewall/GuardAuthenticationListener.php @@ -51,7 +51,7 @@ class GuardAuthenticationListener implements ListenerInterface * @param iterable|AuthenticatorInterface[] $guardAuthenticators The authenticators, with keys that match what's passed to GuardAuthenticationProvider * @param LoggerInterface $logger A LoggerInterface instance */ - public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, $guardAuthenticators, LoggerInterface $logger = null) + public function __construct(GuardAuthenticatorHandler $guardHandler, AuthenticationManagerInterface $authenticationManager, string $providerKey, iterable $guardAuthenticators, LoggerInterface $logger = null) { if (empty($providerKey)) { throw new \InvalidArgumentException('$providerKey must not be empty.'); diff --git a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php index 625ac5e6fe..d4d23dfb0d 100644 --- a/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Guard/Provider/GuardAuthenticationProvider.php @@ -45,7 +45,7 @@ class GuardAuthenticationProvider implements AuthenticationProviderInterface * @param UserProviderInterface $userProvider The user provider * @param string $providerKey The provider (i.e. firewall) key */ - public function __construct($guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker) + public function __construct(iterable $guardAuthenticators, UserProviderInterface $userProvider, string $providerKey, UserCheckerInterface $userChecker) { $this->guardAuthenticators = $guardAuthenticators; $this->userProvider = $userProvider; From 87212e41b395921d4fac8692009947cc53d3922e Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 2 Jan 2020 12:21:52 +0100 Subject: [PATCH 03/18] [FrameworkBundle][TranslationUpdateCommand] Do not output positive feedback on stderr --- .../Command/TranslationUpdateCommand.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 7375450d5d..fcf145cc46 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -200,12 +200,12 @@ EOF } } - $errorIo->title('Translation Messages Extractor and Dumper'); - $errorIo->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName)); + $io->title('Translation Messages Extractor and Dumper'); + $io->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName)); // load any messages from templates $extractedCatalogue = new MessageCatalogue($input->getArgument('locale')); - $errorIo->comment('Parsing templates...'); + $io->comment('Parsing templates...'); $prefix = $input->getOption('prefix'); // @deprecated since version 3.4, to be removed in 4.0 along with the --no-prefix option if ($input->getOption('no-prefix')) { @@ -221,7 +221,7 @@ EOF // load any existing messages from the translation files $currentCatalogue = new MessageCatalogue($input->getArgument('locale')); - $errorIo->comment('Loading translation files...'); + $io->comment('Loading translation files...'); foreach ($transPaths as $path) { if (is_dir($path)) { $this->reader->read($path, $currentCatalogue); @@ -274,7 +274,7 @@ EOF } if ('xlf' == $input->getOption('output-format')) { - $errorIo->comment('Xliff output version is 1.2'); + $io->comment('Xliff output version is 1.2'); } $resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was'); @@ -286,7 +286,7 @@ EOF // save the files if (true === $input->getOption('force')) { - $errorIo->comment('Writing files...'); + $io->comment('Writing files...'); $bundleTransPath = false; foreach ($transPaths as $path) { @@ -306,7 +306,7 @@ EOF } } - $errorIo->success($resultMessage.'.'); + $io->success($resultMessage.'.'); return null; } From 9b711b87fe0552df4dbb3023f3643a5499c19aef Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 6 Jan 2020 22:25:08 +0100 Subject: [PATCH 04/18] [Security] Prevent canceled remember-me cookie from being accepted --- .../Tests/Functional/ClearRememberMeTest.php | 2 +- src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- .../Http/RememberMe/AbstractRememberMeServices.php | 4 ++++ .../RememberMe/AbstractRememberMeServicesTest.php | 11 +++++++++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php index 3a1046b0c4..51f56c220d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php @@ -33,7 +33,7 @@ class ClearRememberMeTest extends AbstractWebTestCase $this->assertNotNull($cookieJar->get('REMEMBERME')); $client->request('GET', '/foo'); - $this->assertSame(200, $client->getResponse()->getStatusCode()); + $this->assertRedirect($client->getResponse(), '/login'); $this->assertNull($cookieJar->get('REMEMBERME')); } } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 1a8057b6fb..f0e35c7f3d 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -19,7 +19,7 @@ "php": "^5.5.9|>=7.0.8", "ext-xml": "*", "symfony/config": "~3.4|~4.0", - "symfony/security": "~3.4.36|~4.3.9|^4.4.1", + "symfony/security": "~3.4.37|~4.3.10|^4.4.3", "symfony/dependency-injection": "^3.4.3|^4.0.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php index 8dacdafb57..bf69f3012b 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -99,6 +99,10 @@ abstract class AbstractRememberMeServices implements RememberMeServicesInterface */ final public function autoLogin(Request $request) { + if (($cookie = $request->attributes->get(self::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) { + return null; + } + if (null === $cookie = $request->cookies->get($this->options['name'])) { return null; } diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index 8dc2042f12..cf70ed4cb1 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -39,6 +39,17 @@ class AbstractRememberMeServicesTest extends TestCase $this->assertNull($service->autoLogin(new Request())); } + public function testAutoLoginReturnsNullAfterLoginFail() + { + $service = $this->getService(null, ['name' => 'foo', 'path' => null, 'domain' => null]); + + $request = new Request(); + $request->cookies->set('foo', 'foo'); + + $service->loginFail($request); + $this->assertNull($service->autoLogin($request)); + } + /** * @group legacy */ From 6fb55812abc78a9e33f04e332bff6c5c474425f9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Jan 2020 11:19:31 +0100 Subject: [PATCH 05/18] [HttpKernel] release lock explicitly --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f21a88b3b4..dda645a6fc 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -556,7 +556,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl } } - public function __destruct() + public function release() { flock($this->lock, LOCK_UN); fclose($this->lock); @@ -634,7 +634,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl } $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass()); - unset($cache); + $cache->release(); $this->container = require $cachePath; $this->container->set('kernel', $this); From 8d7fa32d15fb07de6f9d05c0718c34fbe12b44fd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 7 Jan 2020 11:39:48 +0100 Subject: [PATCH 06/18] fix processing chain adapter based cache pool --- .../DependencyInjection/CachePoolPass.php | 7 +++- .../DependencyInjection/CachePoolPassTest.php | 40 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php index e082df1c45..f52d0271e4 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php @@ -103,7 +103,12 @@ class CachePoolPass implements CompilerPassInterface if (ChainAdapter::class === $class) { $adapters = []; foreach ($adapter->getArgument(0) as $provider => $adapter) { - $chainedPool = $adapter = new ChildDefinition($adapter); + if ($adapter instanceof ChildDefinition) { + $chainedPool = $adapter; + } else { + $chainedPool = $adapter = new ChildDefinition($adapter); + } + $chainedTags = [\is_int($provider) ? [] : ['provider' => $provider]]; $chainedClass = ''; diff --git a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php index e763dabe48..20701adcb4 100644 --- a/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php +++ b/src/Symfony/Component/Cache/Tests/DependencyInjection/CachePoolPassTest.php @@ -12,7 +12,9 @@ namespace Symfony\Component\Cache\Tests\DependencyInjection; use PHPUnit\Framework\TestCase; +use Symfony\Component\Cache\Adapter\ApcuAdapter; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\ChainAdapter; use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\DependencyInjection\CachePoolPass; use Symfony\Component\DependencyInjection\ChildDefinition; @@ -174,4 +176,42 @@ class CachePoolPassTest extends TestCase $this->cachePoolPass->process($container); } + + public function testChainAdapterPool() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.container_class', 'app'); + $container->setParameter('kernel.project_dir', 'foo'); + + $container->register('cache.adapter.array', ArrayAdapter::class) + ->addTag('cache.pool'); + $container->register('cache.adapter.apcu', ApcuAdapter::class) + ->setArguments([null, 0, null]) + ->addTag('cache.pool'); + $container->register('cache.chain', ChainAdapter::class) + ->addArgument(['cache.adapter.array', 'cache.adapter.apcu']) + ->addTag('cache.pool'); + $container->setDefinition('cache.app', new ChildDefinition('cache.chain')) + ->addTag('cache.pool'); + $container->setDefinition('doctrine.result_cache_pool', new ChildDefinition('cache.app')) + ->addTag('cache.pool'); + + $this->cachePoolPass->process($container); + + $appCachePool = $container->getDefinition('cache.app'); + $this->assertInstanceOf(ChildDefinition::class, $appCachePool); + $this->assertSame('cache.chain', $appCachePool->getParent()); + + $chainCachePool = $container->getDefinition('cache.chain'); + $this->assertNotInstanceOf(ChildDefinition::class, $chainCachePool); + $this->assertCount(2, $chainCachePool->getArgument(0)); + $this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[0]); + $this->assertSame('cache.adapter.array', $chainCachePool->getArgument(0)[0]->getParent()); + $this->assertInstanceOf(ChildDefinition::class, $chainCachePool->getArgument(0)[1]); + $this->assertSame('cache.adapter.apcu', $chainCachePool->getArgument(0)[1]->getParent()); + + $doctrineCachePool = $container->getDefinition('doctrine.result_cache_pool'); + $this->assertInstanceOf(ChildDefinition::class, $doctrineCachePool); + $this->assertSame('cache.app', $doctrineCachePool->getParent()); + } } From e48829e9b66dd80cd80d625cf9a9f91710133cce Mon Sep 17 00:00:00 2001 From: Douglas Greenshields Date: Mon, 6 Jan 2020 11:29:29 +0000 Subject: [PATCH 07/18] [DependencyInjection] Handle ServiceClosureArgument for callable in container linting --- .../Compiler/CheckTypeDeclarationsPass.php | 5 ++++ .../CheckTypeDeclarationsPassTest.php | 25 +++++++++++++++++++ .../BarMethodCall.php | 4 +++ 3 files changed, 34 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index 4bbcedbf12..7c414258b7 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException; @@ -219,6 +220,10 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass return; } + if (\in_array($type, ['callable', 'Closure'], true) && $value instanceof ServiceClosureArgument) { + return; + } + if ('iterable' === $type && (\is_array($value) || $value instanceof \Traversable || $value instanceof IteratorArgument)) { return; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php index 22a29fa4d6..350f85296a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -13,6 +13,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Argument\IteratorArgument; +use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument; use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass; use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -697,4 +698,28 @@ class CheckTypeDeclarationsPassTest extends TestCase $this->addToAssertionCount(1); } + + public function testProcessSuccessWhenPassingServiceClosureArgumentToCallable() + { + $container = new ContainerBuilder(); + + $container->register('bar', BarMethodCall::class) + ->addMethodCall('setCallable', [new ServiceClosureArgument(new Reference('foo'))]); + + (new CheckTypeDeclarationsPass(true))->process($container); + + $this->addToAssertionCount(1); + } + + public function testProcessSuccessWhenPassingServiceClosureArgumentToClosure() + { + $container = new ContainerBuilder(); + + $container->register('bar', BarMethodCall::class) + ->addMethodCall('setClosure', [new ServiceClosureArgument(new Reference('foo'))]); + + (new CheckTypeDeclarationsPass(true))->process($container); + + $this->addToAssertionCount(1); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php index b705601609..69f1a693a4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php @@ -40,4 +40,8 @@ class BarMethodCall public function setCallable(callable $callable): void { } + + public function setClosure(\Closure $closure): void + { + } } From 96e70a40801ba1292cf340683e1a46dc797367a3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 7 Jan 2020 13:55:38 +0100 Subject: [PATCH 08/18] [HttpClient] fix exception in case of PSR17 discovery failure --- src/Symfony/Component/HttpClient/HttplugClient.php | 11 ++++++++--- src/Symfony/Component/HttpClient/Psr18Client.php | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpClient/HttplugClient.php b/src/Symfony/Component/HttpClient/HttplugClient.php index e756ea5d3f..08023b9c42 100644 --- a/src/Symfony/Component/HttpClient/HttplugClient.php +++ b/src/Symfony/Component/HttpClient/HttplugClient.php @@ -16,6 +16,7 @@ use Http\Client\Exception\NetworkException; use Http\Client\Exception\RequestException; use Http\Client\HttpAsyncClient; use Http\Client\HttpClient as HttplugInterface; +use Http\Discovery\Exception\NotFoundException; use Http\Discovery\Psr17FactoryDiscovery; use Http\Message\RequestFactory; use Http\Message\StreamFactory; @@ -75,9 +76,13 @@ final class HttplugClient implements HttplugInterface, HttpAsyncClient, RequestF throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".'); } - $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null; - $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory(); - $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory(); + try { + $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null; + $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory(); + $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory(); + } catch (NotFoundException $e) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e); + } } $this->waitLoop = new HttplugWaitLoop($this->client, $this->promisePool, $this->responseFactory, $this->streamFactory); diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php index ba59dc11f7..67c2fdb8f0 100644 --- a/src/Symfony/Component/HttpClient/Psr18Client.php +++ b/src/Symfony/Component/HttpClient/Psr18Client.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpClient; +use Http\Discovery\Exception\NotFoundException; use Http\Discovery\Psr17FactoryDiscovery; use Nyholm\Psr7\Factory\Psr17Factory; use Nyholm\Psr7\Request; @@ -68,9 +69,13 @@ final class Psr18Client implements ClientInterface, RequestFactoryInterface, Str throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\Psr18Client" as no PSR-17 factories have been provided. Try running "composer require nyholm/psr7".'); } - $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null; - $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory(); - $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory(); + try { + $psr17Factory = class_exists(Psr17Factory::class, false) ? new Psr17Factory() : null; + $this->responseFactory = $this->responseFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findResponseFactory(); + $this->streamFactory = $this->streamFactory ?? $psr17Factory ?? Psr17FactoryDiscovery::findStreamFactory(); + } catch (NotFoundException $e) { + throw new \LogicException('You cannot use the "Symfony\Component\HttpClient\HttplugClient" as no PSR-17 factories have been found. Try running "composer require nyholm/psr7".', 0, $e); + } } /** From d38cdc9dce8ba0c1ef263e2fd1948db186fe0324 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Tue, 7 Jan 2020 17:40:07 +0100 Subject: [PATCH 09/18] [FrameworkBundle][ContainerLintCommand] Only skip .errored. services --- .../FrameworkBundle/Command/ContainerLintCommand.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php index 5e6277567e..290f1da5e3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php @@ -102,11 +102,12 @@ final class ContainerLintCommand extends Command $refl->setAccessible(true); $refl->setValue($parameterBag, true); - $passConfig = $container->getCompilerPassConfig(); - $passConfig->setRemovingPasses([]); - $passConfig->setAfterRemovingPasses([]); - - $skippedIds = $kernelContainer->getRemovedIds(); + $skippedIds = []; + foreach ($container->getServiceIds() as $serviceId) { + if (0 === strpos($serviceId, '.errored.')) { + $skippedIds[$serviceId] = true; + } + } } $container->setParameter('container.build_hash', 'lint_container'); From a16a574ca8465a1b472ec7264ff74b53113743bb Mon Sep 17 00:00:00 2001 From: Toni Rudolf Date: Sun, 29 Dec 2019 10:43:19 +0100 Subject: [PATCH 10/18] [Messenger] Added check if json_encode succeeded --- .../Tests/Transport/RedisExt/ConnectionTest.php | 14 ++++++++++++++ .../Messenger/Transport/RedisExt/Connection.php | 8 ++++++++ 2 files changed, 22 insertions(+) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php index 57eafa2c1d..6dd7a0287b 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php @@ -186,6 +186,20 @@ class ConnectionTest extends TestCase $redis->del('messenger-getnonblocking'); } + public function testJsonError() + { + $redis = new \Redis(); + + $connection = Connection::fromDsn('redis://localhost/json-error', [], $redis); + + try { + $connection->add("\xB1\x31", []); + } catch (TransportException $e) { + } + + $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); + } + public function testMaxEntries() { $redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock(); diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 33d6057f67..e198022162 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -248,6 +248,10 @@ class Connection 'uniqid' => uniqid('', true), ]); + if (false === $message) { + throw new TransportException(json_last_error_msg()); + } + $score = (int) ($this->getCurrentTimeInMilliseconds() + $delayInMs); $added = $this->connection->zadd($this->queue, ['NX'], $score, $message); } else { @@ -256,6 +260,10 @@ class Connection 'headers' => $headers, ]); + if (false === $message) { + throw new TransportException(json_last_error_msg()); + } + if ($this->maxEntries) { $added = $this->connection->xadd($this->stream, '*', ['message' => $message], $this->maxEntries, true); } else { From c2bdc4c4d36acdb5c7e3e1a27a4827976df0d188 Mon Sep 17 00:00:00 2001 From: Toni Rudolf Date: Mon, 30 Dec 2019 19:18:34 +0100 Subject: [PATCH 11/18] [Messenger] Added check if json_encode succeeded --- .../Tests/Transport/RedisExt/ConnectionTest.php | 11 +++++++++++ .../Messenger/Transport/RedisExt/Connection.php | 13 ++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php index 81baaac8d9..5d9f68a982 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php @@ -177,6 +177,17 @@ class ConnectionTest extends TestCase $redis->del('messenger-getnonblocking'); } + public function testJsonError() + { + $redis = new \Redis(); + $connection = Connection::fromDsn('redis://localhost/json-error', [], $redis); + try { + $connection->add("\xB1\x31", []); + } catch (TransportException $e) { + } + $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); + } + public function testLastErrorGetsCleared() { $redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock(); diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 6ded724ca5..b9515e7ad0 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -185,9 +185,16 @@ class Connection } try { - $added = $this->connection->xadd($this->stream, '*', ['message' => json_encode( - ['body' => $body, 'headers' => $headers] - )]); + $message = json_encode([ + 'body' => $body, + 'headers' => $headers, + ]); + + if (false === $message) { + throw new TransportException(json_last_error_msg()); + } + + $added = $this->connection->xadd($this->stream, '*', ['message' => $message]); } catch (\RedisException $e) { throw new TransportException($e->getMessage(), 0, $e); } From 25c805ed5612c125be7239f0ae8527b93a972dc5 Mon Sep 17 00:00:00 2001 From: Oleg Andreyev Date: Tue, 7 Jan 2020 00:31:32 +0200 Subject: [PATCH 12/18] [PhpUnitBridge] When using phpenv + phpenv-composer plugin, composer executable is wrapped into a bash script --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 262fdd9dea..da99873a93 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -60,7 +60,7 @@ foreach ($defaultEnvs as $envName => $envValue) { $COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar') || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar 2> /dev/null`)) || ($COMPOSER = rtrim('\\' === DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer`) : `which composer 2> /dev/null`)) - ? $PHP.' '.escapeshellarg($COMPOSER) + ? (file_get_contents($COMPOSER, null, 0, 18) === '#!/usr/bin/env php' ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang : 'composer'; if (false === $SYMFONY_PHPUNIT_REMOVE = getenv('SYMFONY_PHPUNIT_REMOVE')) { From 2a5d9cb75a4388cef7a68f6be256d0554f96eac7 Mon Sep 17 00:00:00 2001 From: Stephen Lewis Date: Fri, 3 Jan 2020 11:56:12 +0000 Subject: [PATCH 13/18] [TwigBridge] button_widget now has its title attr translated even if its label = null or false --- .../Twig/Resources/views/Form/form_div_layout.html.twig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index ad4477cba5..cee716eb47 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -222,13 +222,11 @@ '%name%': name, '%id%': id, }) %} - {%- elseif label is same as(false) -%} - {% set translation_domain = false %} - {%- else -%} + {%- elseif label is not same as(false) -%} {% set label = name|humanize %} {%- endif -%} {%- endif -%} - + {%- endblock button_widget -%} {%- block submit_widget -%} From 08c1481b88a00c2a2d8c3f6f0c44e3306dc7c576 Mon Sep 17 00:00:00 2001 From: Igor Tarasov Date: Tue, 7 Jan 2020 23:22:51 +0300 Subject: [PATCH 14/18] [HttpClient] Added missing sprintf It was supposed to be there. --- src/Symfony/Component/HttpClient/Response/ResponseTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index d249d63048..c747f373a0 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -323,7 +323,7 @@ trait ResponseTrait } if ('' !== $chunk && null !== $response->content && \strlen($chunk) !== fwrite($response->content, $chunk)) { - $multi->handlesActivity[$j] = [null, new TransportException('Failed writing %d bytes to the response buffer.', \strlen($chunk))]; + $multi->handlesActivity[$j] = [null, new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($chunk)))]; continue; } From eb69e135b2768d74544cced5b62152b6ba4c81b8 Mon Sep 17 00:00:00 2001 From: naitsirch Date: Tue, 7 Jan 2020 21:29:45 +0100 Subject: [PATCH 15/18] [Dotenv] Fixed infinite loop with missing quote followed by quoted value If there's a quote missing to end a value and in the next line there's again a quoted value Dotenv will run into an infinite loop. An .env file with the following content will result in this error: ``` FOO="foo BAR="bar" ``` See #34642 for more details. --- src/Symfony/Component/Dotenv/Dotenv.php | 5 ++++- src/Symfony/Component/Dotenv/Tests/DotenvTest.php | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index 84e66b1d0b..63424e165d 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -203,7 +203,10 @@ final class Dotenv $this->cursor += 1 + $len; } elseif ('"' === $this->data[$this->cursor]) { $value = ''; - ++$this->cursor; + + if (++$this->cursor === $this->end) { + throw $this->createFormatException('Missing quote to end the value'); + } while ('"' !== $this->data[$this->cursor] || ('\\' === $this->data[$this->cursor - 1] && '\\' !== $this->data[$this->cursor - 2])) { $value .= $this->data[$this->cursor]; diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 43607d3555..fa53029c67 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -40,6 +40,7 @@ class DotenvTest extends TestCase ['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"], ['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"], ['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"], + ["FOO=\"foo\nBAR=\"bar\"", "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo\\nBAR=\"bar\"...\n ^ line 1 offset 18"], ['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 9"], ['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"], ['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"], From 6449f9299c7588d64cd36caf0367c5ee7851150a Mon Sep 17 00:00:00 2001 From: Bastien Jaillot Date: Tue, 7 Jan 2020 22:43:22 +0100 Subject: [PATCH 16/18] [Serializer] Fix cache in MetadataAwareNameConverter `isset` is used to test existence of values that is `null` by default, which result to always bypass the cache and force to do the calculate all the time. This is a critical perf improvement in prod mode for an api. Ref #35085 --- .../NameConverter/MetadataAwareNameConverter.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php b/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php index bbf70eaac3..a3ffaa3df5 100644 --- a/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php +++ b/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php @@ -47,7 +47,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface return $this->normalizeFallback($propertyName, $class, $format, $context); } - if (!isset(self::$normalizeCache[$class][$propertyName])) { + if (!\array_key_exists($class, self::$normalizeCache) || !\array_key_exists($propertyName, self::$normalizeCache[$class])) { self::$normalizeCache[$class][$propertyName] = $this->getCacheValueForNormalization($propertyName, $class); } @@ -64,7 +64,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface } $cacheKey = $this->getCacheKey($class, $context); - if (!isset(self::$denormalizeCache[$cacheKey][$propertyName])) { + if (!\array_key_exists($cacheKey, self::$denormalizeCache) || !\array_key_exists($propertyName, self::$denormalizeCache[$cacheKey])) { self::$denormalizeCache[$cacheKey][$propertyName] = $this->getCacheValueForDenormalization($propertyName, $class, $context); } @@ -78,7 +78,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface } $attributesMetadata = $this->metadataFactory->getMetadataFor($class)->getAttributesMetadata(); - if (!isset($attributesMetadata[$propertyName])) { + if (!\array_key_exists($propertyName, $attributesMetadata)) { return null; } @@ -93,7 +93,7 @@ final class MetadataAwareNameConverter implements AdvancedNameConverterInterface private function getCacheValueForDenormalization(string $propertyName, string $class, array $context): ?string { $cacheKey = $this->getCacheKey($class, $context); - if (!isset(self::$attributesMetadataCache[$cacheKey])) { + if (!\array_key_exists($cacheKey, self::$attributesMetadataCache)) { self::$attributesMetadataCache[$cacheKey] = $this->getCacheValueForAttributesMetadata($class, $context); } From 3a840a9796ffdc59f9f3d87d9cbf86b6d3db92e9 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Jan 2020 15:00:15 +0100 Subject: [PATCH 17/18] [Routing] Fix using a custom matcher & generator dumper class --- src/Symfony/Component/Routing/Router.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 003bdc3e29..3f91cd64b2 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -291,7 +291,7 @@ class Router implements RouterInterface, RequestMatcherInterface return $this->matcher; } - $compiled = is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && (UrlMatcher::class === $this->options['matcher_base_class'] || RedirectableUrlMatcher::class === $this->options['matcher_base_class']); + $compiled = is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && (UrlMatcher::class === $this->options['matcher_base_class'] || RedirectableUrlMatcher::class === $this->options['matcher_base_class']) && is_a($this->options['matcher_dumper_class'], CompiledUrlMatcherDumper::class, true); if (null === $this->options['cache_dir'] || null === $this->options['matcher_cache_class']) { $routes = $this->getRouteCollection(); @@ -348,7 +348,7 @@ class Router implements RouterInterface, RequestMatcherInterface return $this->generator; } - $compiled = is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && UrlGenerator::class === $this->options['generator_base_class']; + $compiled = is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && UrlGenerator::class === $this->options['generator_base_class'] && is_a($this->options['generator_dumper_class'], CompiledUrlGeneratorDumper::class, true); if (null === $this->options['cache_dir'] || null === $this->options['generator_cache_class']) { $routes = $this->getRouteCollection(); @@ -398,8 +398,8 @@ class Router implements RouterInterface, RequestMatcherInterface */ protected function getGeneratorDumperInstance() { - // For BC, fallback to PhpGeneratorDumper if the UrlGenerator and UrlGeneratorDumper are not consistent with each other - if (is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) !== is_a($this->options['generator_dumper_class'], CompiledUrlGeneratorDumper::class, true)) { + // For BC, fallback to PhpGeneratorDumper (which is the old default value) if the old UrlGenerator is used with the new default CompiledUrlGeneratorDumper + if (!is_a($this->options['generator_class'], CompiledUrlGenerator::class, true) && is_a($this->options['generator_dumper_class'], CompiledUrlGeneratorDumper::class, true)) { return new PhpGeneratorDumper($this->getRouteCollection()); } @@ -411,8 +411,8 @@ class Router implements RouterInterface, RequestMatcherInterface */ protected function getMatcherDumperInstance() { - // For BC, fallback to PhpMatcherDumper if the UrlMatcher and UrlMatcherDumper are not consistent with each other - if (is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) !== is_a($this->options['matcher_dumper_class'], CompiledUrlMatcherDumper::class, true)) { + // For BC, fallback to PhpMatcherDumper (which is the old default value) if the old UrlMatcher is used with the new default CompiledUrlMatcherDumper + if (!is_a($this->options['matcher_class'], CompiledUrlMatcher::class, true) && is_a($this->options['matcher_dumper_class'], CompiledUrlMatcherDumper::class, true)) { return new PhpMatcherDumper($this->getRouteCollection()); } From 0c320febe1547e6db30c59390ea5e86a4dd7d487 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Jan 2020 17:32:40 +0100 Subject: [PATCH 18/18] [Debug] fix ClassNotFoundFatalErrorHandler --- .../Debug/Tests/Exception/FlattenExceptionTest.php | 12 ++++++++++++ .../ClassNotFoundFatalErrorHandlerTest.php | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php index 0290b05bad..3d163eec77 100644 --- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php @@ -199,6 +199,10 @@ class FlattenExceptionTest extends TestCase public function testArguments() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $dh = opendir(__DIR__); $fh = tmpfile(); @@ -261,6 +265,10 @@ class FlattenExceptionTest extends TestCase public function testRecursionInArguments() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $a = null; $a = ['foo', [2, &$a]]; $exception = $this->createException($a); @@ -272,6 +280,10 @@ class FlattenExceptionTest extends TestCase public function testTooBigArray() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $a = []; for ($i = 0; $i < 20; ++$i) { for ($j = 0; $j < 50; ++$j) { diff --git a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php index 9a56b3b4ec..f356476201 100644 --- a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php @@ -29,6 +29,10 @@ class ClassNotFoundFatalErrorHandlerTest extends TestCase // get class loaders wrapped by DebugClassLoader if ($function[0] instanceof DebugClassLoader) { $function = $function[0]->getClassLoader(); + + if (!\is_array($function)) { + continue; + } } if ($function[0] instanceof ComposerClassLoader) {