From 0e92399daa581eb4d6aba1318c0a97c150c83a1d Mon Sep 17 00:00:00 2001 From: gauss Date: Sat, 2 Nov 2019 19:24:35 +0200 Subject: [PATCH 001/124] [DI] Suggest typed argument when binding fails with untyped argument --- .../Compiler/ResolveBindingsPass.php | 18 +++++++++++++++--- .../Tests/Compiler/ResolveBindingsPassTest.php | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php index dccc75a11bd7e..aa688f4dfdcf4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php @@ -112,6 +112,8 @@ protected function processValue($value, $isRoot = false) return parent::processValue($value, $isRoot); } + $bindingNames = []; + foreach ($bindings as $key => $binding) { list($bindingValue, $bindingId, $used, $bindingType, $file) = $binding->getValues(); if ($used) { @@ -121,7 +123,11 @@ protected function processValue($value, $isRoot = false) $this->unusedBindings[$bindingId] = [$key, $this->currentId, $bindingType, $file]; } - if (preg_match('/^(?:(?:array|bool|float|int|string) )?\$/', $key)) { + if (preg_match('/^(?:(?:array|bool|float|int|string|([^ $]++)) )\$/', $key, $m)) { + $bindingNames[substr($key, \strlen($m[0]))] = $binding; + } + + if (!isset($m[1])) { continue; } @@ -182,11 +188,17 @@ protected function processValue($value, $isRoot = false) continue; } - if (!$typeHint || '\\' !== $typeHint[0] || !isset($bindings[$typeHint = substr($typeHint, 1)])) { + if ($typeHint && '\\' === $typeHint[0] && isset($bindings[$typeHint = substr($typeHint, 1)])) { + $arguments[$key] = $this->getBindingValue($bindings[$typeHint]); + continue; } - $arguments[$key] = $this->getBindingValue($bindings[$typeHint]); + if (isset($bindingNames[$parameter->name])) { + $bindingKey = array_search($binding, $bindings, true); + $argumentType = substr($bindingKey, 0, strpos($bindingKey, ' ')); + $this->errorMessages[] = sprintf('Did you forget to add the type "%s" to argument "$%s" of method "%s::%s()"?', $argumentType, $parameter->name, $reflectionMethod->class, $reflectionMethod->name); + } } if ($arguments !== $call[1]) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php index bb8417098e872..e35ff1edf056e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php @@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; @@ -157,4 +158,19 @@ public function testSyntheticServiceWithBind() $this->assertSame([1 => 'bar'], $container->getDefinition(NamedArgumentsDummy::class)->getArguments()); } + + public function testEmptyBindingTypehint() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Did you forget to add the type "string" to argument "$apiKey" of method "Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy::__construct()"?'); + + $container = new ContainerBuilder(); + $bindings = [ + 'string $apiKey' => new BoundArgument('foo'), + ]; + $definition = $container->register(NamedArgumentsDummy::class, NamedArgumentsDummy::class); + $definition->setBindings($bindings); + $pass = new ResolveBindingsPass(); + $pass->process($container); + } } From ff28a24482b391d15eef83ddf51303d2d975cba5 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 19 Dec 2019 17:23:24 +0100 Subject: [PATCH 002/124] updated CHANGELOG for 4.4.2 --- CHANGELOG-4.4.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index 7bd4ac031e861..8dd0f9779c1fc 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,81 @@ in 4.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.4.0...v4.4.1 +* 4.4.2 (2019-12-19) + + * bug #35051 [DependencyInjection] Fix binding tagged services to containers (nicolas-grekas) + * bug #35039 [DI] skip looking for config class when the extension class is anonymous (nicolas-grekas) + * bug #35049 [ProxyManager] fix generating proxies for root-namespaced classes (nicolas-grekas) + * bug #35022 [Dotenv] FIX missing getenv (mccullagh) + * bug #35023 [HttpKernel] ignore failures generated by opcache.restrict_api (nicolas-grekas) + * bug #35024 [HttpFoundation] fix pdo session handler for sqlsrv (azjezz) + * bug #35025 [HttpClient][Psr18Client] Remove Psr18ExceptionTrait (fancyweb) + * bug #35015 [Config] fix perf of glob discovery when GLOB_BRACE is not available (nicolas-grekas) + * bug #35014 [HttpClient] make pushed responses retry-able (nicolas-grekas) + * bug #35010 [VarDumper] ignore failing __debugInfo() (nicolas-grekas) + * bug #34998 [DI] fix auto-binding service providers to their service subscribers (nicolas-grekas) + * bug #34954 [Mailer] Fixed undefined index when sending via Mandrill API (wulff) + * bug #33670 [DI] Service locators can't be decorated (malarzm) + * bug #35000 [Console][SymfonyQuestionHelper] Handle multibytes question choices keys and custom prompt (fancyweb) + * bug #35005 [HttpClient] force HTTP/1.1 when NTLM auth is used (nicolas-grekas) + * bug #34707 [Validation][FrameworkBundle] Allow EnableAutoMapping to work without auto-mapping namespaces (ogizanagi) + * bug #34996 Fix displaying anonymous classes on PHP 7.4 (nicolas-grekas) + * bug #29839 [Validator] fix comparisons with null values at property paths (xabbuh) + * bug #34900 [DoctrineBridge] Fixed submitting invalid ids when using queries with limit (HeahDude) + * bug #34791 [Serializer] Skip uninitialized (PHP 7.4) properties in PropertyNormalizer and ObjectNormalizer (vudaltsov) + * bug #34956 [Messenger][AMQP] Use delivery_mode=2 by default (lyrixx) + * bug #34915 [FrameworkBundle] Fix invalid Windows path normalization in TemplateNameParser (mvorisek) + * bug #34981 stop using deprecated Doctrine persistence classes (xabbuh) + * bug #34904 [Validator][ConstraintValidator] Safe fail on invalid timezones (fancyweb) + * bug #34935 [FrameworkBundle][DependencyInjection] Skip removed ids in the lint container command and its associated pass (fancyweb) + * bug #34957 [Security] Revert "AbstractAuthenticationListener.php error instead info" (larzuk91) + * bug #34922 [FrameworkBundle][Secrets] Hook configured local dotenv file (fancyweb) + * bug #34967 [HttpFoundation] fix redis multi host dsn not recognized (Jan Christoph Beyer) + * bug #34963 [Lock] fix constructor argument type declaration (xabbuh) + * bug #34955 Require doctrine/persistence ^1.3 (nicolas-grekas) + * bug #34923 [DI] Fix support for immutable setters in CallTrait (Lctrs) + * bug #34878 [TwigBundle] fix broken FilesystemLoader::exists() with Twig 3 (dpesch) + * bug #34921 [HttpFoundation] Removed "Content-Type" from the preferred format guessing mechanism (yceruto) + * bug #34886 [HttpKernel] fix triggering deprecation in file locator (xabbuh) + * bug #34918 [Translation] fix memoryleak in PhpFileLoader (nicolas-grekas) + * bug #34920 [Routing] fix memoryleak when loading compiled routes (nicolas-grekas) + * bug #34787 [Cache] Propagate expiry when syncing items in ChainAdapter (trvrnrth) + * bug #34694 [Validator] Fix auto-mapping constraints should not be validated (ogizanagi) + * bug #34848 [Process] change the syntax of portable command lines (nicolas-grekas) + * bug #34862 [FrameworkBundle][ContainerLintCommand] Reinitialize bundles when the container is reprepared (fancyweb) + * bug #34896 [Cache] fix memory leak when using PhpFilesAdapter (nicolas-grekas) + * bug #34438 [HttpFoundation] Use `Cache-Control: must-revalidate` only if explicit lifetime has been given (mpdude) + * bug #34449 [Yaml] Implement multiline string as scalar block for tagged values (natepage) + * bug #34601 [MonologBridge] Fix debug processor datetime type (mRoca) + * bug #34842 [ExpressionLanguage] Process division by zero (tigr1991) + * bug #34902 [PropertyAccess] forward caught exception (xabbuh) + * bug #34903 Fixing bad order of operations with null coalescing operator (weaverryan) + * bug #34888 [TwigBundle] add tags before processing them (xabbuh) + * bug #34760 [Mailer] Fix SMTP Authentication when using STARTTLS (DjLeChuck) + * bug #34762 [Config] never try loading failed classes twice with ClassExistenceResource (nicolas-grekas) + * bug #34783 [DependencyInjection] Handle env var placeholders in CheckTypeDeclarationsPass (fancyweb) + * bug #34839 [Cache] fix memory leak when using PhpArrayAdapter (nicolas-grekas) + * bug #34812 [Yaml] fix parsing negative octal numbers (xabbuh) + * bug #34854 [Messenger] gracefully handle missing event dispatchers (xabbuh) + * bug #34802 [Security] Check UserInterface::getPassword is not null before calling needsRehash (dbrekelmans) + * bug #34788 [SecurityBundle] Properly escape regex in AddSessionDomainConstraintPass (fancyweb) + * bug #34859 [SecurityBundle] Fix TokenStorage::reset not called in stateless firewall (jderusse) + * bug #34827 [HttpFoundation] get currently session.gc_maxlifetime if ttl doesnt exists (rafaeltovar) + * bug #34755 [FrameworkBundle] resolve service locators in `debug:*` commands (nicolas-grekas) + * bug #34832 [Validator] Allow underscore character "_" in URL username and password (romainneutron) + * bug #34811 [TwigBridge] Update bootstrap_4_layout.html.twig missing switch-custom label (sabruss) + * bug #34820 [FrameworkBundle][SodiumVault] Create secrets directory only when it is used (fancyweb) + * bug #34776 [DI] fix resolving bindings for named TypedReference (nicolas-grekas) + * bug #34794 [DependencyInjection] Resolve expressions in CheckTypeDeclarationsPass (fancyweb) + * bug #34797 [Translation] Fix FileDumper behavior (yceruto) + * bug #34738 [SecurityBundle] Passwords are not encoded when algorithm set to "true" (nieuwenhuisen) + * bug #34759 [SecurityBundle] Fix switch_user provider configuration handling (fancyweb) + * bug #34779 [Security] do not validate passwords when the hash is null (xabbuh) + * bug #34786 [SecurityBundle] Use config variable in AnonymousFactory (martijnboers) + * bug #34784 [FrameworkBundle] Set the parameter bag as resolved in ContainerLintCommand (fancyweb) + * bug #34763 [Security/Core] Fix checking for SHA256/SHA512 passwords (David Brooks) + * bug #34757 [DI] Fix making the container path-independent when the app is in /app (nicolas-grekas) + * 4.4.1 (2019-12-01) * bug #34732 [DependencyInjection][Xml] Fix the attribute 'tag' is not allowed in 'bind' tag (tienvx) From 7fe9115db5cfc63eb292dd0e9cb061ad120d9b6f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 19 Dec 2019 17:23:40 +0100 Subject: [PATCH 003/124] updated VERSION for 4.4.2 --- 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 d464259f303e4..ceebec87a93f2 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '4.4.2-DEV'; + const VERSION = '4.4.2'; const VERSION_ID = 40402; const MAJOR_VERSION = 4; const MINOR_VERSION = 4; const RELEASE_VERSION = 2; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2022'; const END_OF_LIFE = '11/2023'; From 6dc0c3835182f9c31ab5d3690d9c5451fcda6dc4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 19 Dec 2019 19:32:23 +0100 Subject: [PATCH 004/124] bumped Symfony version to 4.4.3 --- 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 ceebec87a93f2..f21a88b3b44d4 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '4.4.2'; - const VERSION_ID = 40402; + const VERSION = '4.4.3-DEV'; + const VERSION_ID = 40403; const MAJOR_VERSION = 4; const MINOR_VERSION = 4; - const RELEASE_VERSION = 2; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 3; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2022'; const END_OF_LIFE = '11/2023'; From 10d26470bd58032a85ff41dbf7b565718f54f8ed Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 19 Dec 2019 19:38:31 +0100 Subject: [PATCH 005/124] bumped Symfony version to 5.0.3 --- 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 2394fac7b0f4d..4e6770e4ecd1a 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -68,12 +68,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '5.0.2'; - const VERSION_ID = 50002; + const VERSION = '5.0.3-DEV'; + const VERSION_ID = 50003; const MAJOR_VERSION = 5; const MINOR_VERSION = 0; - const RELEASE_VERSION = 2; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 3; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '07/2020'; const END_OF_LIFE = '07/2020'; From 665ef06013371d7fbe896bc8a427474804a99f63 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 19 Dec 2019 23:40:59 +0100 Subject: [PATCH 006/124] [Security] Fix missing defaults for auto-migrating encoders --- .../Security/Core/Encoder/EncoderFactory.php | 12 ++++++------ .../Core/Tests/Encoder/EncoderFactoryTest.php | 5 +++++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index 4bc9596ce3f8c..cad50180d181e 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -144,10 +144,10 @@ private function getEncoderConfigFromAlgorithm(array $config): array return [ 'class' => Pbkdf2PasswordEncoder::class, 'arguments' => [ - $config['hash_algorithm'], - $config['encode_as_base64'], - $config['iterations'], - $config['key_length'], + $config['hash_algorithm'] ?? 'sha512', + $config['encode_as_base64'] ?? true, + $config['iterations'] ?? 1000, + $config['key_length'] ?? 40, ], ]; @@ -205,8 +205,8 @@ private function getEncoderConfigFromAlgorithm(array $config): array 'class' => MessageDigestPasswordEncoder::class, 'arguments' => [ $config['algorithm'], - $config['encode_as_base64'], - $config['iterations'], + $config['encode_as_base64'] ?? true, + $config['iterations'] ?? 5000, ], ]; } diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php index a25f23528708e..44cecafecd2ba 100644 --- a/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php @@ -162,6 +162,11 @@ public function testDefaultMigratingEncoders() (new EncoderFactory([SomeUser::class => ['class' => NativePasswordEncoder::class, 'arguments' => []]]))->getEncoder(SomeUser::class) ); + $this->assertInstanceOf( + MigratingPasswordEncoder::class, + (new EncoderFactory([SomeUser::class => ['algorithm' => 'bcrypt', 'cost' => 11]]))->getEncoder(SomeUser::class) + ); + if (!SodiumPasswordEncoder::isSupported()) { return; } From d3942cbe17cb972d50aecfa44936ac36014d592c Mon Sep 17 00:00:00 2001 From: Lynn Date: Fri, 20 Dec 2019 16:07:22 +0100 Subject: [PATCH 007/124] Use supportsClass where possible --- .../Core/Tests/User/ChainUserProviderTest.php | 61 ++++++++++++++++++- .../Security/Core/User/ChainUserProvider.php | 4 ++ .../Http/Firewall/ContextListener.php | 7 ++- .../Tests/Firewall/ContextListenerTest.php | 28 ++++++--- 4 files changed, 88 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php b/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php index 1592bcd2fe8e8..cf4909dfe8829 100644 --- a/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php @@ -68,24 +68,49 @@ public function testRefreshUser() $provider1 = $this->getProvider(); $provider1 ->expects($this->once()) - ->method('refreshUser') - ->willThrowException(new UnsupportedUserException('unsupported')) + ->method('supportsClass') + ->willReturn(false) ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 + ->expects($this->once()) + ->method('refreshUser') + ->willThrowException(new UnsupportedUserException('unsupported')) + ; + + $provider3 = $this->getProvider(); + $provider3 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + + $provider3 ->expects($this->once()) ->method('refreshUser') ->willReturn($account = $this->getAccount()) ; - $provider = new ChainUserProvider([$provider1, $provider2]); + $provider = new ChainUserProvider([$provider1, $provider2, $provider3]); $this->assertSame($account, $provider->refreshUser($this->getAccount())); } public function testRefreshUserAgain() { $provider1 = $this->getProvider(); + $provider1 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider1 ->expects($this->once()) ->method('refreshUser') @@ -93,6 +118,12 @@ public function testRefreshUserAgain() ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 ->expects($this->once()) ->method('refreshUser') @@ -107,6 +138,12 @@ public function testRefreshUserThrowsUnsupportedUserException() { $this->expectException('Symfony\Component\Security\Core\Exception\UnsupportedUserException'); $provider1 = $this->getProvider(); + $provider1 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider1 ->expects($this->once()) ->method('refreshUser') @@ -114,6 +151,12 @@ public function testRefreshUserThrowsUnsupportedUserException() ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 ->expects($this->once()) ->method('refreshUser') @@ -171,6 +214,12 @@ public function testSupportsClassWhenNotSupported() public function testAcceptsTraversable() { $provider1 = $this->getProvider(); + $provider1 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider1 ->expects($this->once()) ->method('refreshUser') @@ -178,6 +227,12 @@ public function testAcceptsTraversable() ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 ->expects($this->once()) ->method('refreshUser') diff --git a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php index 02ce08464d218..5ea8150a3017e 100644 --- a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php @@ -73,6 +73,10 @@ public function refreshUser(UserInterface $user) foreach ($this->providers as $provider) { try { + if (!$provider->supportsClass(\get_class($user))) { + continue; + } + return $provider->refreshUser($user); } catch (UnsupportedUserException $e) { // try next one diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index ea9f51f9224ad..6a05ee5175cb1 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -168,12 +168,17 @@ protected function refreshUser(TokenInterface $token) $userNotFoundByProvider = false; $userDeauthenticated = false; + $userClass = \get_class($user); foreach ($this->userProviders as $provider) { if (!$provider instanceof UserProviderInterface) { throw new \InvalidArgumentException(sprintf('User provider "%s" must implement "%s".', \get_class($provider), UserProviderInterface::class)); } + if (!$provider->supportsClass($userClass)) { + continue; + } + try { $refreshedUser = $provider->refreshUser($user); $newToken = clone $token; @@ -233,7 +238,7 @@ protected function refreshUser(TokenInterface $token) return null; } - throw new \RuntimeException(sprintf('There is no user provider for user "%s".', \get_class($user))); + throw new \RuntimeException(sprintf('There is no user provider for user "%s".', $userClass)); } private function safelyUnserialize($serializedToken) diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index acab7087cb92f..74c459604cc8c 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -256,7 +256,7 @@ public function testIfTokenIsDeauthenticatedTriggersDeprecations() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)]); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)]); $this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser()); } @@ -265,7 +265,7 @@ public function testIfTokenIsDeauthenticated() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], null, true); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], null, true); $this->assertNull($tokenStorage->getToken()); } @@ -287,7 +287,7 @@ public function testRememberMeGetsCanceledIfTokenIsDeauthenticated() $rememberMeServices = $this->createMock(RememberMeServicesInterface::class); $rememberMeServices->expects($this->once())->method('loginFail'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], null, true, $rememberMeServices); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], null, true, $rememberMeServices); $this->assertNull($tokenStorage->getToken()); } @@ -296,7 +296,7 @@ public function testTryAllUserProvidersUntilASupportingUserProviderIsFound() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], $refreshedUser); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], $refreshedUser); $this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser()); } @@ -313,7 +313,7 @@ public function testNextSupportingUserProviderIsTriedIfPreviousSupportingUserPro public function testTokenIsSetToNullIfNoUserWasLoadedByTheRegisteredUserProviders() { $tokenStorage = new TokenStorage(); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider()]); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider()]); $this->assertNull($tokenStorage->getToken()); } @@ -321,14 +321,14 @@ public function testTokenIsSetToNullIfNoUserWasLoadedByTheRegisteredUserProvider public function testRuntimeExceptionIsThrownIfNoSupportingUserProviderWasRegistered() { $this->expectException('RuntimeException'); - $this->handleEventWithPreviousSession(new TokenStorage(), [new NotSupportingUserProvider(), new NotSupportingUserProvider()]); + $this->handleEventWithPreviousSession(new TokenStorage(), [new NotSupportingUserProvider(false), new NotSupportingUserProvider(true)]); } public function testAcceptsProvidersAsTraversable() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, new \ArrayObject([new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)]), $refreshedUser); + $this->handleEventWithPreviousSession($tokenStorage, new \ArrayObject([new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)]), $refreshedUser); $this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser()); } @@ -383,6 +383,14 @@ private function handleEventWithPreviousSession(TokenStorageInterface $tokenStor class NotSupportingUserProvider implements UserProviderInterface { + /** @var bool */ + private $throwsUnsupportedException; + + public function __construct($throwsUnsupportedException) + { + $this->throwsUnsupportedException = $throwsUnsupportedException; + } + public function loadUserByUsername($username) { throw new UsernameNotFoundException(); @@ -390,7 +398,11 @@ public function loadUserByUsername($username) public function refreshUser(UserInterface $user) { - throw new UnsupportedUserException(); + if ($this->throwsUnsupportedException) { + throw new UnsupportedUserException(); + } + + return $user; } public function supportsClass($class) From d6a7fbfbc3c988068754e519ae70ace62a7944a7 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 20 Dec 2019 17:42:47 +0100 Subject: [PATCH 008/124] [DependencyInjection][CheckTypeDeclarationsPass] Handle \Closure for callable --- .../Compiler/CheckTypeDeclarationsPass.php | 2 +- .../Compiler/CheckTypeDeclarationsPassTest.php | 16 ++++++++++++++++ .../CheckTypeDeclarationsPass/BarMethodCall.php | 4 ++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index 0743cbbb5ff1a..4bbcedbf124a2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -166,7 +166,7 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar return; } - if ('callable' === $type && method_exists($class, '__invoke')) { + if ('callable' === $type && (\Closure::class === $class || method_exists($class, '__invoke'))) { return; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php index 13c34e156c67a..22a29fa4d6dc0 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -681,4 +681,20 @@ public function testProcessSkipSkippedIds() $this->addToAssertionCount(1); } + + public function testProcessHandleClosureForCallable() + { + $closureDefinition = new Definition(\Closure::class); + $closureDefinition->setFactory([\Closure::class, 'fromCallable']); + $closureDefinition->setArguments(['strlen']); + + $container = new ContainerBuilder(); + $container + ->register('foobar', BarMethodCall::class) + ->addMethodCall('setCallable', [$closureDefinition]); + + (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 c308ef9545710..b7056016094a1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/BarMethodCall.php @@ -36,4 +36,8 @@ public function setArray(array $array) public function setIterable(iterable $iterable) { } + + public function setCallable(callable $callable): void + { + } } From 3bfa8dbb188d494c2c4561c87404d081e53052f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 28 Nov 2019 09:05:29 +0100 Subject: [PATCH 009/124] Migrate server:log command away from WebServerBundle --- src/Symfony/Bridge/Monolog/CHANGELOG.md | 1 + .../Monolog/Command/ServerLogCommand.php | 159 ++++++++++++++++++ .../Bundle/DebugBundle/DebugBundle.php | 2 + .../RemoveWebServerBundleLoggerPass.php | 31 ++++ .../DependencyInjection/DebugExtension.php | 5 + .../DebugBundle/Resources/config/services.xml | 4 + .../Command/ServerLogCommand.php | 4 +- 7 files changed, 204 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php create mode 100644 src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php diff --git a/src/Symfony/Bridge/Monolog/CHANGELOG.md b/src/Symfony/Bridge/Monolog/CHANGELOG.md index e2439304faec0..9deec49664ae3 100644 --- a/src/Symfony/Bridge/Monolog/CHANGELOG.md +++ b/src/Symfony/Bridge/Monolog/CHANGELOG.md @@ -6,6 +6,7 @@ CHANGELOG * The `RouteProcessor` class has been made final * Added `ElasticsearchLogstashHandler` +* Added the `ServerLogCommand`. Backport from the deprecated WebServerBundle 4.3.0 ----- diff --git a/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php b/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php new file mode 100644 index 0000000000000..60e7341db9e2c --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Command; + +use Monolog\Formatter\FormatterInterface; +use Monolog\Logger; +use Symfony\Bridge\Monolog\Formatter\ConsoleFormatter; +use Symfony\Bridge\Monolog\Handler\ConsoleHandler; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Input\InputOption; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\ExpressionLanguage\ExpressionLanguage; + +/** + * @author Grégoire Pineau + */ +class ServerLogCommand extends Command +{ + private static $bgColor = ['black', 'blue', 'cyan', 'green', 'magenta', 'red', 'white', 'yellow']; + + private $el; + private $handler; + + protected static $defaultName = 'server:log'; + + public function isEnabled() + { + if (!class_exists(ConsoleFormatter::class)) { + return false; + } + + // based on a symfony/symfony package, it crashes due a missing FormatterInterface from monolog/monolog + if (!interface_exists(FormatterInterface::class)) { + return false; + } + + return parent::isEnabled(); + } + + protected function configure() + { + if (!class_exists(ConsoleFormatter::class)) { + return; + } + + $this + ->addOption('host', null, InputOption::VALUE_REQUIRED, 'The server host', '0.0.0.0:9911') + ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The line format', ConsoleFormatter::SIMPLE_FORMAT) + ->addOption('date-format', null, InputOption::VALUE_REQUIRED, 'The date format', ConsoleFormatter::SIMPLE_DATE) + ->addOption('filter', null, InputOption::VALUE_REQUIRED, 'An expression to filter log. Example: "level > 200 or channel in [\'app\', \'doctrine\']"') + ->setDescription('Starts a log server that displays logs in real time') + ->setHelp(<<<'EOF' +%command.name% starts a log server to display in real time the log +messages generated by your application: + + php %command.full_name% + +To get the information as a machine readable format, use the +--filter option: + +php %command.full_name% --filter=port +EOF + ) + ; + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $filter = $input->getOption('filter'); + if ($filter) { + if (!class_exists(ExpressionLanguage::class)) { + throw new LogicException('Package "symfony/expression-language" is required to use the "filter" option.'); + } + $this->el = new ExpressionLanguage(); + } + + $this->handler = new ConsoleHandler($output, true, [ + OutputInterface::VERBOSITY_NORMAL => Logger::DEBUG, + ]); + + $this->handler->setFormatter(new ConsoleFormatter([ + 'format' => str_replace('\n', "\n", $input->getOption('format')), + 'date_format' => $input->getOption('date-format'), + 'colors' => $output->isDecorated(), + 'multiline' => OutputInterface::VERBOSITY_DEBUG <= $output->getVerbosity(), + ])); + + if (false === strpos($host = $input->getOption('host'), '://')) { + $host = 'tcp://'.$host; + } + + if (!$socket = stream_socket_server($host, $errno, $errstr)) { + throw new RuntimeException(sprintf('Server start failed on "%s": %s %s.', $host, $errstr, $errno)); + } + + foreach ($this->getLogs($socket) as $clientId => $message) { + $record = unserialize(base64_decode($message)); + + // Impossible to decode the message, give up. + if (false === $record) { + continue; + } + + if ($filter && !$this->el->evaluate($filter, $record)) { + continue; + } + + $this->displayLog($output, $clientId, $record); + } + + return 0; + } + + private function getLogs($socket): iterable + { + $sockets = [(int) $socket => $socket]; + $write = []; + + while (true) { + $read = $sockets; + stream_select($read, $write, $write, null); + + foreach ($read as $stream) { + if ($socket === $stream) { + $stream = stream_socket_accept($socket); + $sockets[(int) $stream] = $stream; + } elseif (feof($stream)) { + unset($sockets[(int) $stream]); + fclose($stream); + } else { + yield (int) $stream => fgets($stream); + } + } + } + } + + private function displayLog(OutputInterface $output, int $clientId, array $record) + { + if (isset($record['log_id'])) { + $clientId = unpack('H*', $record['log_id'])[1]; + } + $logBlock = sprintf(' ', self::$bgColor[$clientId % 8]); + $output->write($logBlock); + + $this->handler->handle($record); + } +} diff --git a/src/Symfony/Bundle/DebugBundle/DebugBundle.php b/src/Symfony/Bundle/DebugBundle/DebugBundle.php index 04fd507612747..fd7d8e72d6a4c 100644 --- a/src/Symfony/Bundle/DebugBundle/DebugBundle.php +++ b/src/Symfony/Bundle/DebugBundle/DebugBundle.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\DebugBundle; use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\DumpDataCollectorPass; +use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\RemoveWebServerBundleLoggerPass; use Symfony\Component\Console\Application; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -52,6 +53,7 @@ public function build(ContainerBuilder $container) parent::build($container); $container->addCompilerPass(new DumpDataCollectorPass()); + $container->addCompilerPass(new RemoveWebServerBundleLoggerPass()); } public function registerCommands(Application $application) diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php new file mode 100644 index 0000000000000..aca150c816101 --- /dev/null +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\DebugBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * @author Jérémy Derussé + */ +class RemoveWebServerBundleLoggerPass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if ($container->hasDefinition('web_server.command.server_log') && $container->hasDefinition('monolog.command.server_log')) { + $container->removeDefinition('web_server.command.server_log'); + } + } +} diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php index 8309db19ecd7c..2528cce5b83a7 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/DebugExtension.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\DebugBundle\DependencyInjection; +use Symfony\Bridge\Monolog\Command\ServerLogCommand; use Symfony\Bundle\DebugBundle\Command\ServerDumpPlaceholderCommand; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; @@ -90,6 +91,10 @@ public function load(array $configs, ContainerBuilder $container) ]]) ; } + + if (!class_exists(ServerLogCommand::class)) { + $container->removeDefinition('monolog.command.server_log'); + } } /** diff --git a/src/Symfony/Bundle/DebugBundle/Resources/config/services.xml b/src/Symfony/Bundle/DebugBundle/Resources/config/services.xml index 49772b46962f7..c7cc5725cf8f8 100644 --- a/src/Symfony/Bundle/DebugBundle/Resources/config/services.xml +++ b/src/Symfony/Bundle/DebugBundle/Resources/config/services.xml @@ -107,5 +107,9 @@ + + + + diff --git a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php index f38fd6fa58ee6..1eb1916a3f129 100644 --- a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php +++ b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php @@ -26,7 +26,7 @@ /** * @author Grégoire Pineau * - * @deprecated since Symfony 4.4, to be removed in 5.0; the new Symfony local server has more features, you can use it instead. + * @deprecated since Symfony 4.4, to be removed in 5.0; use ServerLogCommand from symfony/monolog-bridge instead */ class ServerLogCommand extends Command { @@ -80,7 +80,7 @@ protected function configure() protected function execute(InputInterface $input, OutputInterface $output) { - @trigger_error('Using the WebserverBundle is deprecated since Symfony 4.4. The new Symfony local server has more features, you can use it instead.', E_USER_DEPRECATED); + @trigger_error('Using the WebserverBundle is deprecated since Symfony 4.4. Use the DebugBundle combined with MonologBridge instead.', E_USER_DEPRECATED); $filter = $input->getOption('filter'); if ($filter) { From 429605b2133fea1973bbfa6b117a6259e756d4dd Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Mon, 23 Dec 2019 10:53:34 -0500 Subject: [PATCH 010/124] add note about HTTP status code change --- UPGRADE-4.4.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/UPGRADE-4.4.md b/UPGRADE-4.4.md index 3409bea3b5b66..bcdee9ca1311f 100644 --- a/UPGRADE-4.4.md +++ b/UPGRADE-4.4.md @@ -306,7 +306,7 @@ TwigBundle The new default exception controller will also change the error response content according to https://tools.ietf.org/html/rfc7807 for `json`, `xml`, `atom` and `txt` formats: - Before: + Before (HTTP status code `200`): ```json { "error": { @@ -316,7 +316,7 @@ TwigBundle } ``` - After: + After (HTTP status code `404`): ```json { "title": "Not Found", From dcb7c9a4849f0da1002a64c3713063fdd8ca0b92 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 23 Dec 2019 19:25:43 +0100 Subject: [PATCH 011/124] [String][UnicodeString] Remove unneeded flag in chunk regex pattern --- src/Symfony/Component/String/UnicodeString.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/String/UnicodeString.php b/src/Symfony/Component/String/UnicodeString.php index d7df6f5e1400b..ada77caaae4c0 100644 --- a/src/Symfony/Component/String/UnicodeString.php +++ b/src/Symfony/Component/String/UnicodeString.php @@ -71,7 +71,7 @@ public function chunk(int $length = 1): array $rx .= '\X{65535}'; $length -= 65535; } - $rx .= '\X{'.$length.'})/us'; + $rx .= '\X{'.$length.'})/u'; $str = clone $this; $chunks = []; From 589e93e3b70f3c4ac6f1fc2c81f5349e676b3e0c Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 23 Dec 2019 21:21:28 +0100 Subject: [PATCH 012/124] [Console] Fix filtering out identical alternatives when there is a command loader --- src/Symfony/Component/Console/Application.php | 13 +++++++------ .../Component/Console/Tests/ApplicationTest.php | 3 +++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index d181e41e80c46..1463967ffae08 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -645,8 +645,13 @@ public function find($name) // filter out aliases for commands which are already on the list if (\count($commands) > 1) { $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; - $commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands, &$aliases) { - $commandName = $commandList[$nameOrAlias] instanceof Command ? $commandList[$nameOrAlias]->getName() : $nameOrAlias; + $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) { + if (!$commandList[$nameOrAlias] instanceof Command) { + $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); + } + + $commandName = $commandList[$nameOrAlias]->getName(); + $aliases[$nameOrAlias] = $commandName; return $commandName === $nameOrAlias || !\in_array($commandName, $commands); @@ -662,10 +667,6 @@ public function find($name) $maxLen = max(Helper::strlen($abbrev), $maxLen); } $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) { - if (!$commandList[$cmd] instanceof Command) { - $commandList[$cmd] = $this->commandLoader->get($cmd); - } - if ($commandList[$cmd]->isHidden()) { return false; } diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 30c0688ac7aac..559c42599fbdd 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -568,6 +568,9 @@ public function testFindAlternativeCommandsWithAnAlias() $fooCommand->setAliases(['foo2']); $application = new Application(); + $application->setCommandLoader(new FactoryCommandLoader([ + 'foo3' => static function () use ($fooCommand) { return $fooCommand; }, + ])); $application->add($fooCommand); $result = $application->find('foo'); From 2f608b4dfa43217fdefe7ac71644edc6e00278b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 24 Dec 2019 14:11:19 +0100 Subject: [PATCH 013/124] Do not throw exception on valut generate key --- src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php index 883a68613c540..047d8d5804009 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php +++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php @@ -47,7 +47,9 @@ public function generateKeys(bool $override = false): bool $this->lastMessage = null; if (null === $this->encryptionKey && '' !== $this->decryptionKey = (string) $this->decryptionKey) { - throw new \LogicException('Cannot generate keys when a decryption key has been provided while instantiating the vault.'); + $this->lastMessage = 'Cannot generate keys when a decryption key has been provided while instantiating the vault.'; + + return false; } try { From 3657c0e664bfb1a62f9fea9a898406909a1e130b Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Tue, 24 Dec 2019 19:50:33 +0100 Subject: [PATCH 014/124] Use locale_parse for computing fallback locales --- .../Translation/Tests/TranslatorTest.php | 31 ++++++++++++++++--- .../Component/Translation/Translator.php | 13 +++++++- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 77af7de33efea..68122b2915970 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -234,15 +234,38 @@ public function testTransWithFallbackLocaleFile($format, $loader) $this->assertEquals('bar', $translator->trans('foo', [], 'resources')); } - public function testTransWithFallbackLocaleBis() + /** + * @dataProvider getFallbackLocales + */ + public function testTransWithFallbackLocaleBis($expectedLocale, $locale) { - $translator = new Translator('en_US'); + $translator = new Translator($locale); $translator->addLoader('array', new ArrayLoader()); - $translator->addResource('array', ['foo' => 'foofoo'], 'en_US'); - $translator->addResource('array', ['bar' => 'foobar'], 'en'); + $translator->addResource('array', ['foo' => 'foofoo'], $locale); + $translator->addResource('array', ['bar' => 'foobar'], $expectedLocale); $this->assertEquals('foobar', $translator->trans('bar')); } + public function getFallbackLocales() + { + $locales = [ + ['en', 'en_US'], + ['en', 'en-US'], + ['sl_Latn_IT', 'sl_Latn_IT_nedis'], + ['sl_Latn', 'sl_Latn_IT'], + ]; + + if (\function_exists('locale_parse')) { + $locales[] = ['sl_Latn_IT', 'sl-Latn-IT-nedis']; + $locales[] = ['sl_Latn', 'sl-Latn-IT']; + } else { + $locales[] = ['sl-Latn-IT', 'sl-Latn-IT-nedis']; + $locales[] = ['sl-Latn', 'sl-Latn-IT']; + } + + return $locales; + } + public function testTransWithFallbackLocaleTer() { $translator = new Translator('fr_FR'); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index e72d20a86f512..1bda62d1b11af 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -412,8 +412,19 @@ protected function computeFallbackLocales($locale) $locales[] = $fallback; } - if (false !== strrchr($locale, '_')) { + if (\function_exists('locale_parse')) { + $localeSubTags = locale_parse($locale); + if (1 < \count($localeSubTags)) { + array_pop($localeSubTags); + $fallback = locale_compose($localeSubTags); + if (false !== $fallback) { + array_unshift($locales, $fallback); + } + } + } elseif (false !== strrchr($locale, '_')) { array_unshift($locales, substr($locale, 0, -\strlen(strrchr($locale, '_')))); + } elseif (false !== strrchr($locale, '-')) { + array_unshift($locales, substr($locale, 0, -\strlen(strrchr($locale, '-')))); } return array_unique($locales); From 6eeec7c270ed07c04f7323321816e38364cc3ee5 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Thu, 19 Dec 2019 18:52:42 +0000 Subject: [PATCH 015/124] Fixed test added in #35022 --- src/Symfony/Component/Dotenv/Tests/DotenvTest.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 965f368643d81..43607d35550b6 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -320,9 +320,12 @@ public function testGetVariablesValueFromGetenv() putenv('Foo=Bar'); $dotenv = new Dotenv(true); - $values = $dotenv->parse('Foo=${Foo}'); - $this->assertSame('Bar', $values['Foo']); - putenv('Foo'); + try { + $values = $dotenv->parse('Foo=${Foo}'); + $this->assertSame('Bar', $values['Foo']); + } finally { + putenv('Foo'); + } } } From 36f07b7e09721efbdf174d6e46478833c7719ca5 Mon Sep 17 00:00:00 2001 From: Islam93 Date: Fri, 20 Dec 2019 15:44:59 +0300 Subject: [PATCH 016/124] ticket-30197 [Validator] Add the missing translations for the Chinese (Taiwan) ("zh_TW") locale --- .../translations/validators.zh_TW.xlf | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index d9d5f2f622b43..7cef875f5812e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -278,6 +278,94 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. 該值不應與 {{ compared_value_type }} {{ compared_value }} 相同。 + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + 圖像格式過大 ({{ ratio }})。 最大允許尺寸 {{ max_ratio }}。 + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + 圖像格式過小 ({{ ratio }})。最小尺寸 {{ min_ratio }}。 + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + 方形圖像 ({{ width }}x{{ height }}px)。不接受方形圖像。 + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + 紀念冊布局圖像 ({{ width }}x{{ height }}px)。 不接受紀念冊布局圖像。 + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + 書籍布局圖像 ({{ width }}x{{ height }}px)。不接受圖像書籍布局。 + + + An empty file is not allowed. + 不接受空白文件。 + + + The host could not be resolved. + 未找到服務器。 + + + This value does not match the expected {{ charset }} charset. + 該數值不符合預期 {{ charset }} 符號編碼。 + + + This is not a valid Business Identifier Code (BIC). + 無效企業識別碼 (BIC)。 + + + Error. + 錯誤。 + + + This is not a valid UUID. + 無效的通用唯壹標識符 (UUID)。 + + + This value should be a multiple of {{ compared_value }}. + 該值必須是倍數 {{ compared_value }}。 + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + 該企業識別碼 (BIC) 與銀行賬戶國際編號不壹致 (IBAN) {{ iban }}。 + + + This value should be valid JSON. + 該數值必須序列化為JSON格式。 + + + This collection should contain only unique elements. + 該集合應僅包含唯壹元素。 + + + This value should be positive. + 數值應為正數。 + + + This value should be either positive or zero. + 數值應或未正數,或為零。 + + + This value should be negative. + 數值應為負數。 + + + This value should be either negative or zero. + 數值應或未負數,或為零。 + + + This value is not a valid timezone. + 無效時區。 + + + This password has been leaked in a data breach, it must not be used. Please use another password. + 依據您的密碼,發生數據泄露,請勿使用改密碼。請更換密碼。 + + + This value should be between {{ min }} and {{ max }}. + 該數值應在 {{ min }} 和 {{ max }} 之間。 + From 4557221597e6def8e417cb1bc4099bcf6da5f01c Mon Sep 17 00:00:00 2001 From: Shaharia Azam Date: Sat, 21 Dec 2019 04:43:02 +0600 Subject: [PATCH 017/124] X-Accel Nginx URL updated Obsolete URL has been updated --- src/Symfony/Component/HttpFoundation/BinaryFileResponse.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index ea7ac846974bd..c2f66d6952ab2 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -217,7 +217,7 @@ public function prepare(Request $request) } if ('x-accel-redirect' === strtolower($type)) { // Do X-Accel-Mapping substitutions. - // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect + // @link https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-redirect foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) { $mapping = explode('=', $mapping, 2); From 9bf46f88fb287083029f837c52ee8c3c074e50d3 Mon Sep 17 00:00:00 2001 From: Philippe Segatori Date: Sun, 22 Dec 2019 00:12:27 +0100 Subject: [PATCH 018/124] Add supported schemes doc blocks type --- .../Notifier/Exception/UnsupportedSchemeException.php | 3 +++ .../Component/Notifier/Transport/AbstractTransportFactory.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php index 31e5eed341e5e..c61446339ae5c 100644 --- a/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php +++ b/src/Symfony/Component/Notifier/Exception/UnsupportedSchemeException.php @@ -40,6 +40,9 @@ class UnsupportedSchemeException extends LogicException ], ]; + /** + * @param string[] $supported + */ public function __construct(Dsn $dsn, string $name = null, array $supported = []) { $provider = $dsn->getScheme(); diff --git a/src/Symfony/Component/Notifier/Transport/AbstractTransportFactory.php b/src/Symfony/Component/Notifier/Transport/AbstractTransportFactory.php index be92b3c57883b..2b0cae4b20c11 100644 --- a/src/Symfony/Component/Notifier/Transport/AbstractTransportFactory.php +++ b/src/Symfony/Component/Notifier/Transport/AbstractTransportFactory.php @@ -39,6 +39,9 @@ public function supports(Dsn $dsn): bool return \in_array($dsn->getScheme(), $this->getSupportedSchemes()); } + /** + * @return string[] + */ abstract protected function getSupportedSchemes(): array; protected function getUser(Dsn $dsn): string From 1c92e9e2f14ee97fc1fdeccfddbbc69804c32c40 Mon Sep 17 00:00:00 2001 From: Ruud Kamphuis Date: Wed, 25 Dec 2019 17:22:15 +0100 Subject: [PATCH 019/124] Use spaces correctly to display options in DebugCommand --- .../Component/Messenger/Command/DebugCommand.php | 4 ++-- .../Messenger/Tests/Command/DebugCommandTest.php | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/DebugCommand.php b/src/Symfony/Component/Messenger/Command/DebugCommand.php index 2fba6f02f5122..08b76d1c19410 100644 --- a/src/Symfony/Component/Messenger/Command/DebugCommand.php +++ b/src/Symfony/Component/Messenger/Command/DebugCommand.php @@ -108,9 +108,9 @@ private function formatConditions(array $options): string $optionsMapping = []; foreach ($options as $key => $value) { - $optionsMapping[] = ' '.$key.'='.$value; + $optionsMapping[] = $key.'='.$value; } - return ' (when'.implode(', ', $optionsMapping).')'; + return ' (when '.implode(', ', $optionsMapping).')'; } } diff --git a/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php index 02812adb47a1e..e637d51dd3126 100644 --- a/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php @@ -40,7 +40,7 @@ public function testOutput() { $command = new DebugCommand([ 'command_bus' => [ - DummyCommand::class => [[DummyCommandHandler::class, []]], + DummyCommand::class => [[DummyCommandHandler::class, ['option1' => '1', 'option2' => '2']]], MultipleBusesMessage::class => [[MultipleBusesMessageHandler::class, []]], ], 'query_bus' => [ @@ -62,12 +62,12 @@ public function testOutput() The following messages can be dispatched: - --------------------------------------------------------------------------------------- - Symfony\Component\Messenger\Tests\Fixtures\DummyCommand - handled by Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler - Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessage - handled by Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessageHandler - --------------------------------------------------------------------------------------- + ----------------------------------------------------------------------------------------------------------- + Symfony\Component\Messenger\Tests\Fixtures\DummyCommand + handled by Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler (when option1=1, option2=2) + Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessage + handled by Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessageHandler + ----------------------------------------------------------------------------------------------------------- query_bus --------- From e7c9a28a03bdaf0c862335224737bebe3fd19f14 Mon Sep 17 00:00:00 2001 From: noniagriconomie Date: Tue, 17 Dec 2019 19:01:32 +0100 Subject: [PATCH 020/124] [Profiler] wording --- .../WebProfilerBundle/Resources/views/Profiler/info.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig index 0227532e1208a..43404393ec360 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig @@ -4,7 +4,7 @@ 'no_token' : { status: 'error', title: (token|default('') == 'latest') ? 'There are no profiles' : 'Token not found', - message: (token|default('') == 'latest') ? 'No profiles found in the database.' : 'Token "' ~ token|default('') ~ '" was not found in the database.' + message: (token|default('') == 'latest') ? 'No profiles found.' : 'Token "' ~ token|default('') ~ '" not found.' } } %} From e379dbbf219b52779b34acb40a00afc94f758541 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 27 Dec 2019 10:02:48 +0100 Subject: [PATCH 021/124] do not overwrite variable value --- .../Component/Cache/DependencyInjection/CachePoolPass.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php index eef9e75b06332..00784b64f5f94 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php @@ -54,7 +54,7 @@ public function process(ContainerBuilder $container) } $seed .= '.'.$container->getParameter('kernel.container_class'); - $pools = []; + $allPools = []; $clearers = []; $attributes = [ 'provider', @@ -119,7 +119,7 @@ public function process(ContainerBuilder $container) $clearers[$clearer][$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); } - $pools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); + $allPools[$name] = new Reference($id, $container::IGNORE_ON_UNINITIALIZED_REFERENCE); } $notAliasedCacheClearerId = $this->cacheClearerId; @@ -127,7 +127,7 @@ public function process(ContainerBuilder $container) $this->cacheClearerId = (string) $container->getAlias($this->cacheClearerId); } if ($container->hasDefinition($this->cacheClearerId)) { - $clearers[$notAliasedCacheClearerId] = $pools; + $clearers[$notAliasedCacheClearerId] = $allPools; } foreach ($clearers as $id => $pools) { @@ -145,7 +145,7 @@ public function process(ContainerBuilder $container) } if ($container->hasDefinition('console.command.cache_pool_list')) { - $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($pools)); + $container->getDefinition('console.command.cache_pool_list')->replaceArgument(0, array_keys($allPools)); } } From a90a6c9c4849a1342ebee66417e1046470b81eaf Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 27 Dec 2019 11:24:52 +0100 Subject: [PATCH 022/124] [HttpClient] fix scheduling pending NativeResponse --- .../HttpClient/Internal/NativeClientState.php | 4 -- .../HttpClient/Response/NativeResponse.php | 43 ++++++++++--------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Internal/NativeClientState.php b/src/Symfony/Component/HttpClient/Internal/NativeClientState.php index e82ce4c853d21..6578929dc5466 100644 --- a/src/Symfony/Component/HttpClient/Internal/NativeClientState.php +++ b/src/Symfony/Component/HttpClient/Internal/NativeClientState.php @@ -11,8 +11,6 @@ namespace Symfony\Component\HttpClient\Internal; -use Symfony\Component\HttpClient\Response\NativeResponse; - /** * Internal representation of the native client's state. * @@ -24,8 +22,6 @@ final class NativeClientState extends ClientState { /** @var int */ public $id; - /** @var NativeResponse[] */ - public $pendingResponses = []; /** @var int */ public $maxHostConnections = PHP_INT_MAX; /** @var int */ diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index b8af399a94b10..49e25c51bc03c 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -209,11 +209,7 @@ private static function schedule(self $response, array &$runningResponses): void $runningResponses[$i] = [$response->multi, []]; } - if (null === $response->remaining) { - $response->multi->pendingResponses[] = $response; - } else { - $runningResponses[$i][1][$response->id] = $response; - } + $runningResponses[$i][1][$response->id] = $response; if (null === $response->buffer) { // Response already completed @@ -315,25 +311,30 @@ private static function perform(NativeClientState $multi, array &$responses = nu return; } - if ($multi->pendingResponses && \count($multi->handles) < $multi->maxHostConnections) { - // Open the next pending request - this is a blocking operation so we do only one of them - /** @var self $response */ - $response = array_shift($multi->pendingResponses); - $response->open(); - $responses[$response->id] = $response; - $multi->sleep = false; - self::perform($response->multi); - - if (null !== $response->handle) { - $multi->handles[] = $response->handle; + // Create empty activity lists to tell ResponseTrait::stream() we still have pending requests + foreach ($responses as $i => $response) { + if (null === $response->remaining && null !== $response->buffer) { + $multi->handlesActivity[$i] = []; } } - if ($multi->pendingResponses) { - // Create empty activity list to tell ResponseTrait::stream() we still have pending requests - $response = $multi->pendingResponses[0]; - $responses[$response->id] = $response; - $multi->handlesActivity[$response->id] = []; + if (\count($multi->handles) >= $multi->maxHostConnections) { + return; + } + + // Open the next pending request - this is a blocking operation so we do only one of them + foreach ($responses as $i => $response) { + if (null === $response->remaining && null !== $response->buffer) { + $response->open(); + $multi->sleep = false; + self::perform($multi); + + if (null !== $response->handle) { + $multi->handles[] = $response->handle; + } + + break; + } } } From 6fd266dba65690eaf4106f33940a4cc811050848 Mon Sep 17 00:00:00 2001 From: Olivier Dolbeau Date: Fri, 27 Dec 2019 12:18:21 +0100 Subject: [PATCH 023/124] Add missing use statement --- .../Translation/DataCollector/TranslationDataCollector.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php index fc713463a0bc3..5b96a22f35001 100644 --- a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php +++ b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Symfony\Component\Translation\DataCollectorTranslator; +use Symfony\Component\VarDumper\Cloner\Data; /** * @author Abdellatif Ait boudad From 340bb145d9cd338a24314781701991a7e3d7c68f Mon Sep 17 00:00:00 2001 From: Dmitriy Derepko Date: Thu, 26 Dec 2019 15:06:00 +0300 Subject: [PATCH 024/124] Fixed #35084 --- .../VarDumper/Dumper/ContextProvider/CliContextProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/VarDumper/Dumper/ContextProvider/CliContextProvider.php b/src/Symfony/Component/VarDumper/Dumper/ContextProvider/CliContextProvider.php index e7f8ccf17f194..38f878971c53f 100644 --- a/src/Symfony/Component/VarDumper/Dumper/ContextProvider/CliContextProvider.php +++ b/src/Symfony/Component/VarDumper/Dumper/ContextProvider/CliContextProvider.php @@ -25,7 +25,7 @@ public function getContext(): ?array } return [ - 'command_line' => $commandLine = implode(' ', $_SERVER['argv']), + 'command_line' => $commandLine = implode(' ', $_SERVER['argv'] ?? []), 'identifier' => hash('crc32b', $commandLine.$_SERVER['REQUEST_TIME_FLOAT']), ]; } From 5179af4796f09780f7d98d55b7527e6a24d1a761 Mon Sep 17 00:00:00 2001 From: Artem Brovko Date: Fri, 27 Dec 2019 18:26:36 +0200 Subject: [PATCH 025/124] [Translator] Performance improvement in MessageCatalogue and catalogue operations. --- src/Symfony/Component/Translation/MessageCatalogue.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/MessageCatalogue.php b/src/Symfony/Component/Translation/MessageCatalogue.php index 9b59c87d2f919..cc4a0bfaba9d3 100644 --- a/src/Symfony/Component/Translation/MessageCatalogue.php +++ b/src/Symfony/Component/Translation/MessageCatalogue.php @@ -130,7 +130,9 @@ public function add($messages, $domain = 'messages') if (!isset($this->messages[$domain])) { $this->messages[$domain] = $messages; } else { - $this->messages[$domain] = array_replace($this->messages[$domain], $messages); + foreach ($messages as $id => $message) { + $this->messages[$domain][$id] = $message; + } } } From 12d3aa80ecd9a2a210ff49dcc5c1748b2c55605b Mon Sep 17 00:00:00 2001 From: Alireza Mirsepassi Date: Fri, 27 Dec 2019 13:01:54 +0330 Subject: [PATCH 026/124] Removing unused variable --- src/Symfony/Component/DependencyInjection/TypedReference.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/TypedReference.php b/src/Symfony/Component/DependencyInjection/TypedReference.php index 3765bc73f83a0..78d8edf0b03f6 100644 --- a/src/Symfony/Component/DependencyInjection/TypedReference.php +++ b/src/Symfony/Component/DependencyInjection/TypedReference.php @@ -20,7 +20,6 @@ class TypedReference extends Reference { private $type; private $name; - private $requiringClass; /** * @param string $id The service identifier From 291d1f3a844de36670bb00ac05d984c2bea23a3b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 28 Dec 2019 16:31:08 +0100 Subject: [PATCH 027/124] [DI] fix merge --- .../Tests/Fixtures/php/services_subscriber.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php index e184fad7bdf0c..4f9074e9aaf7f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php @@ -45,8 +45,8 @@ public function isCompiled(): bool public function getRemovedIds(): array { return [ - '.service_locator.bPEFRiK' => true, - '.service_locator.bPEFRiK.foo_service' => true, + '.service_locator.2Wk0Efb' => true, + '.service_locator.2Wk0Efb.foo_service' => true, 'Psr\\Container\\ContainerInterface' => true, 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true, From 86afefed3bd0be2f00e00cffe0afd39df3e7c203 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 28 Dec 2019 19:58:08 +0100 Subject: [PATCH 028/124] [DebugBundle] Make RemoveWebServerBundleLoggerPass internal --- .../Compiler/RemoveWebServerBundleLoggerPass.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php index aca150c816101..2d30cf21d9d6d 100644 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php +++ b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php @@ -16,8 +16,10 @@ /** * @author Jérémy Derussé + * + * @internal */ -class RemoveWebServerBundleLoggerPass implements CompilerPassInterface +final class RemoveWebServerBundleLoggerPass implements CompilerPassInterface { /** * {@inheritdoc} From 167411c194e132b69cd6c5ff34130f58b27c489e Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 28 Dec 2019 20:01:11 +0100 Subject: [PATCH 029/124] [DebugBundle] Drop RemoveWebServerBundleLoggerPass --- .../Bundle/DebugBundle/DebugBundle.php | 2 -- .../RemoveWebServerBundleLoggerPass.php | 31 ------------------- 2 files changed, 33 deletions(-) delete mode 100644 src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php diff --git a/src/Symfony/Bundle/DebugBundle/DebugBundle.php b/src/Symfony/Bundle/DebugBundle/DebugBundle.php index fd7d8e72d6a4c..04fd507612747 100644 --- a/src/Symfony/Bundle/DebugBundle/DebugBundle.php +++ b/src/Symfony/Bundle/DebugBundle/DebugBundle.php @@ -12,7 +12,6 @@ namespace Symfony\Bundle\DebugBundle; use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\DumpDataCollectorPass; -use Symfony\Bundle\DebugBundle\DependencyInjection\Compiler\RemoveWebServerBundleLoggerPass; use Symfony\Component\Console\Application; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Bundle\Bundle; @@ -53,7 +52,6 @@ public function build(ContainerBuilder $container) parent::build($container); $container->addCompilerPass(new DumpDataCollectorPass()); - $container->addCompilerPass(new RemoveWebServerBundleLoggerPass()); } public function registerCommands(Application $application) diff --git a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php b/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php deleted file mode 100644 index aca150c816101..0000000000000 --- a/src/Symfony/Bundle/DebugBundle/DependencyInjection/Compiler/RemoveWebServerBundleLoggerPass.php +++ /dev/null @@ -1,31 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\DebugBundle\DependencyInjection\Compiler; - -use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; -use Symfony\Component\DependencyInjection\ContainerBuilder; - -/** - * @author Jérémy Derussé - */ -class RemoveWebServerBundleLoggerPass implements CompilerPassInterface -{ - /** - * {@inheritdoc} - */ - public function process(ContainerBuilder $container) - { - if ($container->hasDefinition('web_server.command.server_log') && $container->hasDefinition('monolog.command.server_log')) { - $container->removeDefinition('web_server.command.server_log'); - } - } -} From bad07ec557dfd4c72f25c68f1558c04f4e3ccf8e Mon Sep 17 00:00:00 2001 From: Jaapio Date: Sat, 28 Dec 2019 22:02:19 +0100 Subject: [PATCH 030/124] Fix BC issue in phpDoc Reflection library The used phpDocumentor library DocBlockReflection contained an BC break that broke this component. The patch was applied in the recent released v4.3.4 version. But since it is unclear how long this issue existed it is not possible to exclude a certain version. Therefor also `\RuntimeExpception` needs to be catched. The BC break is possibly caused by a change in the TypeResolver library used by the DocBlockReflection which is now supporting the more populair generics notation for arrays. --- .../Component/PropertyInfo/Extractor/PhpDocExtractor.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 76b6c43400791..787bf4b5d2d09 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -212,6 +212,8 @@ private function getDocBlockFromProperty($class, $property) return $this->docBlockFactory->create($reflectionProperty, $this->contextFactory->createFromReflector($reflectionProperty->getDeclaringClass())); } catch (\InvalidArgumentException $e) { return null; + } catch (\RuntimeException $e) { + return null; } } @@ -257,6 +259,8 @@ private function getDocBlockFromMethod($class, $ucFirstProperty, $type) return [$this->docBlockFactory->create($reflectionMethod, $this->contextFactory->createFromReflector($reflectionMethod)), $prefix]; } catch (\InvalidArgumentException $e) { return null; + } catch (\RuntimeException $e) { + return null; } } } From cd40bb8604ca7842f0ffbaa4ba0782865a976401 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Tue, 24 Dec 2019 16:21:48 +0100 Subject: [PATCH 031/124] [Routing] Fix i18n routing when the url contains the locale --- .../Generator/CompiledUrlGenerator.php | 9 ++++- .../Generator/Dumper/PhpGeneratorDumper.php | 9 ++++- .../Routing/Generator/UrlGenerator.php | 14 ++++++-- .../Dumper/CompiledUrlGeneratorDumperTest.php | 31 +++++++++++++++-- .../Dumper/PhpGeneratorDumperTest.php | 34 +++++++++++++++++-- .../Tests/Generator/UrlGeneratorTest.php | 23 +++++++++++++ 6 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Routing/Generator/CompiledUrlGenerator.php b/src/Symfony/Component/Routing/Generator/CompiledUrlGenerator.php index 41cd5893ae2f3..adcc99e31015a 100644 --- a/src/Symfony/Component/Routing/Generator/CompiledUrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/CompiledUrlGenerator.php @@ -40,7 +40,6 @@ public function generate($name, $parameters = [], $referenceType = self::ABSOLUT if (null !== $locale) { do { if (($this->compiledRoutes[$name.'.'.$locale][1]['_canonical_route'] ?? null) === $name) { - unset($parameters['_locale']); $name .= '.'.$locale; break; } @@ -53,6 +52,14 @@ public function generate($name, $parameters = [], $referenceType = self::ABSOLUT list($variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes) = $this->compiledRoutes[$name]; + if (isset($defaults['_canonical_route']) && isset($defaults['_locale'])) { + if (!\in_array('_locale', $variables, true)) { + unset($parameters['_locale']); + } elseif (!isset($parameters['_locale'])) { + $parameters['_locale'] = $defaults['_locale']; + } + } + return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes); } } diff --git a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php index 3869ffda4eebe..8526d81bc0761 100644 --- a/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php +++ b/src/Symfony/Component/Routing/Generator/Dumper/PhpGeneratorDumper.php @@ -120,7 +120,6 @@ public function generate($name, $parameters = [], $referenceType = self::ABSOLUT if (null !== $locale && null !== $name) { do { if ((self::$declaredRoutes[$name.'.'.$locale][1]['_canonical_route'] ?? null) === $name) { - unset($parameters['_locale']); $name .= '.'.$locale; break; } @@ -133,6 +132,14 @@ public function generate($name, $parameters = [], $referenceType = self::ABSOLUT list($variables, $defaults, $requirements, $tokens, $hostTokens, $requiredSchemes) = self::$declaredRoutes[$name]; + if (isset($defaults['_canonical_route']) && isset($defaults['_locale'])) { + if (!\in_array('_locale', $variables, true)) { + unset($parameters['_locale']); + } elseif (!isset($parameters['_locale'])) { + $parameters['_locale'] = $defaults['_locale']; + } + } + return $this->doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, $requiredSchemes); } EOF; diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index 8be593bf98b6f..72870669964ab 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -134,7 +134,6 @@ public function generate($name, $parameters = [], $referenceType = self::ABSOLUT if (null !== $locale) { do { if (null !== ($route = $this->routes->get($name.'.'.$locale)) && $route->getDefault('_canonical_route') === $name) { - unset($parameters['_locale']); break; } } while (false !== $locale = strstr($locale, '_', true)); @@ -147,7 +146,18 @@ public function generate($name, $parameters = [], $referenceType = self::ABSOLUT // the Route has a cache of its own and is not recompiled as long as it does not get modified $compiledRoute = $route->compile(); - return $this->doGenerate($compiledRoute->getVariables(), $route->getDefaults(), $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens(), $route->getSchemes()); + $defaults = $route->getDefaults(); + $variables = $compiledRoute->getVariables(); + + if (isset($defaults['_canonical_route']) && isset($defaults['_locale'])) { + if (!\in_array('_locale', $variables, true)) { + unset($parameters['_locale']); + } elseif (!isset($parameters['_locale'])) { + $parameters['_locale'] = $defaults['_locale']; + } + } + + return $this->doGenerate($variables, $defaults, $route->getRequirements(), $compiledRoute->getTokens(), $parameters, $name, $referenceType, $compiledRoute->getHostTokens(), $route->getSchemes()); } /** diff --git a/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php b/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php index 521f0f126cda7..de4776ff78331 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php @@ -131,9 +131,9 @@ public function testDumpWithRouteNotFoundLocalizedRoutes() public function testDumpWithFallbackLocaleLocalizedRoutes() { - $this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_canonical_route', 'test')); - $this->routeCollection->add('test.nl', (new Route('/testen/is/leuk'))->setDefault('_canonical_route', 'test')); - $this->routeCollection->add('test.fr', (new Route('/tester/est/amusant'))->setDefault('_canonical_route', 'test')); + $this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'test')); + $this->routeCollection->add('test.nl', (new Route('/testen/is/leuk'))->setDefault('_locale', 'nl')->setDefault('_canonical_route', 'test')); + $this->routeCollection->add('test.fr', (new Route('/tester/est/amusant'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'test')); $code = $this->generatorDumper->dump(); file_put_contents($this->testTmpFilepath, $code); @@ -231,4 +231,29 @@ public function testDumpWithSchemeRequirement() $this->assertEquals('https://localhost/app.php/testing', $absoluteUrl); $this->assertEquals('/app.php/testing', $relativeUrl); } + + public function testDumpWithLocalizedRoutesPreserveTheGoodLocaleInTheUrl() + { + $this->routeCollection->add('foo.en', (new Route('/{_locale}/foo'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'foo')); + $this->routeCollection->add('foo.fr', (new Route('/{_locale}/foo'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'foo')); + $this->routeCollection->add('fun.en', (new Route('/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'fun')); + $this->routeCollection->add('fun.fr', (new Route('/amusant'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'fun')); + + file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump()); + + $requestContext = new RequestContext(); + $requestContext->setParameter('_locale', 'fr'); + + $compiledUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, $requestContext, null, null); + + $this->assertSame('/fr/foo', $compiledUrlGenerator->generate('foo')); + $this->assertSame('/en/foo', $compiledUrlGenerator->generate('foo.en')); + $this->assertSame('/en/foo', $compiledUrlGenerator->generate('foo', ['_locale' => 'en'])); + $this->assertSame('/en/foo', $compiledUrlGenerator->generate('foo.fr', ['_locale' => 'en'])); + + $this->assertSame('/amusant', $compiledUrlGenerator->generate('fun')); + $this->assertSame('/fun', $compiledUrlGenerator->generate('fun.en')); + $this->assertSame('/fun', $compiledUrlGenerator->generate('fun', ['_locale' => 'en'])); + $this->assertSame('/amusant', $compiledUrlGenerator->generate('fun.fr', ['_locale' => 'en'])); + } } diff --git a/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php b/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php index 5e81b8f5d5755..1787144780f43 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php @@ -140,9 +140,9 @@ public function testDumpWithRouteNotFoundLocalizedRoutes() public function testDumpWithFallbackLocaleLocalizedRoutes() { - $this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_canonical_route', 'test')); - $this->routeCollection->add('test.nl', (new Route('/testen/is/leuk'))->setDefault('_canonical_route', 'test')); - $this->routeCollection->add('test.fr', (new Route('/tester/est/amusant'))->setDefault('_canonical_route', 'test')); + $this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'test')); + $this->routeCollection->add('test.nl', (new Route('/testen/is/leuk'))->setDefault('_locale', 'nl')->setDefault('_canonical_route', 'test')); + $this->routeCollection->add('test.fr', (new Route('/tester/est/amusant'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'test')); $code = $this->generatorDumper->dump([ 'class' => 'FallbackLocaleLocalizedProjectUrlGenerator', @@ -250,4 +250,32 @@ public function testDumpWithSchemeRequirement() $this->assertEquals('https://localhost/app.php/testing', $absoluteUrl); $this->assertEquals('/app.php/testing', $relativeUrl); } + + public function testDumpWithLocalizedRoutesPreserveTheGoodLocaleInTheUrl() + { + $this->routeCollection->add('foo.en', (new Route('/{_locale}/foo'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'foo')); + $this->routeCollection->add('foo.fr', (new Route('/{_locale}/foo'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'foo')); + $this->routeCollection->add('fun.en', (new Route('/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'fun')); + $this->routeCollection->add('fun.fr', (new Route('/amusant'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'fun')); + + file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump([ + 'class' => 'PreserveTheGoodLocaleInTheUrlGenerator', + ])); + include $this->testTmpFilepath; + + $requestContext = new RequestContext(); + $requestContext->setParameter('_locale', 'fr'); + + $phpGenerator = new \PreserveTheGoodLocaleInTheUrlGenerator($requestContext); + + $this->assertSame('/fr/foo', $phpGenerator->generate('foo')); + $this->assertSame('/en/foo', $phpGenerator->generate('foo.en')); + $this->assertSame('/en/foo', $phpGenerator->generate('foo', ['_locale' => 'en'])); + $this->assertSame('/en/foo', $phpGenerator->generate('foo.fr', ['_locale' => 'en'])); + + $this->assertSame('/amusant', $phpGenerator->generate('fun')); + $this->assertSame('/fun', $phpGenerator->generate('fun.en')); + $this->assertSame('/fun', $phpGenerator->generate('fun', ['_locale' => 'en'])); + $this->assertSame('/amusant', $phpGenerator->generate('fun.fr', ['_locale' => 'en'])); + } } diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index a768384747684..01215da2c064e 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -236,6 +236,29 @@ public function testGenerateWithOverriddenParameterLocaleFromRequestContext() ); } + public function testDumpWithLocalizedRoutesPreserveTheGoodLocaleInTheUrl() + { + $routeCollection = new RouteCollection(); + + $routeCollection->add('foo.en', (new Route('/{_locale}/foo'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'foo')); + $routeCollection->add('foo.fr', (new Route('/{_locale}/foo'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'foo')); + $routeCollection->add('fun.en', (new Route('/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'fun')); + $routeCollection->add('fun.fr', (new Route('/amusant'))->setDefault('_locale', 'fr')->setDefault('_canonical_route', 'fun')); + + $urlGenerator = $this->getGenerator($routeCollection); + $urlGenerator->getContext()->setParameter('_locale', 'fr'); + + $this->assertSame('/app.php/fr/foo', $urlGenerator->generate('foo')); + $this->assertSame('/app.php/en/foo', $urlGenerator->generate('foo.en')); + $this->assertSame('/app.php/en/foo', $urlGenerator->generate('foo', ['_locale' => 'en'])); + $this->assertSame('/app.php/en/foo', $urlGenerator->generate('foo.fr', ['_locale' => 'en'])); + + $this->assertSame('/app.php/amusant', $urlGenerator->generate('fun')); + $this->assertSame('/app.php/fun', $urlGenerator->generate('fun.en')); + $this->assertSame('/app.php/fun', $urlGenerator->generate('fun', ['_locale' => 'en'])); + $this->assertSame('/app.php/amusant', $urlGenerator->generate('fun.fr', ['_locale' => 'en'])); + } + public function testGenerateWithoutRoutes() { $this->expectException('Symfony\Component\Routing\Exception\RouteNotFoundException'); From f0d227db2f0563686a865bdaa088322c0fcedc8c Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Sun, 29 Dec 2019 18:50:02 +0100 Subject: [PATCH 032/124] [Console][FormatterHelper] Use helper strlen statically and remove duplicated code --- .../Component/Console/Helper/FormatterHelper.php | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/FormatterHelper.php b/src/Symfony/Component/Console/Helper/FormatterHelper.php index 4ad63856dcd5c..d6eccee8e85ac 100644 --- a/src/Symfony/Component/Console/Helper/FormatterHelper.php +++ b/src/Symfony/Component/Console/Helper/FormatterHelper.php @@ -54,12 +54,12 @@ public function formatBlock($messages, $style, $large = false) foreach ($messages as $message) { $message = OutputFormatter::escape($message); $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); - $len = max($this->strlen($message) + ($large ? 4 : 2), $len); + $len = max(self::strlen($message) + ($large ? 4 : 2), $len); } $messages = $large ? [str_repeat(' ', $len)] : []; for ($i = 0; isset($lines[$i]); ++$i) { - $messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i])); + $messages[] = $lines[$i].str_repeat(' ', $len - self::strlen($lines[$i])); } if ($large) { $messages[] = str_repeat(' ', $len); @@ -83,17 +83,13 @@ public function formatBlock($messages, $style, $large = false) */ public function truncate($message, $length, $suffix = '...') { - $computedLength = $length - $this->strlen($suffix); + $computedLength = $length - self::strlen($suffix); - if ($computedLength > $this->strlen($message)) { + if ($computedLength > self::strlen($message)) { return $message; } - if (false === $encoding = mb_detect_encoding($message, null, true)) { - return substr($message, 0, $length).$suffix; - } - - return mb_substr($message, 0, $length, $encoding).$suffix; + return self::substr($message, 0, $length).$suffix; } /** From 3a25878e98e462ca804dce790a9883eb5642c22d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 30 Dec 2019 18:19:47 +0100 Subject: [PATCH 033/124] [HttpClient] fix typo --- src/Symfony/Component/HttpClient/NativeHttpClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index 8098ddf23feb9..de6667d540dde 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -340,7 +340,7 @@ private static function createRedirectResolver(array $options, string $host, ?ar }); if (isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) { - $redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) { + $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) { return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); }); } From 4c790b0589798c15184cef78e84e3e2c7ff31aa8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 30 Dec 2019 18:22:15 +0100 Subject: [PATCH 034/124] doctrine/doctrine-bundle ^1.5 is not compatible with Symfony 5 --- composer.json | 2 +- src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f7e384c6196f4..35d8d7361115a 100644 --- a/composer.json +++ b/composer.json @@ -107,7 +107,7 @@ "doctrine/dbal": "~2.4", "doctrine/orm": "~2.4,>=2.4.5", "doctrine/reflection": "~1.0", - "doctrine/doctrine-bundle": "^1.5|^2.0", + "doctrine/doctrine-bundle": "^2.0", "guzzlehttp/promises": "^1.3.1", "masterminds/html5": "^2.6", "monolog/monolog": "^1.25.1|^2", diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index a87e4a1f00d25..21cc505551f9b 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -27,7 +27,7 @@ "symfony/security-http": "^4.4.1|^5.0.1" }, "require-dev": { - "doctrine/doctrine-bundle": "^1.5|^2.0", + "doctrine/doctrine-bundle": "^2.0", "symfony/asset": "^4.4|^5.0", "symfony/browser-kit": "^4.4|^5.0", "symfony/console": "^4.4|^5.0", From 879ba76a6af6ea747758a14c5dbaf6c89f8b9f95 Mon Sep 17 00:00:00 2001 From: Emanuele Panzeri Date: Tue, 31 Dec 2019 11:13:47 +0100 Subject: [PATCH 035/124] Fix Nexmo notifier bridge namespace --- src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json b/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json index cfcc1bcf18058..019d06fb269c1 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/composer.json @@ -21,7 +21,7 @@ "symfony/notifier": "~5.0.0" }, "autoload": { - "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\Twilio\\": "" }, + "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\Nexmo\\": "" }, "exclude-from-classmap": [ "/Tests/" ] From c280a0172458a5b6f14a49db649c35bc5d7d8ecb Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 1 Jan 2020 10:41:58 +0100 Subject: [PATCH 036/124] fix version when "anonymous: lazy" was introduced --- src/Symfony/Bundle/SecurityBundle/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md index 5a18e1f7b05ee..f46d5231851c4 100644 --- a/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/SecurityBundle/CHANGELOG.md @@ -4,6 +4,7 @@ CHANGELOG 4.4.0 ----- + * Added `anonymous: lazy` mode to firewalls to make them (not) start the session as late as possible * Added `migrate_from` option to encoders configuration. * Added new `argon2id` encoder, undeprecated the `bcrypt` and `argon2i` ones (using `auto` is still recommended by default.) * Deprecated the usage of "query_string" without a "search_dn" and a "search_password" config key in Ldap factories. @@ -12,7 +13,6 @@ CHANGELOG 4.3.0 ----- - * Added `anonymous: lazy` mode to firewalls to make them (not) start the session as late as possible * Added new encoder types: `auto` (recommended), `native` and `sodium` * The normalization of the cookie names configured in the `logout.delete_cookies` option is deprecated and will be disabled in Symfony 5.0. This affects to cookies From 889a110e7466bed8091c242b218b4b23011bf89e Mon Sep 17 00:00:00 2001 From: Jan Rosier Date: Wed, 1 Jan 2020 12:03:25 +0100 Subject: [PATCH 037/124] Update year in license files --- LICENSE | 2 +- src/Symfony/Bridge/Doctrine/LICENSE | 2 +- src/Symfony/Bridge/Monolog/LICENSE | 2 +- src/Symfony/Bridge/PhpUnit/LICENSE | 2 +- src/Symfony/Bridge/ProxyManager/LICENSE | 2 +- src/Symfony/Bridge/Twig/LICENSE | 2 +- src/Symfony/Bundle/DebugBundle/LICENSE | 2 +- src/Symfony/Bundle/FrameworkBundle/LICENSE | 2 +- src/Symfony/Bundle/SecurityBundle/LICENSE | 2 +- src/Symfony/Bundle/TwigBundle/LICENSE | 2 +- src/Symfony/Bundle/WebProfilerBundle/LICENSE | 2 +- src/Symfony/Bundle/WebServerBundle/LICENSE | 2 +- src/Symfony/Component/Asset/LICENSE | 2 +- src/Symfony/Component/BrowserKit/LICENSE | 2 +- src/Symfony/Component/Cache/LICENSE | 2 +- src/Symfony/Component/ClassLoader/LICENSE | 2 +- src/Symfony/Component/Config/LICENSE | 2 +- src/Symfony/Component/Console/LICENSE | 2 +- src/Symfony/Component/CssSelector/LICENSE | 2 +- src/Symfony/Component/Debug/LICENSE | 2 +- src/Symfony/Component/DependencyInjection/LICENSE | 2 +- src/Symfony/Component/DomCrawler/LICENSE | 2 +- src/Symfony/Component/Dotenv/LICENSE | 2 +- src/Symfony/Component/EventDispatcher/LICENSE | 2 +- src/Symfony/Component/ExpressionLanguage/LICENSE | 2 +- src/Symfony/Component/Filesystem/LICENSE | 2 +- src/Symfony/Component/Finder/LICENSE | 2 +- src/Symfony/Component/Form/LICENSE | 2 +- src/Symfony/Component/HttpFoundation/LICENSE | 2 +- src/Symfony/Component/HttpKernel/LICENSE | 2 +- src/Symfony/Component/Inflector/LICENSE | 2 +- src/Symfony/Component/Intl/LICENSE | 2 +- src/Symfony/Component/Ldap/LICENSE | 2 +- src/Symfony/Component/Lock/LICENSE | 2 +- src/Symfony/Component/OptionsResolver/LICENSE | 2 +- src/Symfony/Component/Process/LICENSE | 2 +- src/Symfony/Component/PropertyAccess/LICENSE | 2 +- src/Symfony/Component/PropertyInfo/LICENSE | 2 +- src/Symfony/Component/Routing/LICENSE | 2 +- src/Symfony/Component/Security/Core/LICENSE | 2 +- src/Symfony/Component/Security/Csrf/LICENSE | 2 +- src/Symfony/Component/Security/Guard/LICENSE | 2 +- src/Symfony/Component/Security/Http/LICENSE | 2 +- src/Symfony/Component/Security/LICENSE | 2 +- src/Symfony/Component/Serializer/LICENSE | 2 +- src/Symfony/Component/Stopwatch/LICENSE | 2 +- src/Symfony/Component/Templating/LICENSE | 2 +- src/Symfony/Component/Translation/LICENSE | 2 +- src/Symfony/Component/Validator/LICENSE | 2 +- src/Symfony/Component/VarDumper/LICENSE | 2 +- src/Symfony/Component/WebLink/LICENSE | 2 +- src/Symfony/Component/Workflow/LICENSE | 2 +- src/Symfony/Component/Yaml/LICENSE | 2 +- 53 files changed, 53 insertions(+), 53 deletions(-) diff --git a/LICENSE b/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/Doctrine/LICENSE b/src/Symfony/Bridge/Doctrine/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/Doctrine/LICENSE +++ b/src/Symfony/Bridge/Doctrine/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/Monolog/LICENSE b/src/Symfony/Bridge/Monolog/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/Monolog/LICENSE +++ b/src/Symfony/Bridge/Monolog/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/PhpUnit/LICENSE b/src/Symfony/Bridge/PhpUnit/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Bridge/PhpUnit/LICENSE +++ b/src/Symfony/Bridge/PhpUnit/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/ProxyManager/LICENSE b/src/Symfony/Bridge/ProxyManager/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/ProxyManager/LICENSE +++ b/src/Symfony/Bridge/ProxyManager/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/Twig/LICENSE b/src/Symfony/Bridge/Twig/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/Twig/LICENSE +++ b/src/Symfony/Bridge/Twig/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/DebugBundle/LICENSE b/src/Symfony/Bundle/DebugBundle/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Bundle/DebugBundle/LICENSE +++ b/src/Symfony/Bundle/DebugBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/FrameworkBundle/LICENSE b/src/Symfony/Bundle/FrameworkBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/LICENSE +++ b/src/Symfony/Bundle/FrameworkBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/SecurityBundle/LICENSE b/src/Symfony/Bundle/SecurityBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/SecurityBundle/LICENSE +++ b/src/Symfony/Bundle/SecurityBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/TwigBundle/LICENSE b/src/Symfony/Bundle/TwigBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/TwigBundle/LICENSE +++ b/src/Symfony/Bundle/TwigBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/WebProfilerBundle/LICENSE b/src/Symfony/Bundle/WebProfilerBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/LICENSE +++ b/src/Symfony/Bundle/WebProfilerBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/WebServerBundle/LICENSE b/src/Symfony/Bundle/WebServerBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/WebServerBundle/LICENSE +++ b/src/Symfony/Bundle/WebServerBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Asset/LICENSE b/src/Symfony/Component/Asset/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Asset/LICENSE +++ b/src/Symfony/Component/Asset/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/BrowserKit/LICENSE b/src/Symfony/Component/BrowserKit/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/BrowserKit/LICENSE +++ b/src/Symfony/Component/BrowserKit/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Cache/LICENSE b/src/Symfony/Component/Cache/LICENSE index 3c464ca94359b..a7ec70801827a 100644 --- a/src/Symfony/Component/Cache/LICENSE +++ b/src/Symfony/Component/Cache/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2019 Fabien Potencier +Copyright (c) 2016-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/ClassLoader/LICENSE b/src/Symfony/Component/ClassLoader/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/ClassLoader/LICENSE +++ b/src/Symfony/Component/ClassLoader/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Config/LICENSE b/src/Symfony/Component/Config/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Config/LICENSE +++ b/src/Symfony/Component/Config/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Console/LICENSE b/src/Symfony/Component/Console/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Console/LICENSE +++ b/src/Symfony/Component/Console/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/CssSelector/LICENSE b/src/Symfony/Component/CssSelector/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/CssSelector/LICENSE +++ b/src/Symfony/Component/CssSelector/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Debug/LICENSE b/src/Symfony/Component/Debug/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Debug/LICENSE +++ b/src/Symfony/Component/Debug/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/DependencyInjection/LICENSE b/src/Symfony/Component/DependencyInjection/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/DependencyInjection/LICENSE +++ b/src/Symfony/Component/DependencyInjection/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/DomCrawler/LICENSE b/src/Symfony/Component/DomCrawler/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/DomCrawler/LICENSE +++ b/src/Symfony/Component/DomCrawler/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Dotenv/LICENSE b/src/Symfony/Component/Dotenv/LICENSE index 3c464ca94359b..a7ec70801827a 100644 --- a/src/Symfony/Component/Dotenv/LICENSE +++ b/src/Symfony/Component/Dotenv/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2019 Fabien Potencier +Copyright (c) 2016-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/EventDispatcher/LICENSE b/src/Symfony/Component/EventDispatcher/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/EventDispatcher/LICENSE +++ b/src/Symfony/Component/EventDispatcher/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/ExpressionLanguage/LICENSE b/src/Symfony/Component/ExpressionLanguage/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/ExpressionLanguage/LICENSE +++ b/src/Symfony/Component/ExpressionLanguage/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Filesystem/LICENSE b/src/Symfony/Component/Filesystem/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Filesystem/LICENSE +++ b/src/Symfony/Component/Filesystem/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Finder/LICENSE b/src/Symfony/Component/Finder/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Finder/LICENSE +++ b/src/Symfony/Component/Finder/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Form/LICENSE b/src/Symfony/Component/Form/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Form/LICENSE +++ b/src/Symfony/Component/Form/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/HttpFoundation/LICENSE b/src/Symfony/Component/HttpFoundation/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/HttpFoundation/LICENSE +++ b/src/Symfony/Component/HttpFoundation/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/HttpKernel/LICENSE b/src/Symfony/Component/HttpKernel/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/HttpKernel/LICENSE +++ b/src/Symfony/Component/HttpKernel/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Inflector/LICENSE b/src/Symfony/Component/Inflector/LICENSE index f03153cc4a232..2749b15672205 100644 --- a/src/Symfony/Component/Inflector/LICENSE +++ b/src/Symfony/Component/Inflector/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2019 Fabien Potencier +Copyright (c) 2012-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Intl/LICENSE b/src/Symfony/Component/Intl/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Intl/LICENSE +++ b/src/Symfony/Component/Intl/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Ldap/LICENSE b/src/Symfony/Component/Ldap/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Ldap/LICENSE +++ b/src/Symfony/Component/Ldap/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Lock/LICENSE b/src/Symfony/Component/Lock/LICENSE index 3c464ca94359b..a7ec70801827a 100644 --- a/src/Symfony/Component/Lock/LICENSE +++ b/src/Symfony/Component/Lock/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2019 Fabien Potencier +Copyright (c) 2016-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/OptionsResolver/LICENSE b/src/Symfony/Component/OptionsResolver/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/OptionsResolver/LICENSE +++ b/src/Symfony/Component/OptionsResolver/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Process/LICENSE b/src/Symfony/Component/Process/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Process/LICENSE +++ b/src/Symfony/Component/Process/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/PropertyAccess/LICENSE b/src/Symfony/Component/PropertyAccess/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/PropertyAccess/LICENSE +++ b/src/Symfony/Component/PropertyAccess/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/PropertyInfo/LICENSE b/src/Symfony/Component/PropertyInfo/LICENSE index 4cd8bdd3007da..5612f967a232e 100644 --- a/src/Symfony/Component/PropertyInfo/LICENSE +++ b/src/Symfony/Component/PropertyInfo/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Routing/LICENSE b/src/Symfony/Component/Routing/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Routing/LICENSE +++ b/src/Symfony/Component/Routing/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Core/LICENSE b/src/Symfony/Component/Security/Core/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Core/LICENSE +++ b/src/Symfony/Component/Security/Core/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Csrf/LICENSE b/src/Symfony/Component/Security/Csrf/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Csrf/LICENSE +++ b/src/Symfony/Component/Security/Csrf/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Guard/LICENSE b/src/Symfony/Component/Security/Guard/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Guard/LICENSE +++ b/src/Symfony/Component/Security/Guard/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Http/LICENSE b/src/Symfony/Component/Security/Http/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Http/LICENSE +++ b/src/Symfony/Component/Security/Http/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/LICENSE b/src/Symfony/Component/Security/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/LICENSE +++ b/src/Symfony/Component/Security/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Serializer/LICENSE b/src/Symfony/Component/Serializer/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Serializer/LICENSE +++ b/src/Symfony/Component/Serializer/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Stopwatch/LICENSE b/src/Symfony/Component/Stopwatch/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Stopwatch/LICENSE +++ b/src/Symfony/Component/Stopwatch/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Templating/LICENSE b/src/Symfony/Component/Templating/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Templating/LICENSE +++ b/src/Symfony/Component/Templating/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Translation/LICENSE b/src/Symfony/Component/Translation/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Translation/LICENSE +++ b/src/Symfony/Component/Translation/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Validator/LICENSE b/src/Symfony/Component/Validator/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Validator/LICENSE +++ b/src/Symfony/Component/Validator/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/VarDumper/LICENSE b/src/Symfony/Component/VarDumper/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Component/VarDumper/LICENSE +++ b/src/Symfony/Component/VarDumper/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/WebLink/LICENSE b/src/Symfony/Component/WebLink/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/WebLink/LICENSE +++ b/src/Symfony/Component/WebLink/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Workflow/LICENSE b/src/Symfony/Component/Workflow/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Component/Workflow/LICENSE +++ b/src/Symfony/Component/Workflow/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Yaml/LICENSE b/src/Symfony/Component/Yaml/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Yaml/LICENSE +++ b/src/Symfony/Component/Yaml/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 0d7a8bdd0a1ceb01ee56c0fb255312984406baf4 Mon Sep 17 00:00:00 2001 From: Jan Rosier Date: Wed, 1 Jan 2020 12:51:43 +0100 Subject: [PATCH 038/124] Update year in license files --- src/Symfony/Component/HttpClient/LICENSE | 2 +- src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE | 2 +- src/Symfony/Component/Mailer/Bridge/Google/LICENSE | 2 +- src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE | 2 +- src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE | 2 +- src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE | 2 +- src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE | 2 +- src/Symfony/Component/Mailer/LICENSE | 2 +- src/Symfony/Component/Messenger/LICENSE | 2 +- src/Symfony/Component/Mime/LICENSE | 2 +- src/Symfony/Component/VarExporter/LICENSE | 2 +- src/Symfony/Contracts/Cache/LICENSE | 2 +- src/Symfony/Contracts/EventDispatcher/LICENSE | 2 +- src/Symfony/Contracts/HttpClient/LICENSE | 2 +- src/Symfony/Contracts/LICENSE | 2 +- src/Symfony/Contracts/Service/LICENSE | 2 +- src/Symfony/Contracts/Translation/LICENSE | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/HttpClient/LICENSE b/src/Symfony/Component/HttpClient/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Component/HttpClient/LICENSE +++ b/src/Symfony/Component/HttpClient/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE b/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/Bridge/Google/LICENSE b/src/Symfony/Component/Mailer/Bridge/Google/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/LICENSE +++ b/src/Symfony/Component/Mailer/Bridge/Google/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE b/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE b/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE b/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE b/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mailer/LICENSE b/src/Symfony/Component/Mailer/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Mailer/LICENSE +++ b/src/Symfony/Component/Mailer/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Messenger/LICENSE b/src/Symfony/Component/Messenger/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Component/Messenger/LICENSE +++ b/src/Symfony/Component/Messenger/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Mime/LICENSE b/src/Symfony/Component/Mime/LICENSE index 9a9a61b1c6c10..d53be68356dbf 100644 --- a/src/Symfony/Component/Mime/LICENSE +++ b/src/Symfony/Component/Mime/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010-2019 Fabien Potencier +Copyright (c) 2010-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/VarExporter/LICENSE b/src/Symfony/Component/VarExporter/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Component/VarExporter/LICENSE +++ b/src/Symfony/Component/VarExporter/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Contracts/Cache/LICENSE b/src/Symfony/Contracts/Cache/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Contracts/Cache/LICENSE +++ b/src/Symfony/Contracts/Cache/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Contracts/EventDispatcher/LICENSE b/src/Symfony/Contracts/EventDispatcher/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Contracts/EventDispatcher/LICENSE +++ b/src/Symfony/Contracts/EventDispatcher/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Contracts/HttpClient/LICENSE b/src/Symfony/Contracts/HttpClient/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Contracts/HttpClient/LICENSE +++ b/src/Symfony/Contracts/HttpClient/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Contracts/LICENSE b/src/Symfony/Contracts/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Contracts/LICENSE +++ b/src/Symfony/Contracts/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Contracts/Service/LICENSE b/src/Symfony/Contracts/Service/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Contracts/Service/LICENSE +++ b/src/Symfony/Contracts/Service/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Contracts/Translation/LICENSE b/src/Symfony/Contracts/Translation/LICENSE index 3f853aaf35fe1..69d925ba7511e 100644 --- a/src/Symfony/Contracts/Translation/LICENSE +++ b/src/Symfony/Contracts/Translation/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2018-2019 Fabien Potencier +Copyright (c) 2018-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 5374d4f210819afb64cfbcd69bcd024dfd707cf7 Mon Sep 17 00:00:00 2001 From: Christophe Meneses Date: Fri, 27 Dec 2019 16:02:38 +0100 Subject: [PATCH 039/124] [TwigBridge][Form] Added missing help messages in form themes --- .../bootstrap_3_horizontal_layout.html.twig | 1 + .../views/Form/bootstrap_3_layout.html.twig | 2 ++ .../views/Form/foundation_5_layout.html.twig | 2 ++ ...AbstractBootstrap3HorizontalLayoutTest.php | 19 ++++++++++++ .../AbstractBootstrap3LayoutTest.php | 30 +++++++++++++++++++ ...AbstractBootstrap4HorizontalLayoutTest.php | 19 ++++++++++++ .../AbstractBootstrap4LayoutTest.php | 30 +++++++++++++++++++ 7 files changed, 103 insertions(+) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig index 4dc3e9c896fb7..49cd804398b5e 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_horizontal_layout.html.twig @@ -64,6 +64,7 @@ col-sm-10
{#--#}
{{- form_widget(form) -}} + {{- form_help(form) -}} {{- form_errors(form) -}}
{#--#} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig index f0cf0ad81854d..44492cebe74d7 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig @@ -148,6 +148,7 @@ {% block checkbox_row -%} {{- form_widget(form) -}} + {{- form_help(form) -}} {{- form_errors(form) -}} {%- endblock checkbox_row %} @@ -155,6 +156,7 @@ {% block radio_row -%} {{- form_widget(form) -}} + {{- form_help(form) -}} {{- form_errors(form) -}} {%- endblock radio_row %} 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 83c5e30d803bc..8ab44ccc7738f 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 @@ -311,6 +311,7 @@
{{ form_widget(form) }} + {{- form_help(form) -}} {{ form_errors(form) }}
@@ -320,6 +321,7 @@
{{ form_widget(form) }} + {{- form_help(form) -}} {{ form_errors(form) }}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php index 9131216182a3d..69064a003d7fe 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php @@ -163,4 +163,23 @@ public function testCheckboxRow() $this->assertMatchesXpath($html, '/div[@class="form-group"]/div[@class="col-sm-2" or @class="col-sm-10"]', 2); } + + public function testCheckboxRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType'); + $html = $this->renderRow($form->createView(), ['label' => 'foo', 'help' => 'really helpful text']); + + $this->assertMatchesXpath($html, +'/div + [@class="form-group"] + [ + ./div[@class="col-sm-2" or @class="col-sm-10"] + /following-sibling::div[@class="col-sm-2" or @class="col-sm-10"] + [ + ./span[text() = "[trans]really helpful text[/trans]"] + ] + ] +' + ); + } } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 16f8f818f38cb..be7a11e7977f1 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -333,6 +333,21 @@ public function testCheckboxWithValue() ); } + public function testCheckboxRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType'); + $html = $this->renderRow($form->createView(), ['label' => 'foo', 'help' => 'really helpful text']); + + $this->assertMatchesXpath($html, +'/div + [@class="form-group"] + [ + ./span[text() = "[trans]really helpful text[/trans]"] + ] +' + ); + } + public function testSingleChoice() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&a', [ @@ -2277,6 +2292,21 @@ public function testRadioWithValue() ); } + public function testRadioRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RadioType', false); + $html = $this->renderRow($form->createView(), ['label' => 'foo', 'help' => 'really helpful text']); + + $this->assertMatchesXpath($html, +'/div + [@class="form-group"] + [ + ./span[text() = "[trans]really helpful text[/trans]"] + ] +' + ); + } + public function testRange() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RangeType', 42, ['attr' => ['min' => 5]]); diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php index e9416b02213f2..e20f4818b2810 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php @@ -231,6 +231,25 @@ public function testCheckboxRowWithHelp() ./small[text() = "[trans]really helpful text[/trans]"] ] ] +' + ); + } + + public function testRadioRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RadioType', false); + $html = $this->renderRow($form->createView(), ['label' => 'foo', 'help' => 'really helpful text']); + + $this->assertMatchesXpath($html, +'/div + [@class="form-group row"] + [ + ./div[@class="col-sm-2" or @class="col-sm-10"] + /following-sibling::div[@class="col-sm-2" or @class="col-sm-10"] + [ + ./small[text() = "[trans]really helpful text[/trans]"] + ] + ] ' ); } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php index 89fbacf2fc2d7..2643274d47c3e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php @@ -422,6 +422,21 @@ public function testCheckboxWithValue() ); } + public function testCheckboxRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\CheckboxType'); + $html = $this->renderRow($form->createView(), ['label' => 'foo', 'help' => 'really helpful text']); + + $this->assertMatchesXpath($html, + '/div + [@class="form-group"] + [ + ./small[text() = "[trans]really helpful text[/trans]"] + ] +' + ); + } + public function testSingleChoiceExpanded() { $form = $this->factory->createNamed('name', ChoiceType::class, '&a', [ @@ -1027,6 +1042,21 @@ public function testRadioWithValue() ); } + public function testRadioRowWithHelp() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\RadioType', false); + $html = $this->renderRow($form->createView(), ['label' => 'foo', 'help' => 'really helpful text']); + + $this->assertMatchesXpath($html, +'/div + [@class="form-group"] + [ + ./small[text() = "[trans]really helpful text[/trans]"] + ] +' + ); + } + public function testButtonAttributeNameRepeatedIfTrue() { $form = $this->factory->createNamed('button', ButtonType::class, null, [ From 500a075673c4c85723d1d9fdd53b5a4fbbf06c10 Mon Sep 17 00:00:00 2001 From: Jan Rosier Date: Wed, 1 Jan 2020 15:47:03 +0100 Subject: [PATCH 040/124] Update year in license files --- src/Symfony/Component/ErrorHandler/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/ErrorHandler/LICENSE b/src/Symfony/Component/ErrorHandler/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/ErrorHandler/LICENSE +++ b/src/Symfony/Component/ErrorHandler/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From ef4426ae8735f65d77f78cbd595a6d0396e9722e Mon Sep 17 00:00:00 2001 From: Jan Rosier Date: Wed, 1 Jan 2020 15:53:07 +0100 Subject: [PATCH 041/124] Update year in license files --- src/Symfony/Component/Notifier/Bridge/Nexmo/LICENSE | 2 +- src/Symfony/Component/Notifier/Bridge/Slack/LICENSE | 2 +- src/Symfony/Component/Notifier/Bridge/Telegram/LICENSE | 2 +- src/Symfony/Component/Notifier/Bridge/Twilio/LICENSE | 2 +- src/Symfony/Component/Notifier/LICENSE | 2 +- src/Symfony/Component/String/LICENSE | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/LICENSE b/src/Symfony/Component/Notifier/Bridge/Nexmo/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/LICENSE +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/LICENSE b/src/Symfony/Component/Notifier/Bridge/Slack/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/LICENSE +++ b/src/Symfony/Component/Notifier/Bridge/Slack/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/LICENSE b/src/Symfony/Component/Notifier/Bridge/Telegram/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/LICENSE +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Notifier/Bridge/Twilio/LICENSE b/src/Symfony/Component/Notifier/Bridge/Twilio/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Notifier/Bridge/Twilio/LICENSE +++ b/src/Symfony/Component/Notifier/Bridge/Twilio/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Notifier/LICENSE b/src/Symfony/Component/Notifier/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/Notifier/LICENSE +++ b/src/Symfony/Component/Notifier/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/String/LICENSE b/src/Symfony/Component/String/LICENSE index 1a1869751d250..4bf0fef4ff3b0 100644 --- a/src/Symfony/Component/String/LICENSE +++ b/src/Symfony/Component/String/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2019 Fabien Potencier +Copyright (c) 2019-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 234589a753e9a7eabe9444c735b4b362a95c1cb1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 2 Jan 2020 11:45:12 +0100 Subject: [PATCH 042/124] [HttpClient] fix capturing SSL certificates with NativeHttpClient --- .../Component/HttpClient/Response/NativeResponse.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 49e25c51bc03c..383603dd28833 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -158,13 +158,13 @@ private function open(): void restore_error_handler(); } - stream_set_blocking($h, false); - $this->context = $this->resolveRedirect = null; - - if (isset($context['ssl']['peer_certificate_chain'])) { + if (isset($context['ssl']['capture_peer_cert_chain']) && isset(($context = stream_context_get_options($this->context))['ssl']['peer_certificate_chain'])) { $this->info['peer_certificate_chain'] = $context['ssl']['peer_certificate_chain']; } + stream_set_blocking($h, false); + $this->context = $this->resolveRedirect = null; + // Create dechunk and inflate buffers if (isset($this->headers['content-length'])) { $this->remaining = (int) $this->headers['content-length'][0]; From 9e12a6dcda478307a213d76c1664960c7e2fa31b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vilius=20Grigali=C5=ABnas?= Date: Thu, 2 Jan 2020 17:01:57 +0200 Subject: [PATCH 043/124] [Mailer][MailchimpBridge] Fix incorrect sender address when sender has name This fixes the same problem as https://github.com/symfony/symfony/commit/6dbac13a07c23f321b04489b6a9773 but for HTTP transport. --- .../Mailer/Bridge/Mailchimp/Http/MandrillTransport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php index ea8bcf4dbbba5..ed9bea8d80ebf 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/MandrillTransport.php @@ -42,7 +42,7 @@ protected function doSend(SentMessage $message): void 'json' => [ 'key' => $this->key, 'to' => $this->stringifyAddresses($envelope->getRecipients()), - 'from_email' => $envelope->getSender()->toString(), + 'from_email' => $envelope->getSender()->getAddress(), 'raw_message' => $message->toString(), ], ]); From 7b1bbb619000c1d7d9fb0b94e7ed439fdd9bd1e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vilius=20Grigali=C5=ABnas?= Date: Thu, 2 Jan 2020 17:40:32 +0200 Subject: [PATCH 044/124] [Mailer][MailchimpBridge] Fix missing attachments when sending via Mandrill API Previous code tries to pass attachments to API, but uses incorrect structure and as a result all attachments are missing when the email is sent. --- .../Bridge/Mailchimp/Http/Api/MandrillTransport.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php index c8e313e7b7391..34395ad9221e2 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php @@ -79,10 +79,14 @@ private function getPayload(Email $email, SmtpEnvelope $envelope): array 'type' => $headers->get('Content-Type')->getBody(), ]; + if ($name = $headers->getHeaderParameter('Content-Disposition', 'name')) { + $att['name'] = $name; + } + if ('inline' === $disposition) { - $payload['images'][] = $att; + $payload['message']['images'][] = $att; } else { - $payload['attachments'][] = $att; + $payload['message']['attachments'][] = $att; } } From 36eeba7a3a26e81e08d53a3108a251078c198f85 Mon Sep 17 00:00:00 2001 From: Guillaume Verstraete Date: Fri, 3 Jan 2020 02:28:31 +0100 Subject: [PATCH 045/124] [Mailer] Fix addresses management in Sendgrid API payload --- .../Tests/Transport/SendgridApiTransportTest.php | 15 +++++++++++---- .../Sendgrid/Transport/SendgridApiTransport.php | 12 ++++++++++-- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php index 9ad5c280ecbad..c64dd505526a6 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridApiTransport; +use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; @@ -48,8 +49,8 @@ public function getTransportData() public function testSend() { $email = new Email(); - $email->from('foo@example.com') - ->to('bar@example.com') + $email->from(new Address('foo@example.com', 'Ms. Foo Bar')) + ->to(new Address('bar@example.com', 'Mr. Recipient')) ->bcc('baz@example.com') ->text('content'); @@ -73,12 +74,18 @@ public function testSend() 'json' => [ 'personalizations' => [ [ - 'to' => [['email' => 'bar@example.com']], + 'to' => [[ + 'email' => 'bar@example.com', + 'name' => 'Mr. Recipient', + ]], 'subject' => null, 'bcc' => [['email' => 'baz@example.com']], ], ], - 'from' => ['email' => 'foo@example.com'], + 'from' => [ + 'email' => 'foo@example.com', + 'name' => 'Ms. Foo Bar', + ], 'content' => [ ['type' => 'text/plain', 'value' => 'content'], ], diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php index 262983afd73fd..37740861b862c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php @@ -63,11 +63,19 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e private function getPayload(Email $email, Envelope $envelope): array { - $addressStringifier = function (Address $address) {return ['email' => $address->toString()]; }; + $addressStringifier = function (Address $address) { + $stringified = ['email' => $address->getAddress()]; + + if ($address->getName()) { + $stringified['name'] = $address->getName(); + } + + return $stringified; + }; $payload = [ 'personalizations' => [], - 'from' => ['email' => $envelope->getSender()->toString()], + 'from' => $addressStringifier($envelope->getSender()), 'content' => $this->getContent($email), ]; From bba9fd6ccf84b34d770bf8953bcfd3b844e0b6bc Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Fri, 3 Jan 2020 00:46:11 -0500 Subject: [PATCH 046/124] [FrameworkBundle] Fix getUser() phpdoc in AbstractController --- .../Bundle/FrameworkBundle/Controller/AbstractController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php index 20f420ce9d45b..d3548430b9f6b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php @@ -38,6 +38,7 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Serializer\SerializerInterface; From 50ba566c0b5852c7499ed4db0f5dbcfaa5d28d97 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 3 Jan 2020 11:52:47 +0100 Subject: [PATCH 047/124] [PhpUnitBridge][SymfonyTestsListenerTrait] Remove $testsWithWarnings stack --- .../Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV5.php | 5 ----- .../Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV6.php | 5 ----- .../Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV7.php | 5 ----- .../Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php | 9 --------- 4 files changed, 24 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV5.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV5.php index 2da40f2c204f1..a760d126ca854 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV5.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV5.php @@ -47,11 +47,6 @@ public function startTest(\PHPUnit_Framework_Test $test) $this->trait->startTest($test); } - public function addWarning(\PHPUnit_Framework_Test $test, \PHPUnit_Framework_Warning $e, $time) - { - $this->trait->addWarning($test, $e, $time); - } - public function endTest(\PHPUnit_Framework_Test $test, $time) { $this->trait->endTest($test, $time); diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV6.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV6.php index 5b864bfe58a32..bcab4be4eeb25 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV6.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV6.php @@ -52,11 +52,6 @@ public function startTest(Test $test) $this->trait->startTest($test); } - public function addWarning(Test $test, Warning $e, $time) - { - $this->trait->addWarning($test, $e, $time); - } - public function endTest(Test $test, $time) { $this->trait->endTest($test, $time); diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV7.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV7.php index 18bbdbeba0f03..0c2069c66bf5e 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV7.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerForV7.php @@ -55,11 +55,6 @@ public function startTest(Test $test): void $this->trait->startTest($test); } - public function addWarning(Test $test, Warning $e, float $time): void - { - $this->trait->addWarning($test, $e, $time); - } - public function endTest(Test $test, float $time): void { $this->trait->endTest($test, $time); diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index ed84eedf4a92a..36d866b72296d 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -37,7 +37,6 @@ class SymfonyTestsListenerTrait private $expectedDeprecations = array(); private $gatheredDeprecations = array(); private $previousErrorHandler; - private $testsWithWarnings; private $reportUselessTests; private $error; private $runsInSeparateProcess = false; @@ -114,7 +113,6 @@ public function startTestSuite($suite) $Test = 'PHPUnit\Util\Test'; } $suiteName = $suite->getName(); - $this->testsWithWarnings = array(); foreach ($suite->tests() as $test) { if (!($test instanceof \PHPUnit\Framework\TestCase || $test instanceof TestCase)) { @@ -245,13 +243,6 @@ public function startTest($test) } } - public function addWarning($test, $e, $time) - { - if ($test instanceof \PHPUnit\Framework\TestCase || $test instanceof TestCase) { - $this->testsWithWarnings[$test->getName()] = true; - } - } - public function endTest($test, $time) { if (class_exists('PHPUnit_Util_Blacklist', false)) { From dba1804f5d5d66c40321a0c284a22973491af9bf Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 3 Jan 2020 12:08:23 +0100 Subject: [PATCH 048/124] [PhpUnitBridge] Add test case for @expectedDeprecation annotation --- .../ExpectedDeprecationAnnotationTest.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php new file mode 100644 index 0000000000000..259c99162a831 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests; + +use PHPUnit\Framework\TestCase; + +final class ExpectedDeprecationAnnotationTest extends TestCase +{ + /** + * Do not remove this test in the next major versions. + * + * @group legacy + * + * @expectedDeprecation foo + */ + public function testOne() + { + @trigger_error('foo', E_USER_DEPRECATED); + } + + /** + * Do not remove this test in the next major versions. + * + * @group legacy + * + * @expectedDeprecation foo + * @expectedDeprecation bar + */ + public function testMany() + { + @trigger_error('foo', E_USER_DEPRECATED); + @trigger_error('bar', E_USER_DEPRECATED); + } +} From 35c08ef395de1e0c621989f19e9dddefe9f4e222 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 3 Jan 2020 14:52:20 +0100 Subject: [PATCH 049/124] [HttpClient] fix casting responses to PHP streams --- .../Component/HttpClient/CurlHttpClient.php | 4 ++-- .../Component/HttpClient/NativeHttpClient.php | 2 +- .../HttpClient/Response/ResponseTrait.php | 6 ++++- .../HttpClient/Response/StreamWrapper.php | 23 +++++++++++-------- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index d26b48c19a803..a36372c619e8e 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -288,7 +288,7 @@ public function request(string $method, string $url, array $options = []): Respo $pushedResponse = $pushedResponse->response; $pushedResponse->__construct($this->multi, $url, $options, $this->logger); } else { - $this->logger && $this->logger->debug(sprintf('Rejecting pushed response: "%s".', $url)); + $this->logger && $this->logger->debug(sprintf('Rejecting pushed response: "%s"', $url)); $pushedResponse = null; } } @@ -412,7 +412,7 @@ private static function acceptPushForRequest(string $method, array $options, Pus return false; } - foreach (['proxy', 'no_proxy', 'bindto'] as $k) { + foreach (['proxy', 'no_proxy', 'bindto', 'local_cert', 'local_pk'] as $k) { if ($options[$k] !== $pushedResponse->parentOptions[$k]) { return false; } diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index a500200aba216..56405fd6a31bc 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -169,7 +169,7 @@ public function request(string $method, string $url, array $options = []): Respo $this->multi->dnsCache = $options['resolve'] + $this->multi->dnsCache; } - $this->logger && $this->logger->info(sprintf('Request: %s %s', $method, implode('', $url))); + $this->logger && $this->logger->info(sprintf('Request: "%s %s"', $method, implode('', $url))); [$host, $port, $url['authority']] = self::dnsResolve($url, $this->multi, $info, $onProgress); diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 0ea434e3a0da4..71a04f1e8a1a1 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -204,7 +204,11 @@ public function toStream(bool $throw = true) $this->getHeaders($throw); } - return StreamWrapper::createResource($this, null, $this->content, $this->handle && 'stream' === get_resource_type($this->handle) ? $this->handle : null); + $stream = StreamWrapper::createResource($this); + stream_get_meta_data($stream)['wrapper_data'] + ->bindHandles($this->handle, $this->content); + + return $stream; } /** diff --git a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php index 59fd118e86e01..4b8566e869ba6 100644 --- a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php +++ b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php @@ -43,13 +43,9 @@ class StreamWrapper /** * Creates a PHP stream resource from a ResponseInterface. * - * @param resource|null $contentBuffer The seekable resource where the response body is buffered - * @param resource|null $selectHandle The resource handle that should be monitored when - * stream_select() is used on the created stream - * * @return resource */ - public static function createResource(ResponseInterface $response, HttpClientInterface $client = null, $contentBuffer = null, $selectHandle = null) + public static function createResource(ResponseInterface $response, HttpClientInterface $client = null) { if (null === $client && !method_exists($response, 'stream')) { throw new \InvalidArgumentException(sprintf('Providing a client to "%s()" is required when the response doesn\'t have any "stream()" method.', __CLASS__)); @@ -63,8 +59,6 @@ public static function createResource(ResponseInterface $response, HttpClientInt $context = [ 'client' => $client ?? $response, 'response' => $response, - 'content' => $contentBuffer, - 'handle' => $selectHandle, ]; return fopen('symfony://'.$response->getInfo('url'), 'r', false, stream_context_create(['symfony' => $context])) ?: null; @@ -78,6 +72,17 @@ public function getResponse(): ResponseInterface return $this->response; } + /** + * @param resource|null $handle The resource handle that should be monitored when + * stream_select() is used on the created stream + * @param resource|null $content The seekable resource where the response body is buffered + */ + public function bindHandles(&$handle, &$content): void + { + $this->handle = &$handle; + $this->content = &$content; + } + public function stream_open(string $path, string $mode, int $options): bool { if ('r' !== $mode) { @@ -91,8 +96,6 @@ public function stream_open(string $path, string $mode, int $options): bool $context = stream_context_get_options($this->context)['symfony'] ?? null; $this->client = $context['client'] ?? null; $this->response = $context['response'] ?? null; - $this->content = $context['content'] ?? null; - $this->handle = $context['handle'] ?? null; $this->context = null; if (null !== $this->client && null !== $this->response) { @@ -238,6 +241,8 @@ public function stream_seek(int $offset, int $whence = SEEK_SET): bool public function stream_cast(int $castAs) { if (STREAM_CAST_FOR_SELECT === $castAs) { + $this->response->getHeaders(false); + return $this->handle ?? false; } From c5b81904248ba3b773f9f53fcb07a1dd0d3b32a4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 3 Jan 2020 19:23:58 +0100 Subject: [PATCH 050/124] 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 a97a38e5204e3..b5f1d36cabb61 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 83c5e30d803bc..e5d129736c7ae 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 66654d9ce5890..b46358d6dc471 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -531,6 +531,31 @@ public function testSingleChoiceWithPreferred() ); } + 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 555189ae2c9d089af59f62cff4d9d8f6b9928e19 Mon Sep 17 00:00:00 2001 From: Jesse Rushlow Date: Fri, 3 Jan 2020 18:06:56 -0500 Subject: [PATCH 051/124] [Security-Guard] fixed 35203 missing name tag in param docblock Added missing $credentials name tag to @param for getPassword() to resolve PHPStan error and comply with the docBlock spec. --- .../Component/Security/Guard/PasswordAuthenticatedInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php b/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php index 4dd7a7b4466d2..dd2eeba33dea8 100644 --- a/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php +++ b/src/Symfony/Component/Security/Guard/PasswordAuthenticatedInterface.php @@ -19,7 +19,7 @@ interface PasswordAuthenticatedInterface /** * Returns the clear-text password contained in credentials if any. * - * @param mixed The user credentials + * @param mixed $credentials The user credentials */ public function getPassword($credentials): ?string; } From 8d46f95f4c8e82033d8bdab441e6d3b326388ce3 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 4 Jan 2020 10:07:46 +0100 Subject: [PATCH 052/124] ensure to expect no validation for the right reasons --- .../Constraints/FormValidatorTest.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) 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 e024ac3338a94..e19620e790f7c 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -133,7 +133,10 @@ public function testDontValidateIfParentWithoutValidConstraint() $parent->add($form); $form->setData($object); + $parent->submit([]); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -188,10 +191,15 @@ public function testDontValidateIfNoValidationGroups() 'validation_groups' => [], ]) ->setData($object) + ->setCompound(true) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form->setData($object); + $form->submit([]); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -214,6 +222,8 @@ public function testDontValidateConstraintsIfNoValidationGroups() // Launch transformer $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -236,6 +246,8 @@ public function testDontValidateChildConstraintsIfCallableNoValidationGroups() $form->add($child); $form->submit([]); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -264,6 +276,8 @@ function () { throw new TransformationFailedException(); } // Launch transformer $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -299,6 +313,8 @@ function () { throw new TransformationFailedException(); } // Launch transformer $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -369,6 +385,8 @@ function () { throw new TransformationFailedException(); } // Launch transformer $form->submit(['child' => 'foo']); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -574,7 +592,10 @@ public function testDontWalkScalars() $form = $this->getBuilder() ->setData('scalar') ->getForm(); + $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -592,6 +613,8 @@ public function testViolationIfExtraData() $form->submit(['foo' => 'bar']); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -613,6 +636,8 @@ public function testViolationFormatIfMultipleExtraFields() $form->submit(['foo' => 'bar', 'baz' => 'qux', 'quux' => 'quuz']); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); From da117714fd851df5af8e705ffab3c381c7403217 Mon Sep 17 00:00:00 2001 From: Ahmed Raafat Date: Mon, 30 Dec 2019 14:53:54 +0100 Subject: [PATCH 053/124] [Validator] Add the missing translations for the Arabic (ar) locale --- .../Resources/translations/validators.ar.xlf | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index 12f26fdc88688..79dab63d7de58 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -334,6 +334,38 @@ This value should be valid JSON. هذه القيمة يجب أن تكون صالحة ل JSON. + + This collection should contain only unique elements. + يجب أن تحتوي هذه المجموعة علي عناصر فريدة فقط. + + + This value should be positive. + يجب أن تكون هذه القيمة موجبة. + + + This value should be either positive or zero. + يجب أن تكون هذه القيمة إما موجبة او صفر. + + + This value should be negative. + يجب أن تكون هذه القيمة سالبة. + + + This value should be either negative or zero. + يجب أن تكون هذه القيمة إما سالبة او صفر. + + + This value is not a valid timezone. + هذه القيمة ليست منطقة زمنية صحيحة. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + تم تسريب كلمة المرور هذه في خرق للبيانات، ويجب عدم استخدامها. يرجي استخدام كلمة مرور أخري. + + + This value should be between {{ min }} and {{ max }}. + يجب أن تكون هذه القيمة بين {{ min }} و {{ max }}. + From 5cac29571b6ab58640bfc76054c033c82c62dad2 Mon Sep 17 00:00:00 2001 From: Shaharia Azam Date: Sat, 21 Dec 2019 04:13:14 +0600 Subject: [PATCH 054/124] Update links to documentation --- src/Symfony/Component/ClassLoader/README.md | 2 +- src/Symfony/Component/Config/README.md | 2 +- src/Symfony/Component/Console/README.md | 2 +- src/Symfony/Component/Debug/README.md | 2 +- src/Symfony/Component/DependencyInjection/README.md | 2 +- src/Symfony/Component/EventDispatcher/README.md | 2 +- src/Symfony/Component/Filesystem/README.md | 2 +- src/Symfony/Component/Form/README.md | 2 +- src/Symfony/Component/HttpFoundation/README.md | 2 +- src/Symfony/Component/HttpKernel/README.md | 2 +- src/Symfony/Component/PropertyAccess/README.md | 2 +- src/Symfony/Component/Routing/README.md | 2 +- src/Symfony/Component/Security/Core/README.md | 2 +- src/Symfony/Component/Security/Csrf/README.md | 2 +- src/Symfony/Component/Security/Guard/README.md | 2 +- src/Symfony/Component/Security/Http/README.md | 2 +- src/Symfony/Component/Security/README.md | 2 +- src/Symfony/Component/Templating/README.md | 2 +- src/Symfony/Component/Translation/README.md | 2 +- src/Symfony/Component/Yaml/README.md | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/ClassLoader/README.md b/src/Symfony/Component/ClassLoader/README.md index d61992b6a80e7..96d1e9fe5a5ce 100644 --- a/src/Symfony/Component/ClassLoader/README.md +++ b/src/Symfony/Component/ClassLoader/README.md @@ -7,7 +7,7 @@ their locations for performance. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/class_loader/index.html) + * [Documentation](https://symfony.com/doc/current/components/class_loader.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Config/README.md b/src/Symfony/Component/Config/README.md index bf400da196b22..0bbde55230a21 100644 --- a/src/Symfony/Component/Config/README.md +++ b/src/Symfony/Component/Config/README.md @@ -8,7 +8,7 @@ may be (YAML, XML, INI files, or for instance a database). Resources --------- - * [Documentation](https://symfony.com/doc/current/components/config/index.html) + * [Documentation](https://symfony.com/doc/current/components/config.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Console/README.md b/src/Symfony/Component/Console/README.md index 664a37c0ee7be..3e2fc605e5bfd 100644 --- a/src/Symfony/Component/Console/README.md +++ b/src/Symfony/Component/Console/README.md @@ -7,7 +7,7 @@ interfaces. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/console/index.html) + * [Documentation](https://symfony.com/doc/current/components/console.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Debug/README.md b/src/Symfony/Component/Debug/README.md index a1d16175c1a1f..38bc800c587b3 100644 --- a/src/Symfony/Component/Debug/README.md +++ b/src/Symfony/Component/Debug/README.md @@ -6,7 +6,7 @@ The Debug component provides tools to ease debugging PHP code. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/debug/index.html) + * [Documentation](https://symfony.com/doc/current/components/debug.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/DependencyInjection/README.md b/src/Symfony/Component/DependencyInjection/README.md index 932647f94a903..cb2d4a11c5886 100644 --- a/src/Symfony/Component/DependencyInjection/README.md +++ b/src/Symfony/Component/DependencyInjection/README.md @@ -7,7 +7,7 @@ way objects are constructed in your application. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/dependency_injection/index.html) + * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/EventDispatcher/README.md b/src/Symfony/Component/EventDispatcher/README.md index 185c3fecf8fee..e0d38eed017f8 100644 --- a/src/Symfony/Component/EventDispatcher/README.md +++ b/src/Symfony/Component/EventDispatcher/README.md @@ -8,7 +8,7 @@ them. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/event_dispatcher/index.html) + * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Filesystem/README.md b/src/Symfony/Component/Filesystem/README.md index 877ab3543f32d..cb03d43c15dd2 100644 --- a/src/Symfony/Component/Filesystem/README.md +++ b/src/Symfony/Component/Filesystem/README.md @@ -6,7 +6,7 @@ The Filesystem component provides basic utilities for the filesystem. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/filesystem/index.html) + * [Documentation](https://symfony.com/doc/current/components/filesystem.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Form/README.md b/src/Symfony/Component/Form/README.md index 3fe6f8bbf3206..5519cd00058dd 100644 --- a/src/Symfony/Component/Form/README.md +++ b/src/Symfony/Component/Form/README.md @@ -6,7 +6,7 @@ The Form component allows you to easily create, process and reuse HTML forms. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/form/index.html) + * [Documentation](https://symfony.com/doc/current/components/form.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/HttpFoundation/README.md b/src/Symfony/Component/HttpFoundation/README.md index 8907f0b967896..ac98f9b80ad5d 100644 --- a/src/Symfony/Component/HttpFoundation/README.md +++ b/src/Symfony/Component/HttpFoundation/README.md @@ -7,7 +7,7 @@ specification. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_foundation/index.html) + * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/HttpKernel/README.md b/src/Symfony/Component/HttpKernel/README.md index cc5e74b6bca3b..abdaf513f9cde 100644 --- a/src/Symfony/Component/HttpKernel/README.md +++ b/src/Symfony/Component/HttpKernel/README.md @@ -9,7 +9,7 @@ an advanced CMS system (Drupal). Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_kernel/index.html) + * [Documentation](https://symfony.com/doc/current/components/http_kernel.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/PropertyAccess/README.md b/src/Symfony/Component/PropertyAccess/README.md index 1959fd9e93492..891528d29cb94 100644 --- a/src/Symfony/Component/PropertyAccess/README.md +++ b/src/Symfony/Component/PropertyAccess/README.md @@ -7,7 +7,7 @@ object or array using a simple string notation. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/property_access/index.html) + * [Documentation](https://symfony.com/doc/current/components/property_access.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Routing/README.md b/src/Symfony/Component/Routing/README.md index 88fb1fde5a7bd..a16d9d7fcbbbb 100644 --- a/src/Symfony/Component/Routing/README.md +++ b/src/Symfony/Component/Routing/README.md @@ -6,7 +6,7 @@ The Routing component maps an HTTP request to a set of configuration variables. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/routing/index.html) + * [Documentation](https://symfony.com/doc/current/components/routing.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Core/README.md b/src/Symfony/Component/Security/Core/README.md index ede185bd3b3f5..70476d9e7f2b2 100644 --- a/src/Symfony/Component/Security/Core/README.md +++ b/src/Symfony/Component/Security/Core/README.md @@ -9,7 +9,7 @@ the Java Spring framework. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Csrf/README.md b/src/Symfony/Component/Security/Csrf/README.md index aff72a0c32240..15b9ace238fb9 100644 --- a/src/Symfony/Component/Security/Csrf/README.md +++ b/src/Symfony/Component/Security/Csrf/README.md @@ -7,7 +7,7 @@ The Security CSRF (cross-site request forgery) component provides a class Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Guard/README.md b/src/Symfony/Component/Security/Guard/README.md index ce706223901b3..40083a48d7682 100644 --- a/src/Symfony/Component/Security/Guard/README.md +++ b/src/Symfony/Component/Security/Guard/README.md @@ -8,7 +8,7 @@ total control. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Http/README.md b/src/Symfony/Component/Security/Http/README.md index 5be2111830116..dbac8c659c112 100644 --- a/src/Symfony/Component/Security/Http/README.md +++ b/src/Symfony/Component/Security/Http/README.md @@ -9,7 +9,7 @@ the Java Spring framework. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/README.md b/src/Symfony/Component/Security/README.md index f55f8a10eab98..d98dcd9ed2cc1 100644 --- a/src/Symfony/Component/Security/README.md +++ b/src/Symfony/Component/Security/README.md @@ -11,7 +11,7 @@ roles. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Templating/README.md b/src/Symfony/Component/Templating/README.md index 58e2a0a5c6b83..2b8ecad873964 100644 --- a/src/Symfony/Component/Templating/README.md +++ b/src/Symfony/Component/Templating/README.md @@ -12,7 +12,7 @@ layouts. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/templating/index.html) + * [Documentation](https://symfony.com/doc/current/components/templating.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Translation/README.md b/src/Symfony/Component/Translation/README.md index 46f3d1f2f25e6..e80a70cad033e 100644 --- a/src/Symfony/Component/Translation/README.md +++ b/src/Symfony/Component/Translation/README.md @@ -6,7 +6,7 @@ The Translation component provides tools to internationalize your application. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/translation/index.html) + * [Documentation](https://symfony.com/doc/current/components/translation.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Yaml/README.md b/src/Symfony/Component/Yaml/README.md index 0d324881ce5e4..b914e7836c7a5 100644 --- a/src/Symfony/Component/Yaml/README.md +++ b/src/Symfony/Component/Yaml/README.md @@ -6,7 +6,7 @@ The Yaml component loads and dumps YAML files. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/yaml/index.html) + * [Documentation](https://symfony.com/doc/current/components/yaml.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) From a28a7f9dee5dcb2bdfc4e744b30d43d0973799a7 Mon Sep 17 00:00:00 2001 From: Stuart Fyfe Date: Mon, 23 Sep 2019 13:39:21 +0100 Subject: [PATCH 055/124] [Mailer] Remove line breaks in email attachment content --- .../Sendgrid/Http/Api/SendgridTransport.php | 2 +- .../Tests/Http/Api/SendgridTransportTest.php | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php index 27a530f3099a9..f4415cc8e6fa5 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Http/Api/SendgridTransport.php @@ -115,7 +115,7 @@ private function getAttachments(Email $email): array $disposition = $headers->getHeaderBody('Content-Disposition'); $att = [ - 'content' => $attachment->bodyToString(), + 'content' => str_replace("\r\n", '', $attachment->bodyToString()), 'type' => $headers->get('Content-Type')->getBody(), 'filename' => $filename, 'disposition' => $disposition, diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Http/Api/SendgridTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Http/Api/SendgridTransportTest.php index e6cb1a9718ea6..534868383f5be 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Http/Api/SendgridTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Http/Api/SendgridTransportTest.php @@ -58,4 +58,52 @@ public function testSend() $mailer->send($email); } + + public function testLineBreaksInEncodedAttachment() + { + $email = new Email(); + $email->from('foo@example.com') + ->to('bar@example.com') + // even if content doesn't include new lines, the base64 encoding performed later may add them + ->attach('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod', 'lorem.txt'); + + $response = $this->createMock(ResponseInterface::class); + + $response + ->expects($this->once()) + ->method('getStatusCode') + ->willReturn(202); + + $httpClient = $this->createMock(HttpClientInterface::class); + + $httpClient + ->expects($this->once()) + ->method('request') + ->with('POST', 'https://api.sendgrid.com/v3/mail/send', [ + 'json' => [ + 'personalizations' => [ + [ + 'to' => [['email' => 'bar@example.com']], + 'subject' => null, + ], + ], + 'from' => ['email' => 'foo@example.com'], + 'content' => [], + 'attachments' => [ + [ + 'content' => 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2VkIGRvIGVpdXNtb2Q=', + 'filename' => 'lorem.txt', + 'type' => 'application/octet-stream', + 'disposition' => 'attachment', + ], + ], + ], + 'auth_bearer' => 'foo', + ]) + ->willReturn($response); + + $mailer = new SendgridTransport('foo', $httpClient); + + $mailer->send($email); + } } From 43c1e77a887105853d870878771d275cce7023a1 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Wed, 1 Jan 2020 22:40:09 +0100 Subject: [PATCH 056/124] [Mailer] Make sure you can pass custom headers to Mailgun --- .../Transport/MandrillApiTransportTest.php | 20 +++++++++++++++++++ .../Transport/MandrillApiTransport.php | 2 +- .../Transport/MailgunApiTransportTest.php | 19 ++++++++++++++++++ .../Mailgun/Transport/MailgunApiTransport.php | 2 +- .../Transport/PostmarkApiTransportTest.php | 20 +++++++++++++++++++ .../Transport/PostmarkApiTransport.php | 2 +- .../Transport/SendgridApiTransportTest.php | 17 ++++++++++++++++ .../Transport/SendgridApiTransport.php | 2 +- 8 files changed, 80 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php index 2bec482818421..af4cdbeebedfb 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Tests/Transport/MandrillApiTransportTest.php @@ -13,6 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillApiTransport; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; class MandrillApiTransportTest extends TestCase { @@ -41,4 +44,21 @@ public function getTransportData() ], ]; } + + public function testCustomHeader() + { + $email = new Email(); + $email->getHeaders()->addTextHeader('foo', 'bar'); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new MandrillApiTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(MandrillApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('message', $payload); + $this->assertArrayHasKey('headers', $payload['message']); + $this->assertCount(1, $payload['message']['headers']); + $this->assertEquals('foo: bar', $payload['message']['headers'][0]); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php index 4a982501bd669..af221ca66e4fb 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Transport/MandrillApiTransport.php @@ -111,7 +111,7 @@ private function getPayload(Email $email, Envelope $envelope): array continue; } - $payload['message']['headers'][] = $name.': '.$header->toString(); + $payload['message']['headers'][] = $name.': '.$header->getBodyAsString(); } return $payload; diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php index eb9838390aed8..f30fa0285c059 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php @@ -13,6 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Mailgun\Transport\MailgunApiTransport; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; class MailgunApiTransportTest extends TestCase { @@ -45,4 +48,20 @@ public function getTransportData() ], ]; } + + public function testCustomHeader() + { + $json = json_encode(['foo' => 'bar']); + $email = new Email(); + $email->getHeaders()->addTextHeader('X-Mailgun-Variables', $json); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new MailgunApiTransport('ACCESS_KEY', 'DOMAIN'); + $method = new \ReflectionMethod(MailgunApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('h:x-mailgun-variables', $payload); + $this->assertEquals($json, $payload['h:x-mailgun-variables']); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php index 8d7b5cc7e28be..cf40a8cf1eaa6 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php @@ -114,7 +114,7 @@ private function getPayload(Email $email, Envelope $envelope): array continue; } - $payload['h:'.$name] = $header->toString(); + $payload['h:'.$name] = $header->getBodyAsString(); } return $payload; diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php index b6568706f8306..6996997b659c2 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Tests/Transport/PostmarkApiTransportTest.php @@ -13,6 +13,9 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Postmark\Transport\PostmarkApiTransport; +use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mime\Address; +use Symfony\Component\Mime\Email; class PostmarkApiTransportTest extends TestCase { @@ -41,4 +44,21 @@ public function getTransportData() ], ]; } + + public function testCustomHeader() + { + $email = new Email(); + $email->getHeaders()->addTextHeader('foo', 'bar'); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new PostmarkApiTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(PostmarkApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('Headers', $payload); + $this->assertCount(1, $payload['Headers']); + + $this->assertEquals(['Name' => 'foo', 'Value' => 'bar'], $payload['Headers'][0]); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php index 96dd8d4a65f3f..610f858260549 100644 --- a/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Postmark/Transport/PostmarkApiTransport.php @@ -84,7 +84,7 @@ private function getPayload(Email $email, Envelope $envelope): array $payload['Headers'][] = [ 'Name' => $name, - 'Value' => $header->toString(), + 'Value' => $header->getBodyAsString(), ]; } diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php index f94ace1b2f445..ab271d574c796 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Tests/Transport/SendgridApiTransportTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Bridge\Sendgrid\Transport\SendgridApiTransport; +use Symfony\Component\Mailer\Envelope; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Email; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -149,4 +150,20 @@ public function testLineBreaksInEncodedAttachment() $mailer->send($email); } + + public function testCustomHeader() + { + $email = new Email(); + $email->getHeaders()->addTextHeader('foo', 'bar'); + $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); + + $transport = new SendgridApiTransport('ACCESS_KEY'); + $method = new \ReflectionMethod(SendgridApiTransport::class, 'getPayload'); + $method->setAccessible(true); + $payload = $method->invoke($transport, $email, $envelope); + + $this->assertArrayHasKey('headers', $payload); + $this->assertArrayHasKey('foo', $payload['headers']); + $this->assertEquals('bar', $payload['headers']['foo']); + } } diff --git a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php index 1864e7a2eceb9..df90d2147277a 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendgrid/Transport/SendgridApiTransport.php @@ -104,7 +104,7 @@ private function getPayload(Email $email, Envelope $envelope): array continue; } - $payload['headers'][$name] = $header->toString(); + $payload['headers'][$name] = $header->getBodyAsString(); } return $payload; From c651f63813cf7f228494c6ed44f3f1d795f5f4ac Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 4 Jan 2020 14:48:34 +0100 Subject: [PATCH 057/124] [HttpClient] fix support for non-blocking resource streams --- .../HttpClient/Response/StreamWrapper.php | 17 ++++++++++++++++- .../HttpClient/Tests/HttpClientTestCase.php | 16 ++++++++++++++++ .../HttpClient/Tests/MockHttpClientTest.php | 4 ++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php index 59fd118e86e01..c8a32d820a255 100644 --- a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php +++ b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php @@ -37,6 +37,8 @@ class StreamWrapper /** @var resource|null */ private $handle; + private $blocking = true; + private $timeout; private $eof = false; private $offset = 0; @@ -147,7 +149,7 @@ public function stream_read(int $count) return $data; } - foreach ($this->client->stream([$this->response]) as $chunk) { + foreach ($this->client->stream([$this->response], $this->blocking ? $this->timeout : 0) as $chunk) { try { $this->eof = true; $this->eof = !$chunk->isTimeout(); @@ -178,6 +180,19 @@ public function stream_read(int $count) return ''; } + public function stream_set_option(int $option, int $arg1, ?int $arg2): bool + { + if (STREAM_OPTION_BLOCKING === $option) { + $this->blocking = (bool) $arg1; + } elseif (STREAM_OPTION_READ_TIMEOUT === $option) { + $this->timeout = $arg1 + $arg2 / 1e6; + } else { + return false; + } + + return true; + } + public function stream_tell(): int { return $this->offset; diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index b4b5b9ec1a639..29171969b457e 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -75,4 +75,20 @@ public function testToStream404() $response = $client->request('GET', 'http://localhost:8057/404'); $stream = $response->toStream(); } + + public function testNonBlockingStream() + { + $client = $this->getHttpClient(__FUNCTION__); + $response = $client->request('GET', 'http://localhost:8057/timeout-body'); + $stream = $response->toStream(); + + $this->assertTrue(stream_set_blocking($stream, false)); + $this->assertSame('<1>', fread($stream, 8192)); + $this->assertFalse(feof($stream)); + + $this->assertTrue(stream_set_blocking($stream, true)); + $this->assertSame('<2>', fread($stream, 8192)); + $this->assertSame('', fread($stream, 8192)); + $this->assertTrue(feof($stream)); + } } diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php index 7bc528354811b..bce4bfafea8cc 100644 --- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php @@ -171,6 +171,10 @@ protected function getHttpClient(string $testCase): HttpClientInterface return $client; + case 'testNonBlockingStream': + $responses[] = new MockResponse((function () { yield '<1>'; yield ''; yield '<2>'; })(), ['response_headers' => $headers]); + break; + case 'testMaxDuration': $mock = $this->getMockBuilder(ResponseInterface::class)->getMock(); $mock->expects($this->any()) From 8b61c956858fb880365365ebe9397b729df58b81 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 4 Jan 2020 15:00:37 +0100 Subject: [PATCH 058/124] [HttpClient] NativeHttpClient should not send >1.1 protocol version --- src/Symfony/Component/HttpClient/NativeHttpClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index de6667d540dde..7081842ddf4eb 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -170,7 +170,7 @@ public function request(string $method, string $url, array $options = []): Respo $context = [ 'http' => [ - 'protocol_version' => $options['http_version'] ?: '1.1', + 'protocol_version' => min($options['http_version'] ?: '1.1', '1.1'), 'method' => $method, 'content' => $options['body'], 'ignore_errors' => true, From 2ef8771ad7a90366b31e24f986d23e686bc1ef41 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 4 Jan 2020 19:57:41 +0100 Subject: [PATCH 059/124] [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 25de3ce44079c..94a1efb469cd3 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 625ac5e6fe51d..d4d23dfb0d44f 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 99dab87adac128da2f738a25a633f18b89a62b86 Mon Sep 17 00:00:00 2001 From: Maciej Malarz Date: Sat, 4 Jan 2020 20:22:08 +0100 Subject: [PATCH 060/124] [DI] DecoratorServicePass should keep container.service_locator on the decorated definition --- .../Compiler/DecoratorServicePass.php | 14 ++++++++++++-- .../Compiler/DecoratorServicePassTest.php | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php index f49e8cf949985..e65b7b331ea30 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php @@ -64,8 +64,18 @@ public function process(ContainerBuilder $container) if (isset($decoratingDefinitions[$inner])) { $decoratingDefinition = $decoratingDefinitions[$inner]; - $definition->setTags(array_merge($decoratingDefinition->getTags(), $definition->getTags())); - $decoratingDefinition->setTags([]); + + $decoratingTags = $decoratingDefinition->getTags(); + $resetTags = []; + + if (isset($decoratingTags['container.service_locator'])) { + // container.service_locator has special logic and it must not be transferred out to decorators + $resetTags = ['container.service_locator' => $decoratingTags['container.service_locator']]; + unset($decoratingTags['container.service_locator']); + } + + $definition->setTags(array_merge($decoratingTags, $definition->getTags())); + $decoratingDefinition->setTags($resetTags); $decoratingDefinitions[$inner] = $definition; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php index d8d7587c8d425..721426b024dc4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php @@ -167,6 +167,25 @@ public function testProcessMovesTagsFromDecoratedDefinitionToDecoratingDefinitio $this->assertEquals(['bar' => ['attr' => 'baz']], $container->getDefinition('deco2')->getTags()); } + public function testProcessLeavesServiceLocatorTagOnOriginalDefinition() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->setTags(['container.service_locator' => [0 => []], 'bar' => ['attr' => 'baz']]) + ; + $container + ->register('baz') + ->setTags(['foobar' => ['attr' => 'bar']]) + ->setDecoratedService('foo') + ; + + $this->process($container); + + $this->assertEquals(['container.service_locator' => [0 => []]], $container->getDefinition('baz.inner')->getTags()); + $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); + } + protected function process(ContainerBuilder $container) { $repeatedPass = new DecoratorServicePass(); From ac3d77a76acbc67da67b67a6f37f39807238d4f0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 5 Jan 2020 14:56:11 +0100 Subject: [PATCH 061/124] [HttpClient] Don't read from the network faster than the CPU can deal with --- .../Component/HttpClient/CurlHttpClient.php | 6 +- .../Component/HttpClient/NativeHttpClient.php | 4 +- .../HttpClient/Response/CurlResponse.php | 46 +++++---------- .../HttpClient/Response/MockResponse.php | 17 +----- .../HttpClient/Response/NativeResponse.php | 47 ++++----------- .../HttpClient/Response/ResponseTrait.php | 57 ++++++++++++++----- 6 files changed, 77 insertions(+), 100 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 494bf76a1043d..727f878ccc0d7 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -113,7 +113,7 @@ public function request(string $method, string $url, array $options = []): Respo $url = implode('', $url); if (!isset($options['normalized_headers']['user-agent'])) { - $options['normalized_headers']['user-agent'][] = $options['headers'][] = 'User-Agent: Symfony HttpClient/Curl'; + $options['headers'][] = 'User-Agent: Symfony HttpClient/Curl'; } $curlopts = [ @@ -194,8 +194,8 @@ public function request(string $method, string $url, array $options = []): Respo $curlopts[CURLOPT_NOSIGNAL] = true; } - if (!isset($options['normalized_headers']['accept-encoding']) && CURL_VERSION_LIBZ & self::$curlVersion['features']) { - $curlopts[CURLOPT_ENCODING] = 'gzip'; // Expose only one encoding, some servers mess up when more are provided + if (\extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) { + $options['headers'][] = 'Accept-Encoding: gzip'; // Expose only one encoding, some servers mess up when more are provided } foreach ($options['headers'] as $header) { diff --git a/src/Symfony/Component/HttpClient/NativeHttpClient.php b/src/Symfony/Component/HttpClient/NativeHttpClient.php index 7081842ddf4eb..06b1f3ad7121d 100644 --- a/src/Symfony/Component/HttpClient/NativeHttpClient.php +++ b/src/Symfony/Component/HttpClient/NativeHttpClient.php @@ -77,7 +77,7 @@ public function request(string $method, string $url, array $options = []): Respo $options['headers'][] = 'Content-Type: application/x-www-form-urlencoded'; } - if ($gzipEnabled = \extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) { + if (\extension_loaded('zlib') && !isset($options['normalized_headers']['accept-encoding'])) { // gzip is the most widely available algo, no need to deal with deflate $options['headers'][] = 'Accept-Encoding: gzip'; } @@ -210,7 +210,7 @@ public function request(string $method, string $url, array $options = []): Respo $context = stream_context_create($context, ['notification' => $notification]); self::configureHeadersAndProxy($context, $host, $options['headers'], $proxy, $noProxy); - return new NativeResponse($this->multi, $context, implode('', $url), $options, $gzipEnabled, $info, $resolveRedirect, $onProgress, $this->logger); + return new NativeResponse($this->multi, $context, implode('', $url), $options, $info, $resolveRedirect, $onProgress, $this->logger); } /** diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php index 13320acfbba91..51b815b47a1c4 100644 --- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php +++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php @@ -52,6 +52,7 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, $this->id = $id = (int) $ch; $this->logger = $logger; + $this->shouldBuffer = $options['buffer'] ?? true; $this->timeout = $options['timeout'] ?? null; $this->info['http_method'] = $method; $this->info['user_data'] = $options['user_data'] ?? null; @@ -65,30 +66,25 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, curl_setopt($ch, CURLOPT_PRIVATE, \in_array($method, ['GET', 'HEAD', 'OPTIONS', 'TRACE'], true) && 1.0 < (float) ($options['http_version'] ?? 1.1) ? 'H2' : 'H0'); // H = headers + retry counter } - if (null === $content = &$this->content) { - $content = ($options['buffer'] ?? true) ? fopen('php://temp', 'w+') : null; - } else { - // Move the pushed response to the activity list - if (ftell($content)) { - rewind($content); - $multi->handlesActivity[$id][] = stream_get_contents($content); - } - $content = ($options['buffer'] ?? true) ? $content : null; - } - curl_setopt($ch, CURLOPT_HEADERFUNCTION, static function ($ch, string $data) use (&$info, &$headers, $options, $multi, $id, &$location, $resolveRedirect, $logger): int { return self::parseHeaderLine($ch, $data, $info, $headers, $options, $multi, $id, $location, $resolveRedirect, $logger); }); if (null === $options) { // Pushed response: buffer until requested - curl_setopt($ch, CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use (&$content): int { - return fwrite($content, $data); + curl_setopt($ch, CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { + $multi->handlesActivity[$id][] = $data; + curl_pause($ch, CURLPAUSE_RECV); + + return \strlen($data); }); return; } + $this->inflate = !isset($options['normalized_headers']['accept-encoding']); + curl_pause($ch, CURLPAUSE_CONT); + if ($onProgress = $options['on_progress']) { $url = isset($info['url']) ? ['url' => $info['url']] : []; curl_setopt($ch, CURLOPT_NOPROGRESS, false); @@ -108,33 +104,16 @@ public function __construct(CurlClientState $multi, $ch, array $options = null, }); } - curl_setopt($ch, CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use (&$content, $multi, $id): int { + curl_setopt($ch, CURLOPT_WRITEFUNCTION, static function ($ch, string $data) use ($multi, $id): int { $multi->handlesActivity[$id][] = $data; - return null !== $content ? fwrite($content, $data) : \strlen($data); + return \strlen($data); }); $this->initializer = static function (self $response) { - if (null !== $response->info['error']) { - throw new TransportException($response->info['error']); - } - $waitFor = curl_getinfo($ch = $response->handle, CURLINFO_PRIVATE); - if ('H' === $waitFor[0] || 'D' === $waitFor[0]) { - try { - foreach (self::stream([$response]) as $chunk) { - if ($chunk->isFirst()) { - break; - } - } - } catch (\Throwable $e) { - // Persist timeouts thrown during initialization - $response->info['error'] = $e->getMessage(); - $response->close(); - throw $e; - } - } + return 'H' === $waitFor[0] || 'D' === $waitFor[0]; }; // Schedule the request in a non-blocking way @@ -221,6 +200,7 @@ public function __destruct() */ private function close(): void { + $this->inflate = null; unset($this->multi->openHandles[$this->id], $this->multi->handlesActivity[$this->id]); curl_multi_remove_handle($this->multi->handle, $this->handle); curl_setopt_array($this->handle, [ diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php index 4cb8be180b48d..01c3f605a7bbd 100644 --- a/src/Symfony/Component/HttpClient/Response/MockResponse.php +++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php @@ -93,6 +93,7 @@ public function cancel(): void */ protected function close(): void { + $this->inflate = null; $this->body = []; } @@ -104,16 +105,9 @@ public static function fromRequest(string $method, string $url, array $options, $response = new self([]); $response->requestOptions = $options; $response->id = ++self::$idSequence; - $response->content = ($options['buffer'] ?? true) ? fopen('php://temp', 'w+') : null; + $response->shouldBuffer = $options['buffer'] ?? true; $response->initializer = static function (self $response) { - if (null !== $response->info['error']) { - throw new TransportException($response->info['error']); - } - - if (\is_array($response->body[0] ?? null)) { - // Consume the first chunk if it's not yielded yet - self::stream([$response])->current(); - } + return \is_array($response->body[0] ?? null); }; $response->info['redirect_count'] = 0; @@ -186,11 +180,6 @@ protected static function perform(ClientState $multi, array &$responses): void } else { // Data or timeout chunk $multi->handlesActivity[$id][] = $chunk; - - if (\is_string($chunk) && null !== $response->content) { - // Buffer response body - fwrite($response->content, $chunk); - } } } } diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php index 383603dd28833..f8c19fbf8c7d3 100644 --- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php +++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php @@ -32,14 +32,13 @@ final class NativeResponse implements ResponseInterface private $onProgress; private $remaining; private $buffer; - private $inflate; private $multi; private $debugBuffer; /** * @internal */ - public function __construct(NativeClientState $multi, $context, string $url, $options, bool $gzipEnabled, array &$info, callable $resolveRedirect, ?callable $onProgress, ?LoggerInterface $logger) + public function __construct(NativeClientState $multi, $context, string $url, array $options, array &$info, callable $resolveRedirect, ?callable $onProgress, ?LoggerInterface $logger) { $this->multi = $multi; $this->id = (int) $context; @@ -50,27 +49,17 @@ public function __construct(NativeClientState $multi, $context, string $url, $op $this->info = &$info; $this->resolveRedirect = $resolveRedirect; $this->onProgress = $onProgress; - $this->content = $options['buffer'] ? fopen('php://temp', 'w+') : null; + $this->inflate = !isset($options['normalized_headers']['accept-encoding']); + $this->shouldBuffer = $options['buffer'] ?? true; - // Temporary resources to dechunk/inflate the response stream + // Temporary resource to dechunk the response stream $this->buffer = fopen('php://temp', 'w+'); - $this->inflate = $gzipEnabled ? inflate_init(ZLIB_ENCODING_GZIP) : null; $info['user_data'] = $options['user_data']; ++$multi->responseCount; $this->initializer = static function (self $response) { - if (null !== $response->info['error']) { - throw new TransportException($response->info['error']); - } - - if (null === $response->remaining) { - foreach (self::stream([$response]) as $chunk) { - if ($chunk->isFirst()) { - break; - } - } - } + return null === $response->remaining; }; } @@ -165,7 +154,7 @@ private function open(): void stream_set_blocking($h, false); $this->context = $this->resolveRedirect = null; - // Create dechunk and inflate buffers + // Create dechunk buffers if (isset($this->headers['content-length'])) { $this->remaining = (int) $this->headers['content-length'][0]; } elseif ('chunked' === ($this->headers['transfer-encoding'][0] ?? null)) { @@ -175,10 +164,6 @@ private function open(): void $this->remaining = -2; } - if ($this->inflate && 'gzip' !== ($this->headers['content-encoding'][0] ?? null)) { - $this->inflate = null; - } - $this->multi->handlesActivity[$this->id] = [new FirstChunk()]; if ('HEAD' === $context['http']['method'] || \in_array($this->info['http_code'], [204, 304], true)) { @@ -188,7 +173,7 @@ private function open(): void return; } - $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, $this->content, $this->onProgress, &$this->remaining, &$this->info]; + $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->onProgress, &$this->remaining, &$this->info]; } /** @@ -228,15 +213,15 @@ private static function perform(NativeClientState $multi, array &$responses = nu $multi->handles = []; } - foreach ($multi->openHandles as $i => [$h, $buffer, $inflate, $content, $onProgress]) { + foreach ($multi->openHandles as $i => [$h, $buffer, $onProgress]) { $hasActivity = false; - $remaining = &$multi->openHandles[$i][5]; - $info = &$multi->openHandles[$i][6]; + $remaining = &$multi->openHandles[$i][3]; + $info = &$multi->openHandles[$i][4]; $e = null; // Read incoming buffer and write it to the dechunk one try { - while ($remaining && '' !== $data = (string) fread($h, 0 > $remaining ? 16372 : $remaining)) { + if ($remaining && '' !== $data = (string) fread($h, 0 > $remaining ? 16372 : $remaining)) { fwrite($buffer, $data); $hasActivity = true; $multi->sleep = false; @@ -264,16 +249,8 @@ private static function perform(NativeClientState $multi, array &$responses = nu rewind($buffer); ftruncate($buffer, 0); - if (null !== $inflate && false === $data = @inflate_add($inflate, $data)) { - $e = new TransportException('Error while processing content unencoding.'); - } - - if ('' !== $data && null === $e) { + if (null === $e) { $multi->handlesActivity[$i][] = $data; - - if (null !== $content && \strlen($data) !== fwrite($content, $data)) { - $e = new TransportException(sprintf('Failed writing %d bytes to the response buffer.', \strlen($data))); - } } } diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php index 52e413a07ad33..d249d63048781 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -39,11 +39,6 @@ trait ResponseTrait */ private $initializer; - /** - * @var resource A php://temp stream typically - */ - private $content; - private $info = [ 'response_headers' => [], 'http_code' => 0, @@ -54,6 +49,9 @@ trait ResponseTrait private $handle; private $id; private $timeout; + private $inflate; + private $shouldBuffer; + private $content; private $finalInfo; private $offset = 0; private $jsonData; @@ -64,8 +62,7 @@ trait ResponseTrait public function getStatusCode(): int { if ($this->initializer) { - ($this->initializer)($this); - $this->initializer = null; + self::initialize($this); } return $this->info['http_code']; @@ -77,8 +74,7 @@ public function getStatusCode(): int public function getHeaders(bool $throw = true): array { if ($this->initializer) { - ($this->initializer)($this); - $this->initializer = null; + self::initialize($this); } if ($throw) { @@ -94,8 +90,7 @@ public function getHeaders(bool $throw = true): array public function getContent(bool $throw = true): string { if ($this->initializer) { - ($this->initializer)($this); - $this->initializer = null; + self::initialize($this); } if ($throw) { @@ -201,6 +196,30 @@ abstract protected static function perform(ClientState $multi, array &$responses */ abstract protected static function select(ClientState $multi, float $timeout): int; + private static function initialize(self $response): void + { + if (null !== $response->info['error']) { + throw new TransportException($response->info['error']); + } + + try { + if (($response->initializer)($response)) { + foreach (self::stream([$response]) as $chunk) { + if ($chunk->isFirst()) { + break; + } + } + } + } catch (\Throwable $e) { + // Persist timeouts thrown during initialization + $response->info['error'] = $e->getMessage(); + $response->close(); + throw $e; + } + + $response->initializer = null; + } + private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers, string &$debug = ''): void { foreach ($responseHeaders as $h) { @@ -246,8 +265,7 @@ private function checkStatusCode() private function doDestruct() { if ($this->initializer && null === $this->info['error']) { - ($this->initializer)($this); - $this->initializer = null; + self::initialize($this); $this->checkStatusCode(); } } @@ -299,6 +317,16 @@ public static function stream(iterable $responses, float $timeout = null): \Gene $isTimeout = false; if (\is_string($chunk = array_shift($multi->handlesActivity[$j]))) { + if (null !== $response->inflate && false === $chunk = @inflate_add($response->inflate, $chunk)) { + $multi->handlesActivity[$j] = [null, new TransportException('Error while processing content unencoding.')]; + continue; + } + + 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))]; + continue; + } + $response->offset += \strlen($chunk); $chunk = new DataChunk($response->offset, $chunk); } elseif (null === $chunk) { @@ -326,6 +354,9 @@ public static function stream(iterable $responses, float $timeout = null): \Gene $response->logger->info(sprintf('Response: "%s %s"', $info['http_code'], $info['url'])); } + $response->inflate = \extension_loaded('zlib') && $response->inflate && 'gzip' === ($response->headers['content-encoding'][0] ?? null) ? inflate_init(ZLIB_ENCODING_GZIP) : null; + $response->content = $response->shouldBuffer ? fopen('php://temp', 'w+') : null; + yield $response => $chunk; if ($response->initializer && null === $response->info['error']) { From 4f80d4d63920626d3fafe6a2e118634497c39946 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 6 Jan 2020 11:24:48 +0100 Subject: [PATCH 062/124] [Notifier] Fix two minor issues --- src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php | 2 +- src/Symfony/Component/Notifier/Message/SmsMessage.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php index 9ce02fa0b703a..ae46ffbea2fe3 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransport.php @@ -69,7 +69,7 @@ protected function doSend(MessageInterface $message): void $result = $response->toArray(false); foreach ($result['messages'] as $msg) { - if ($msg['status'] ?? 0 > 0) { + if ($msg['status'] ?? false) { throw new TransportException(sprintf('Unable to send the SMS: %s (%s).', $msg['error-text'], $msg['status']), $response); } } diff --git a/src/Symfony/Component/Notifier/Message/SmsMessage.php b/src/Symfony/Component/Notifier/Message/SmsMessage.php index e704e169a9040..9fbb75ce3af40 100644 --- a/src/Symfony/Component/Notifier/Message/SmsMessage.php +++ b/src/Symfony/Component/Notifier/Message/SmsMessage.php @@ -37,7 +37,7 @@ public function __construct(string $phone, string $subject) public static function fromNotification(Notification $notification, Recipient $recipient, string $transport = null): self { if (!$recipient instanceof SmsRecipientInterface) { - throw new LogicException(sprintf('To send a SMS message, "%s" should implement "%s" or the recipient should implement "%s".', get_class($notification), SmsNotificationInterface::class, SmsRecipientInterface::class)); + throw new LogicException(sprintf('To send a SMS message, "%s" should implement "%s" or the recipient should implement "%s".', \get_class($notification), SmsNotificationInterface::class, SmsRecipientInterface::class)); } return new self($recipient->getPhone(), $notification->getSubject()); From c2d2e5a61ddca46b46ffbaf0c5de96564793cf8b Mon Sep 17 00:00:00 2001 From: Tomas Date: Mon, 6 Jan 2020 13:23:58 +0200 Subject: [PATCH 063/124] Fix closing tag in mailer collector template --- .../Resources/views/Collector/mailer.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig index 819711eff774b..983a6f39f062d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/mailer.html.twig @@ -94,7 +94,7 @@ {% for transport in events.transports %}
{{ events.messages(transport)|length }} - {{ events.messages(transport)|length == 1 ? 'message' : 'messages' }} + {{ events.messages(transport)|length == 1 ? 'message' : 'messages' }}
{% endfor %} From 87212e41b395921d4fac8692009947cc53d3922e Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 2 Jan 2020 12:21:52 +0100 Subject: [PATCH 064/124] [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 7375450d5d219..fcf145cc4603f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -200,12 +200,12 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - $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 @@ protected function execute(InputInterface $input, OutputInterface $output) // 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 @@ protected function execute(InputInterface $input, OutputInterface $output) } 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 @@ protected function execute(InputInterface $input, OutputInterface $output) // 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 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - $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 065/124] [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 3a1046b0c4a17..51f56c220d33c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php @@ -33,7 +33,7 @@ public function testUserChangeClearsCookie() $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 1a8057b6fbd08..f0e35c7f3d7e8 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 8dacdafb574d1..bf69f3012b6ba 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -99,6 +99,10 @@ public function getSecret() */ 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 8dc2042f12c09..cf70ed4cb1618 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 @@ public function testAutoLoginReturnsNullWhenNoCookie() $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 066/124] [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 f21a88b3b44d4..dda645a6fca2e 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -556,7 +556,7 @@ public function write($content, array $metadata = null) } } - public function __destruct() + public function release() { flock($this->lock, LOCK_UN); fclose($this->lock); @@ -634,7 +634,7 @@ public function __destruct() } $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 067/124] 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 e082df1c4559c..f52d0271e4117 100644 --- a/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php +++ b/src/Symfony/Component/Cache/DependencyInjection/CachePoolPass.php @@ -103,7 +103,12 @@ public function process(ContainerBuilder $container) 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 e763dabe48cfa..20701adcb4507 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 @@ public function testThrowsExceptionWhenCachePoolTagHasUnknownAttributes() $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 068/124] [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 4bbcedbf124a2..7c414258b79f2 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 @@ private function checkType(Definition $checkedDefinition, $value, \ReflectionPar 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 22a29fa4d6dc0..350f85296a09c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckTypeDeclarationsPassTest.php @@ -13,6 +13,7 @@ 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 @@ public function testProcessHandleClosureForCallable() $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 b7056016094a1..69f1a693a4c5b 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 @@ public function setIterable(iterable $iterable) 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 069/124] [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 e756ea5d3f434..08023b9c42718 100644 --- a/src/Symfony/Component/HttpClient/HttplugClient.php +++ b/src/Symfony/Component/HttpClient/HttplugClient.php @@ -16,6 +16,7 @@ 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 @@ public function __construct(HttpClientInterface $client = null, ResponseFactoryI 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 ba59dc11f7ecc..67c2fdb8f07bc 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 @@ public function __construct(HttpClientInterface $client = null, ResponseFactoryI 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 070/124] [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 5e6277567eff3..290f1da5e3af7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerLintCommand.php @@ -102,11 +102,12 @@ private function getContainerBuilder(): ContainerBuilder $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 071/124] [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 57eafa2c1db77..6dd7a0287b5e5 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 @@ public function testGetNonBlocking() $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 33d6057f67004..e1980221625e3 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -248,6 +248,10 @@ public function add(string $body, array $headers, int $delayInMs = 0): void '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 @@ public function add(string $body, array $headers, int $delayInMs = 0): void '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 072/124] [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 81baaac8d96a2..5d9f68a982a83 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 @@ public function testGetNonBlocking() $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 6ded724ca5bfa..b9515e7ad0cc1 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -185,9 +185,16 @@ public function add(string $body, array $headers): void } 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 073/124] [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 262fdd9dea603..da99873a936a3 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 074/124] [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 ad4477cba5dea..cee716eb47b33 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 075/124] [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 d249d63048781..c747f373a03a5 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -323,7 +323,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene } 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 076/124] [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 84e66b1d0bd79..63424e165d477 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -203,7 +203,10 @@ private function lexValue() $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 43607d35550b6..fa53029c67dea 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -40,6 +40,7 @@ public function getEnvDataWithFormatErrors() ['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 077/124] [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 bbf70eaac3734..a3ffaa3df5e1f 100644 --- a/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php +++ b/src/Symfony/Component/Serializer/NameConverter/MetadataAwareNameConverter.php @@ -47,7 +47,7 @@ public function normalize($propertyName, string $class = null, string $format = 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 @@ public function denormalize($propertyName, string $class = null, string $format } $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 @@ private function getCacheValueForNormalization(string $propertyName, string $cla } $attributesMetadata = $this->metadataFactory->getMetadataFor($class)->getAttributesMetadata(); - if (!isset($attributesMetadata[$propertyName])) { + if (!\array_key_exists($propertyName, $attributesMetadata)) { return null; } @@ -93,7 +93,7 @@ private function normalizeFallback(string $propertyName, string $class = null, s 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 b9931f571cacee05ab7a7fbdea3711c9b36e73d4 Mon Sep 17 00:00:00 2001 From: Philippe Segatori Date: Sun, 22 Dec 2019 00:26:00 +0100 Subject: [PATCH 078/124] [Notifier] Add more specific types at documentation level when php engine can't --- .../Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php | 3 +++ .../Component/Notifier/Bridge/Slack/SlackTransportFactory.php | 3 +++ .../Notifier/Bridge/Telegram/TelegramTransportFactory.php | 3 +++ .../Notifier/Bridge/Twilio/TwilioTransportFactory.php | 3 +++ src/Symfony/Component/Notifier/Message/SmsMessage.php | 2 +- .../Component/Notifier/Transport/NullTransportFactory.php | 3 +++ 6 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php index 21f2e080bd8e4..e4a4479fb2f1e 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/NexmoTransportFactory.php @@ -23,6 +23,9 @@ */ final class NexmoTransportFactory extends AbstractTransportFactory { + /** + * @return NexmoTransport + */ public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransportFactory.php index 6e12c0b218a63..0600b1c9104ae 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/SlackTransportFactory.php @@ -23,6 +23,9 @@ */ final class SlackTransportFactory extends AbstractTransportFactory { + /** + * @return SlackTransport + */ public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransportFactory.php index 07378dc6a8cd5..9640d64c3c490 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/TelegramTransportFactory.php @@ -24,6 +24,9 @@ */ final class TelegramTransportFactory extends AbstractTransportFactory { + /** + * @return TelegramTransport + */ public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); diff --git a/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransportFactory.php index 8353eec7e6810..65fb413a3dc8f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Twilio/TwilioTransportFactory.php @@ -23,6 +23,9 @@ */ final class TwilioTransportFactory extends AbstractTransportFactory { + /** + * @return TwilioTransport + */ public function create(Dsn $dsn): TransportInterface { $scheme = $dsn->getScheme(); diff --git a/src/Symfony/Component/Notifier/Message/SmsMessage.php b/src/Symfony/Component/Notifier/Message/SmsMessage.php index 9fbb75ce3af40..6b0bdd3806df4 100644 --- a/src/Symfony/Component/Notifier/Message/SmsMessage.php +++ b/src/Symfony/Component/Notifier/Message/SmsMessage.php @@ -58,7 +58,7 @@ public function getPhone(): string return $this->phone; } - public function getRecipientId(): ?string + public function getRecipientId(): string { return $this->phone; } diff --git a/src/Symfony/Component/Notifier/Transport/NullTransportFactory.php b/src/Symfony/Component/Notifier/Transport/NullTransportFactory.php index f93ff8c7b0c29..abfcd1c75d3f7 100644 --- a/src/Symfony/Component/Notifier/Transport/NullTransportFactory.php +++ b/src/Symfony/Component/Notifier/Transport/NullTransportFactory.php @@ -20,6 +20,9 @@ */ final class NullTransportFactory extends AbstractTransportFactory { + /** + * @return NullTransport + */ public function create(Dsn $dsn): TransportInterface { if ('null' === $dsn->getScheme()) { From b3a2173c8ec04bbd205be21a4eb38298708ec350 Mon Sep 17 00:00:00 2001 From: Islam93 Date: Mon, 30 Dec 2019 22:53:00 +0300 Subject: [PATCH 079/124] [DI] deferred exceptions in ResolveParameterPlaceHoldersPass --- .../Compiler/PassConfig.php | 2 +- .../ResolveParameterPlaceHoldersPass.php | 15 +++++++++-- .../ResolveParameterPlaceHoldersPassTest.php | 26 +++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 323faad57f9a0..bf8d75e6df280 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -53,7 +53,7 @@ public function __construct() new ServiceLocatorTagPass(), new RegisterServiceSubscribersPass(), new DecoratorServicePass(), - new ResolveParameterPlaceHoldersPass(false), + new ResolveParameterPlaceHoldersPass(false, false), new ResolveFactoryClassPass(), new FactoryReturnTypePass($resolveClassPass), new CheckDefinitionValidityPass(), diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php index 8c942b524ea3b..32eb6a3a76f3e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php @@ -24,10 +24,12 @@ class ResolveParameterPlaceHoldersPass extends AbstractRecursivePass { private $bag; private $resolveArrays; + private $throwOnResolveException; - public function __construct($resolveArrays = true) + public function __construct($resolveArrays = true, $throwOnResolveException = true) { $this->resolveArrays = $resolveArrays; + $this->throwOnResolveException = $throwOnResolveException; } /** @@ -61,7 +63,16 @@ public function process(ContainerBuilder $container) protected function processValue($value, $isRoot = false) { if (\is_string($value)) { - $v = $this->bag->resolveValue($value); + try { + $v = $this->bag->resolveValue($value); + } catch (ParameterNotFoundException $e) { + if ($this->throwOnResolveException) { + throw $e; + } + + $v = null; + $this->container->getDefinition($this->currentId)->addError($e->getMessage()); + } return $this->resolveArrays || !$v || !\is_array($v) ? $v : $value; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php index 5aa6471751f24..06399614392e5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; class ResolveParameterPlaceHoldersPassTest extends TestCase { @@ -71,6 +72,31 @@ public function testBindingsShouldBeResolved() $this->assertSame($this->container->getParameterBag()->resolveValue('%env(BAZ)%'), $boundValue); } + public function testParameterNotFoundExceptionsIsThrown() + { + $this->expectException(ParameterNotFoundException::class); + $this->expectExceptionMessage('The service "baz_service_id" has a dependency on a non-existent parameter "non_existent_param".'); + + $containerBuilder = new ContainerBuilder(); + $definition = $containerBuilder->register('baz_service_id'); + $definition->setArgument(0, '%non_existent_param%'); + + $pass = new ResolveParameterPlaceHoldersPass(); + $pass->process($containerBuilder); + } + + public function testParameterNotFoundExceptionsIsNotThrown() + { + $containerBuilder = new ContainerBuilder(); + $definition = $containerBuilder->register('baz_service_id'); + $definition->setArgument(0, '%non_existent_param%'); + + $pass = new ResolveParameterPlaceHoldersPass(true, false); + $pass->process($containerBuilder); + + $this->assertCount(1, $definition->getErrors()); + } + private function createContainerBuilder() { $containerBuilder = new ContainerBuilder(); From 3a840a9796ffdc59f9f3d87d9cbf86b6d3db92e9 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Jan 2020 15:00:15 +0100 Subject: [PATCH 080/124] [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 003bdc3e298b1..3f91cd64b2450 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -291,7 +291,7 @@ public function getMatcher() 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 @@ public function getGenerator() 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 @@ public function addExpressionLanguageProvider(ExpressionFunctionProviderInterfac */ 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 @@ protected function getGeneratorDumperInstance() */ 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 add10dfe2c7c3fa897b4e8e9dea3111113ad3d02 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Jan 2020 15:54:22 +0100 Subject: [PATCH 081/124] [FrameworkBundle] Document the router.cache_class_prefix parameter removal --- UPGRADE-5.0.md | 1 + src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 7e75c9593fbbc..c25b547e2199a 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -243,6 +243,7 @@ FrameworkBundle * Removed `routing.loader.service`. * Added support for PHPUnit 8. A `void` return-type was added to the `KernelTestCase::tearDown()` and `WebTestCase::tearDown()` method. * Removed the `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract` services. + * Removed the `router.cache_class_prefix` parameter. HttpClient ---------- diff --git a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md index 8188769bdd29e..46dc89b255395 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md +++ b/src/Symfony/Bundle/FrameworkBundle/CHANGELOG.md @@ -21,6 +21,7 @@ CHANGELOG * Service route loaders must be tagged with `routing.route_loader`. * Added `slugger` service and `SluggerInterface` alias * Removed the `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract` services. + * Removed the `router.cache_class_prefix` parameter. 4.4.0 ----- From 0c320febe1547e6db30c59390ea5e86a4dd7d487 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 8 Jan 2020 17:32:40 +0100 Subject: [PATCH 082/124] [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 0290b05bad484..3d163eec7775f 100644 --- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php @@ -199,6 +199,10 @@ public function flattenDataProvider() 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 @@ function () {}, 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 @@ public function testRecursionInArguments() 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 9a56b3b4ec8fc..f3564762013fc 100644 --- a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php @@ -29,6 +29,10 @@ public static function setUpBeforeClass() // 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) { From 18ce8399d2820239970e1e85c7d05fd248984890 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 8 Jan 2020 19:32:07 +0100 Subject: [PATCH 083/124] [HttpKernel][FileLocator] Fix deprecation message --- src/Symfony/Component/HttpKernel/Config/FileLocator.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Config/FileLocator.php b/src/Symfony/Component/HttpKernel/Config/FileLocator.php index fecdf223b7b04..03dfe3de316af 100644 --- a/src/Symfony/Component/HttpKernel/Config/FileLocator.php +++ b/src/Symfony/Component/HttpKernel/Config/FileLocator.php @@ -65,7 +65,7 @@ public function locate($file, $currentPath = null, $first = true) || (\strlen($file) > 3 && ctype_alpha($file[0]) && ':' === $file[1] && ('\\' === $file[2] || '/' === $file[2])) || null !== parse_url($file, PHP_URL_SCHEME) )) { - $triggerDeprecation = false; + $deprecation = false; // no need to trigger deprecations when the loaded file is given as absolute path foreach ($this->paths as $deprecatedPath) { @@ -75,13 +75,13 @@ public function locate($file, $currentPath = null, $first = true) } if (0 === strpos($location, $deprecatedPath) && (null === $currentPath || false === strpos($location, $currentPath))) { - $triggerDeprecation = true; + $deprecation = sprintf('Loading the file "%s" from the global resource directory "%s" is deprecated since Symfony 4.4 and will be removed in 5.0.', $file, $deprecatedPath); } } } - if ($triggerDeprecation) { - @trigger_error(sprintf('Loading the file "%s" from the global resource directory "%s" is deprecated since Symfony 4.4 and will be removed in 5.0.', $file, $deprecatedPath), E_USER_DEPRECATED); + if ($deprecation) { + @trigger_error($deprecation, E_USER_DEPRECATED); } } From 576e18561f916d35319d528cbf13c9c4a1c1a91d Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Wed, 8 Jan 2020 14:37:17 +0100 Subject: [PATCH 084/124] [PHPUnit-Bridge] Fail-fast in simple-phpunit if one of the passthru() commands fails --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index da99873a936a3..2bdd705ec0e91 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -15,6 +15,14 @@ error_reporting(-1); +$passthruOrFail = function ($command) { + passthru($command, $status); + + if ($status) { + exit($status); + } +}; + if (PHP_VERSION_ID >= 70200) { // PHPUnit 6 is required for PHP 7.2+ $PHPUNIT_VERSION = getenv('SYMFONY_PHPUNIT_VERSION') ?: '6.5'; @@ -77,25 +85,25 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ rename("phpunit-$PHPUNIT_VERSION", "phpunit-$PHPUNIT_VERSION.old"); passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s': 'rm -rf %s', "phpunit-$PHPUNIT_VERSION.old")); } - passthru("$COMPOSER create-project --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); + $passthruOrFail("$COMPOSER create-project --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); @copy("phpunit-$PHPUNIT_VERSION/phpunit.xsd", 'phpunit.xsd'); chdir("phpunit-$PHPUNIT_VERSION"); if ($SYMFONY_PHPUNIT_REMOVE) { - passthru("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE); + $passthruOrFail("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE); } if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { - passthru("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); + $passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); } - passthru("$COMPOSER config --unset platform"); + $passthruOrFail("$COMPOSER config --unset platform"); if (file_exists($path = $root.'/vendor/symfony/phpunit-bridge')) { - passthru("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\""); - passthru("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $path))); + $passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\""); + $passthruOrFail("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $path))); if ('\\' === DIRECTORY_SEPARATOR) { file_put_contents('composer.json', preg_replace('/^( {8})"phpunit-bridge": \{$/m', "$0\n$1 ".'"options": {"symlink": false},', file_get_contents('composer.json'))); } } else { - passthru("$COMPOSER require --no-update symfony/phpunit-bridge \"*\""); + $passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*\""); } $prevRoot = getenv('COMPOSER_ROOT_VERSION'); putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99"); From a28a42187c994b8559bb95a7791256c6c41cb591 Mon Sep 17 00:00:00 2001 From: Pablo Lozano Date: Thu, 9 Jan 2020 09:55:05 +0100 Subject: [PATCH 085/124] [PHPUnitBridge] file_get_contents() expects parameter 3 to be resource --- 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 da99873a936a3..0366b07cb3ff8 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`)) - ? (file_get_contents($COMPOSER, null, 0, 18) === '#!/usr/bin/env php' ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang + ? (file_get_contents($COMPOSER, false, 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 2be7029b70a0b6af86ef49c56045db1b69aa8107 Mon Sep 17 00:00:00 2001 From: Benhssaein Youssef Date: Wed, 8 Jan 2020 16:02:14 +0100 Subject: [PATCH 086/124] [Process] - update @throws phpdoc --- src/Symfony/Component/Process/Process.php | 27 +++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 5d02c60069ec7..8cc3e768a4fd0 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -135,7 +135,7 @@ class Process implements \IteratorAggregate * @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input * @param int|float|null $timeout The timeout in seconds or null to disable * - * @throws RuntimeException When proc_open is not installed + * @throws LogicException When proc_open is not installed */ public function __construct($command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60) { @@ -188,7 +188,7 @@ public function __construct($command, string $cwd = null, array $env = null, $in * * @return static * - * @throws RuntimeException When proc_open is not installed + * @throws LogicException When proc_open is not installed */ public static function fromShellCommandline(string $command, string $cwd = null, array $env = null, $input = null, ?float $timeout = 60) { @@ -223,9 +223,11 @@ public function __clone() * * @return int The exit status code * - * @throws RuntimeException When process can't be launched - * @throws RuntimeException When process stopped after receiving signal - * @throws LogicException In case a callback is provided and output has been disabled + * @throws RuntimeException When process can't be launched + * @throws RuntimeException When process is already running + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException In case a callback is provided and output has been disabled * * @final */ @@ -390,9 +392,9 @@ public function restart(callable $callback = null, array $env = []) * * @return int The exitcode of the process * - * @throws RuntimeException When process timed out - * @throws RuntimeException When process stopped after receiving signal - * @throws LogicException When process is not yet started + * @throws ProcessTimedOutException When process timed out + * @throws ProcessSignaledException When process stopped after receiving signal + * @throws LogicException When process is not yet started */ public function wait(callable $callback = null) { @@ -403,7 +405,7 @@ public function wait(callable $callback = null) if (null !== $callback) { if (!$this->processPipes->haveReadSupport()) { $this->stop(0); - throw new \LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait"'); + throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::wait"'); } $this->callback = $this->buildCallback($callback); } @@ -433,8 +435,9 @@ public function wait(callable $callback = null) * from the output in real-time while writing the standard input to the process. * It allows to have feedback from the independent process during execution. * - * @throws RuntimeException When process timed out - * @throws LogicException When process is not yet started + * @throws RuntimeException When process timed out + * @throws LogicException When process is not yet started + * @throws ProcessTimedOutException In case the timeout was reached */ public function waitUntil(callable $callback): bool { @@ -443,7 +446,7 @@ public function waitUntil(callable $callback): bool if (!$this->processPipes->haveReadSupport()) { $this->stop(0); - throw new \LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".'); + throw new LogicException('Pass the callback to the "Process::start" method or call enableOutput to use a callback with "Process::waitUntil".'); } $callback = $this->buildCallback($callback); From c314598df9305b59d7fd57018dc4c228de96b4e6 Mon Sep 17 00:00:00 2001 From: Mohamed Gamal Date: Mon, 6 Jan 2020 22:34:32 +0200 Subject: [PATCH 087/124] [String] add test case for wordwrap method --- .../String/Tests/AbstractAsciiTestCase.php | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index 934b29c1486bd..0508a36b3f428 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -55,6 +55,50 @@ public static function provideBytesAt(): array ]; } + /** + * @dataProvider wordwrapProvider + */ + public function testWordwrap($expected, $actual, $length, $break, $cut = false) + { + $instance = static::createFromString($actual); + $actual = $instance->wordwrap($length, $break, $cut); + + $this->assertEquals($expected, $actual); + } + + public function wordwrapProvider() + { + return [ + [ + 'Lo-re-m-Ip-su-m', + 'Lorem Ipsum', + 2, + '-', + true, + ], + [ + 'Lorem-Ipsum', + 'Lorem Ipsum', + 2, + '-', + ], + [ + 'Lor-em-Ips-um', + 'Lorem Ipsum', + 3, + '-', + true, + ], + [ + 'L-o-r-e-m-I-p-s-u-m', + 'Lorem Ipsum', + 1, + '-', + true, + ], + ]; + } + /** * @dataProvider provideWrap */ From 2f7a820eddf34b5a4dd9017c5d09462414f7e9a2 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Fri, 17 May 2019 11:48:13 +0200 Subject: [PATCH 088/124] Added more tests for WebProfilerBundle --- .../Controller/ProfilerControllerTest.php | 186 +++++++++++++++++- .../Functional/WebProfilerBundleKernel.php | 80 ++++++++ .../Bundle/WebProfilerBundle/composer.json | 15 +- 3 files changed, 270 insertions(+), 11 deletions(-) create mode 100644 src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php index c55c67e537a02..d9e20878e5ab2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php @@ -11,19 +11,110 @@ namespace Symfony\Bundle\WebProfilerBundle\Tests\Controller; -use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\Client; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController; use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler; +use Symfony\Bundle\WebProfilerBundle\Tests\Functional\WebProfilerBundleKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Profiler\Profile; -class ProfilerControllerTest extends TestCase +class ProfilerControllerTest extends WebTestCase { + public function testHomeActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->homeAction(); + } + + public function testHomeActionRedirect() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/'); + + $this->assertSame(302, $client->getResponse()->getStatusCode()); + $this->assertSame('/_profiler/empty/search/results?limit=10', $client->getResponse()->getTargetUrl()); + } + + public function testPanelActionWithLatestTokenWhenNoTokensExist() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/latest'); + + $this->assertStringContainsString('No profiles found.', $client->getResponse()->getContent()); + } + + public function testPanelActionWithLatestToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $client->request('GET', '/_profiler/latest'); + + $this->assertStringContainsString('kernel:homepageController', $client->getResponse()->getContent()); + } + + public function testPanelActionWithoutValidToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/this-token-does-not-exist'); + + $this->assertStringContainsString('Token "this-token-does-not-exist" not found.', $client->getResponse()->getContent()); + } + + public function testPanelActionWithWrongPanel() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $client->request('GET', '/_profiler/latest?panel=this-panel-does-not-exist'); + + $this->assertSame(404, $client->getResponse()->getStatusCode()); + } + + public function testPanelActionWithValidPanelAndToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $crawler = $client->request('GET', '/_profiler/latest?panel=router'); + + $this->assertSame('_', $crawler->filter('.metrics .metric .value')->eq(0)->text()); + $this->assertSame('12', $crawler->filter('.metrics .metric .value')->eq(1)->text()); + } + + public function testToolbarActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->toolbarAction(Request::create('/_wdt/foo-token'), null); + } + /** * @dataProvider getEmptyTokenCases */ - public function testEmptyToken($token) + public function testToolbarActionWithEmptyToken($token) { $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); @@ -111,10 +202,36 @@ public function testReturns404onTokenNotFound($withCsp) $this->assertEquals(404, $response->getStatusCode()); } + public function testSearchBarActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->searchBarAction(Request::create('/_profiler/search_bar')); + } + + public function testSearchBarActionDefaultPage() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $crawler = $client->request('GET', '/_profiler/search_bar'); + + $this->assertSame(200, $client->getResponse()->getStatusCode()); + + foreach (['ip', 'status_code', 'url', 'token', 'start', 'end'] as $searchCriteria) { + $this->assertSame('', $crawler->filter(sprintf('form input[name="%s"]', $searchCriteria))->text()); + } + } + /** * @dataProvider provideCspVariants */ - public function testSearchResult($withCsp) + public function testSearchResultsAction($withCsp) { $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); $profiler = $this @@ -177,6 +294,67 @@ public function testSearchResult($withCsp) $this->assertEquals(200, $response->getStatusCode()); } + public function testSearchActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->searchBarAction(Request::create('/_profiler/search')); + } + + public function testSearchActionWithToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $token = $client->getResponse()->headers->get('x-debug-token'); + $client->request('GET', '/_profiler/search?token='.$token); + + $this->assertSame(302, $client->getResponse()->getStatusCode()); + $this->assertSame('/_profiler/'.$token, $client->getResponse()->getTargetUrl()); + } + + public function testSearchActionWithoutToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + $client->followRedirects(); + + $client->request('GET', '/'); + $token = $client->getResponse()->headers->get('x-debug-token'); + $client->request('GET', '/_profiler/search?ip=&method=GET&status_code=&url=&token=&start=&end=&limit=10'); + + $this->assertStringContainsString('1 results found', $client->getResponse()->getContent()); + $this->assertStringContainsString(sprintf('%s', $token, $token), $client->getResponse()->getContent()); + } + + public function testPhpinfoActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->phpinfoAction(Request::create('/_profiler/phpinfo')); + } + + public function testPhpinfoAction() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/phpinfo'); + + $this->assertStringContainsString('PHP License', $client->getResponse()->getContent()); + } + public function provideCspVariants() { return [ diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php new file mode 100644 index 0000000000000..5470ca7dc6858 --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php @@ -0,0 +1,80 @@ +name) { + $this->name = parent::getName().substr(md5(__CLASS__), -16); + } + + return $this->name; + } + + public function registerBundles() + { + return [ + new FrameworkBundle(), + new TwigBundle(), + new WebProfilerBundle(), + ]; + } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $routes->import(__DIR__.'/../../Resources/config/routing/profiler.xml', '/_profiler'); + $routes->import(__DIR__.'/../../Resources/config/routing/wdt.xml', '/_wdt'); + $routes->add('/', 'kernel:homepageController'); + } + + protected function configureContainer(ContainerBuilder $containerBuilder, LoaderInterface $loader) + { + $containerBuilder->loadFromExtension('framework', [ + 'secret' => 'foo-secret', + 'profiler' => ['only_exceptions' => false], + 'session' => ['storage_id' => 'session.storage.mock_file'], + ]); + + $containerBuilder->loadFromExtension('web_profiler', [ + 'toolbar' => true, + 'intercept_redirects' => false, + ]); + } + + public function getCacheDir() + { + return sys_get_temp_dir().'/cache-'.spl_object_hash($this); + } + + public function getLogDir() + { + return sys_get_temp_dir().'/log-'.spl_object_hash($this); + } + + public function homepageController() + { + return new Response('Homepage Controller.'); + } +} diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index c82ef0fe0093d..6f254c67cc482 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -17,21 +17,22 @@ ], "require": { "php": "^5.5.9|>=7.0.8", + "symfony/config": "~3.4|~4.0", "symfony/http-kernel": "~3.4.25|^4.2.6", "symfony/polyfill-php70": "~1.0", - "symfony/routing": "~2.8|~3.0|~4.0", - "symfony/twig-bundle": "~2.8|~3.0|~4.0", + "symfony/routing": "~3.4.7|~4.0", + "symfony/twig-bundle": "~3.4|~4.0", "symfony/var-dumper": "~3.3|~4.0", "twig/twig": "~1.34|~2.4" }, "require-dev": { - "symfony/config": "~3.4|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" + "symfony/browser-kit": "~3.4|~4.0", + "symfony/console": "~3.4|~4.0", + "symfony/css-selector": "~3.4|~4.0", + "symfony/framework-bundle": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0" }, "conflict": { - "symfony/config": "<3.4", "symfony/dependency-injection": "<3.4", "symfony/event-dispatcher": "<3.3.1", "symfony/var-dumper": "<3.3" From 0497fd9d31cae2eef5262beca79eb3a397553535 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 9 Jan 2020 13:09:28 +0100 Subject: [PATCH 089/124] Relax transient test --- .../Tests/Controller/ProfilerControllerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php index d9e20878e5ab2..78edaac89e5f2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php @@ -329,7 +329,7 @@ public function testSearchActionWithoutToken() $token = $client->getResponse()->headers->get('x-debug-token'); $client->request('GET', '/_profiler/search?ip=&method=GET&status_code=&url=&token=&start=&end=&limit=10'); - $this->assertStringContainsString('1 results found', $client->getResponse()->getContent()); + $this->assertStringContainsString('results found', $client->getResponse()->getContent()); $this->assertStringContainsString(sprintf('%s', $token, $token), $client->getResponse()->getContent()); } From 4ee84b39150aea665f9822d13f5701ae37c6c510 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 9 Jan 2020 13:29:25 +0100 Subject: [PATCH 090/124] fix deps --- src/Symfony/Bundle/WebProfilerBundle/composer.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index c32e5582febc8..211c4ce7f6b56 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -19,16 +19,16 @@ "php": "^7.1.3", "symfony/config": "^4.2", "symfony/http-kernel": "^4.3", - "symfony/routing": "~3.4.7|~4.0", + "symfony/routing": "^4.3", "symfony/twig-bundle": "~4.2", - "symfony/var-dumper": "~3.4|~4.0", + "symfony/var-dumper": "^4.3", "twig/twig": "^1.41|^2.10" }, "require-dev": { - "symfony/browser-kit": "~3.4|~4.0", - "symfony/console": "~3.4|~4.0", + "symfony/browser-kit": "^4.3", + "symfony/console": "^4.3", "symfony/css-selector": "~3.4|~4.0", - "symfony/framework-bundle": "~3.4|~4.0", + "symfony/framework-bundle": "^4.3", "symfony/stopwatch": "~3.4|~4.0" }, "conflict": { From d24df0d4419b3f0573a657f0f855e8dab5a65cbb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 9 Jan 2020 13:44:20 +0100 Subject: [PATCH 091/124] fix tests --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 3fb5d4bfd7ff8..f726a7cf6c1a7 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -95,7 +95,9 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ $passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); } - $passthruOrFail("$COMPOSER config --unset platform"); + if (PHP_VERSION_ID >= 70000) { + $passthruOrFail("$COMPOSER config --unset platform"); + } if (file_exists($path = $root.'/vendor/symfony/phpunit-bridge')) { $passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\""); $passthruOrFail("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $path))); From f5d407318dfc6410a5935dc2c0c921a7b6f04950 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 9 Jan 2020 14:14:31 +0100 Subject: [PATCH 092/124] expand listener in place --- src/Symfony/Component/EventDispatcher/EventDispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/EventDispatcher/EventDispatcher.php b/src/Symfony/Component/EventDispatcher/EventDispatcher.php index f7c66309827a4..221fdc8f53bae 100644 --- a/src/Symfony/Component/EventDispatcher/EventDispatcher.php +++ b/src/Symfony/Component/EventDispatcher/EventDispatcher.php @@ -270,7 +270,7 @@ private function sortListeners(string $eventName) $this->sorted[$eventName] = []; foreach ($this->listeners[$eventName] as &$listeners) { - foreach ($listeners as $k => $listener) { + foreach ($listeners as $k => &$listener) { if (\is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) { $listener[0] = $listener[0](); } From 416f0abf9962eec2bce3d0e1241972d20acffbbd Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 9 Jan 2020 14:36:09 +0100 Subject: [PATCH 093/124] [PhpUnitBridge] fix compat with older versions of composer --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index f726a7cf6c1a7..11a40d55b6d32 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -95,9 +95,7 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ $passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); } - if (PHP_VERSION_ID >= 70000) { - $passthruOrFail("$COMPOSER config --unset platform"); - } + $passthruOrFail("$COMPOSER config --unset platform.php"); if (file_exists($path = $root.'/vendor/symfony/phpunit-bridge')) { $passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\""); $passthruOrFail("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $path))); From 452f92540bef8e5b02d04f36c27f9d3d9ec8b256 Mon Sep 17 00:00:00 2001 From: Javier Spagnoletti Date: Thu, 9 Jan 2020 17:48:41 -0300 Subject: [PATCH 094/124] [Workflow] Fix configuration node reference for "initial_marking" --- UPGRADE-5.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index 302cea6dec969..6e136a6cc387f 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -416,7 +416,7 @@ Workflow * `ClassInstanceSupportStrategy` has been removed, use `InstanceOfSupportStrategy` instead. * `WorkflowInterface::apply()` has a third argument: `array $context = []`. * `MarkingStoreInterface::setMarking()` has a third argument: `array $context = []`. - * Removed support of `initial_place`. Use `initial_places` instead. + * Removed support of `initial_place`. Use `initial_marking` instead. * `MultipleStateMarkingStore` has been removed. Use `MethodMarkingStore` instead. * `DefinitionBuilder::setInitialPlace()` has been removed, use `DefinitionBuilder::setInitialPlaces()` instead. From eaa767bebd889e429746b214af2d82344f4e78e3 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 9 Jan 2020 22:18:08 +0100 Subject: [PATCH 095/124] [Filesystem][FilesystemCommonTrait] Use a dedicated directory when there are no namespace --- src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php index d828982b8270c..15cc950e81a9b 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php @@ -35,6 +35,8 @@ private function init(string $namespace, ?string $directory) throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+_.A-Za-z0-9] are allowed.', $match[0])); } $directory .= \DIRECTORY_SEPARATOR.$namespace; + } else { + $directory .= \DIRECTORY_SEPARATOR.'@'; } if (!file_exists($directory)) { @mkdir($directory, 0777, true); From a3a9a0e30a224b9c690489e6d106b6886d1b6386 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 7 Jan 2020 05:14:48 +0100 Subject: [PATCH 096/124] [SecurityBundle] Fix collecting traceable listeners info using anonymous: lazy --- .../Debug/TraceableFirewallListener.php | 44 ++++++++++-- .../Debug/TraceableListenerTrait.php | 42 +++++++++++ .../Debug/WrappedLazyListener.php | 72 +++++++++++++++++++ .../SecurityBundle/Debug/WrappedListener.php | 45 +----------- 4 files changed, 156 insertions(+), 47 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php index 62be170ddc1d6..e7f9df1221e69 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php @@ -12,7 +12,10 @@ namespace Symfony\Bundle\SecurityBundle\Debug; use Symfony\Bundle\SecurityBundle\EventListener\FirewallListener; +use Symfony\Bundle\SecurityBundle\Security\FirewallContext; +use Symfony\Bundle\SecurityBundle\Security\LazyFirewallContext; use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\Security\Http\Firewall\AbstractListener; /** * Firewall collecting called listeners. @@ -21,7 +24,7 @@ */ final class TraceableFirewallListener extends FirewallListener { - private $wrappedListeners; + private $wrappedListeners = []; public function getWrappedListeners() { @@ -30,14 +33,47 @@ public function getWrappedListeners() protected function callListeners(RequestEvent $event, iterable $listeners) { + $wrappedListeners = []; + $wrappedLazyListeners = []; + foreach ($listeners as $listener) { - $wrappedListener = new WrappedListener($listener); - $wrappedListener($event); - $this->wrappedListeners[] = $wrappedListener->getInfo(); + if ($listener instanceof LazyFirewallContext) { + \Closure::bind(function () use (&$wrappedLazyListeners, &$wrappedListeners) { + $listeners = []; + foreach ($this->listeners as $listener) { + if ($listener instanceof AbstractListener) { + $listener = new WrappedLazyListener($listener); + $listeners[] = $listener; + $wrappedLazyListeners[] = $listener; + } else { + $listeners[] = function (RequestEvent $event) use ($listener, &$wrappedListeners) { + $wrappedListener = new WrappedListener($listener); + $wrappedListener($event); + $wrappedListeners[] = $wrappedListener->getInfo(); + }; + } + } + $this->listeners = $listeners; + }, $listener, FirewallContext::class)(); + + $listener($event); + } else { + $wrappedListener = $listener instanceof AbstractListener ? new WrappedLazyListener($listener) : new WrappedListener($listener); + $wrappedListener($event); + $wrappedListeners[] = $wrappedListener->getInfo(); + } if ($event->hasResponse()) { break; } } + + if ($wrappedLazyListeners) { + foreach ($wrappedLazyListeners as $lazyListener) { + $this->wrappedListeners[] = $lazyListener->getInfo(); + } + } + + $this->wrappedListeners = array_merge($this->wrappedListeners, $wrappedListeners); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php new file mode 100644 index 0000000000000..7b65d86b75d34 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Debug; + +use Symfony\Component\Security\Http\Firewall\LegacyListenerTrait; + +/** + * @author Robin Chalas + * + * @internal + */ +trait TraceableListenerTrait +{ + use LegacyListenerTrait; + + private $response; + private $listener; + private $time; + private $stub; + + /** + * Proxies all method calls to the original listener. + */ + public function __call(string $method, array $arguments) + { + return $this->listener->{$method}(...$arguments); + } + + public function getWrappedListener() + { + return $this->listener; + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php new file mode 100644 index 0000000000000..649a4065efae3 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Debug; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\Security\Core\Exception\LazyResponseException; +use Symfony\Component\Security\Http\Firewall\AbstractListener; +use Symfony\Component\Security\Http\Firewall\ListenerInterface; +use Symfony\Component\VarDumper\Caster\ClassStub; + +/** + * Wraps a lazy security listener. + * + * @author Robin Chalas + * + * @internal + */ +final class WrappedLazyListener extends AbstractListener implements ListenerInterface +{ + use TraceableListenerTrait; + + public function __construct(AbstractListener $listener) + { + $this->listener = $listener; + } + + public function supports(Request $request): ?bool + { + return $this->listener->supports($request); + } + + /** + * {@inheritdoc} + */ + public function authenticate(RequestEvent $event) + { + $startTime = microtime(true); + + try { + $ret = $this->listener->authenticate($event); + } catch (LazyResponseException $e) { + $this->response = $e->getResponse(); + + throw $e; + } finally { + $this->time = microtime(true) - $startTime; + } + + $this->response = $event->getResponse(); + + return $ret; + } + + public function getInfo(): array + { + return [ + 'response' => $this->response, + 'time' => $this->time, + 'stub' => $this->stub ?? $this->stub = ClassStub::wrapCallable($this->listener), + ]; + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php index 0bc7fdda9e573..e7728f2fae7cd 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php @@ -12,7 +12,6 @@ namespace Symfony\Bundle\SecurityBundle\Debug; use Symfony\Component\HttpKernel\Event\RequestEvent; -use Symfony\Component\Security\Http\Firewall\LegacyListenerTrait; use Symfony\Component\Security\Http\Firewall\ListenerInterface; use Symfony\Component\VarDumper\Caster\ClassStub; @@ -25,13 +24,7 @@ */ final class WrappedListener implements ListenerInterface { - use LegacyListenerTrait; - - private $response; - private $listener; - private $time; - private $stub; - private static $hasVarDumper; + use TraceableListenerTrait; /** * @param callable $listener @@ -57,46 +50,12 @@ public function __invoke(RequestEvent $event) $this->response = $event->getResponse(); } - /** - * Proxies all method calls to the original listener. - */ - public function __call(string $method, array $arguments) - { - return $this->listener->{$method}(...$arguments); - } - - public function getWrappedListener() - { - return $this->listener; - } - public function getInfo(): array { - if (null !== $this->stub) { - // no-op - } elseif (self::$hasVarDumper ?? self::$hasVarDumper = class_exists(ClassStub::class)) { - $this->stub = ClassStub::wrapCallable($this->listener); - } elseif (\is_array($this->listener)) { - $this->stub = (\is_object($this->listener[0]) ? \get_class($this->listener[0]) : $this->listener[0]).'::'.$this->listener[1]; - } elseif ($this->listener instanceof \Closure) { - $r = new \ReflectionFunction($this->listener); - if (false !== strpos($r->name, '{closure}')) { - $this->stub = 'closure'; - } elseif ($class = $r->getClosureScopeClass()) { - $this->stub = $class->name.'::'.$r->name; - } else { - $this->stub = $r->name; - } - } elseif (\is_string($this->listener)) { - $this->stub = $this->listener; - } else { - $this->stub = \get_class($this->listener).'::__invoke'; - } - return [ 'response' => $this->response, 'time' => $this->time, - 'stub' => $this->stub, + 'stub' => $this->stub ?? $this->stub = ClassStub::wrapCallable($this->listener), ]; } } From 474f3bef08f80d30bd6066b28b36ab08c99bd0a1 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 9 Jan 2020 19:48:50 +0100 Subject: [PATCH 097/124] [Console] Fix SymfonyQuestionHelper tests sometimes failing on AppVeyor --- .../Tests/Helper/SymfonyQuestionHelperTest.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php index b7a26f95087f9..467f38b6d45c8 100644 --- a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php @@ -145,13 +145,13 @@ public function testChoiceQuestionPadding() ); $this->assertOutputContains(<< EOT - , $output); + , $output, true); } public function testChoiceQuestionCustomPrompt() @@ -168,9 +168,9 @@ public function testChoiceQuestionCustomPrompt() $this->assertOutputContains(<<ccc> + >ccc> EOT - , $output); + , $output, true); } protected function getInputStream($input) @@ -200,10 +200,15 @@ protected function createInputInterfaceMock($interactive = true) return $mock; } - private function assertOutputContains($expected, StreamOutput $output) + private function assertOutputContains($expected, StreamOutput $output, $normalize = false) { rewind($output->getStream()); $stream = stream_get_contents($output->getStream()); + + if ($normalize) { + $stream = str_replace(PHP_EOL, "\n", $stream); + } + $this->assertStringContainsString($expected, $stream); } } From 3a23ec89c338edbfb39492c7d94fbb95c82b3a95 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 10 Jan 2020 10:52:55 +0000 Subject: [PATCH 098/124] Avoid stale-if-error if kernel.debug = true, because it hides errors --- .../Bundle/FrameworkBundle/HttpCache/HttpCache.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php index 6d79c6a90e29e..c5220f350ca86 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php @@ -37,7 +37,14 @@ public function __construct(KernelInterface $kernel, $cacheDir = null) $this->kernel = $kernel; $this->cacheDir = $cacheDir; - parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge(['debug' => $kernel->isDebug()], $this->getOptions())); + $isDebug = $kernel->isDebug(); + $options = ['debug' => $isDebug]; + + if ($isDebug) { + $options['stale_if_error'] = 0; + } + + parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($options, $this->getOptions())); } /** From 2cc708341e0156e34ef32bfc0fa7be36fe96ede9 Mon Sep 17 00:00:00 2001 From: flack Date: Fri, 10 Jan 2020 11:36:38 +0100 Subject: [PATCH 099/124] Improve upgrading instructions for deprecated router options See https://github.com/symfony/symfony/pull/30249#issuecomment-572976926 --- UPGRADE-5.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-5.0.md b/UPGRADE-5.0.md index c25b547e2199a..00c46aea19d08 100644 --- a/UPGRADE-5.0.md +++ b/UPGRADE-5.0.md @@ -393,7 +393,7 @@ Routing ------- * The `generator_base_class`, `generator_cache_class`, `matcher_base_class`, and `matcher_cache_class` router - options have been removed. + options have been removed. If you are using multiple Router instances and need separate caches for them, set a unique `cache_dir` per Router instance instead. * `Serializable` implementing methods for `Route` and `CompiledRoute` are final. Instead of overwriting them, use `__serialize` and `__unserialize` as extension points which are forward compatible with the new serialization methods in PHP 7.4. From c8bdcb3408e1408ca6657a81d9cf7cad375d19c4 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 10 Jan 2020 22:32:00 +0000 Subject: [PATCH 100/124] Fix that no-cache requires positive validation with the origin, even for fresh responses --- .../Component/HttpKernel/HttpCache/HttpCache.php | 4 ++++ .../HttpKernel/Tests/HttpCache/HttpCacheTest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index dbe028065948d..da60e74642cb4 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -323,6 +323,10 @@ protected function lookup(Request $request, $catch = false) return $this->validate($request, $entry, $catch); } + if ($entry->headers->hasCacheControlDirective('no-cache')) { + return $this->validate($request, $entry, $catch); + } + $this->record($request, 'fresh'); $entry->headers->set('Age', $entry->getAge()); diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index a4e30444a5391..ef201de6cf15f 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -443,6 +443,22 @@ public function testCachesResponsesWithExplicitNoCacheDirective() $this->assertTrue($this->response->headers->has('Age')); } + public function testRevalidatesResponsesWithNoCacheDirectiveEvenIfFresh() + { + $this->setNextResponse(200, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag'], 'OK'); + $this->request('GET', '/'); // warm the cache + + sleep(5); + + $this->setNextResponse(304, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag']); + $this->request('GET', '/'); + + $this->assertHttpKernelIsCalled(); // no-cache -> MUST have revalidated at origin + $this->assertTraceContains('valid'); + $this->assertEquals('OK', $this->response->getContent()); + $this->assertEquals(0, $this->response->getAge()); + } + public function testCachesResponsesWithAnExpirationHeader() { $time = \DateTime::createFromFormat('U', time() + 5); From 25fd665d0e77a8709222e7585005c2fdf44fe153 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 11 Jan 2020 09:47:13 +0100 Subject: [PATCH 101/124] [FrameworkBundle] Make sure one can use fragments.hinclude_default_template --- .../DependencyInjection/FrameworkExtension.php | 2 +- .../Fixtures/php/fragments_and_hinclude.php | 8 ++++++++ .../Fixtures/xml/fragments_and_hinclude.xml | 11 +++++++++++ .../Fixtures/yml/fragments_and_hinclude.yml | 4 ++++ .../DependencyInjection/FrameworkExtensionTest.php | 7 +++++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/fragments_and_hinclude.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/fragments_and_hinclude.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/fragments_and_hinclude.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index a6b8f4658d283..b3a7095cce966 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -523,7 +523,7 @@ private function registerFragmentsConfiguration(array $config, ContainerBuilder return; } - if ($container->hasParameter('fragment.renderer.hinclude.global_template') && null !== $container->getParameter('fragment.renderer.hinclude.global_template') && null !== $config['hinclude_default_template']) { + if ($container->hasParameter('fragment.renderer.hinclude.global_template') && '' !== $container->getParameter('fragment.renderer.hinclude.global_template') && null !== $config['hinclude_default_template']) { throw new \LogicException('You cannot set both "templating.hinclude_default_template" and "fragments.hinclude_default_template", please only use "fragments.hinclude_default_template".'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/fragments_and_hinclude.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/fragments_and_hinclude.php new file mode 100644 index 0000000000000..dbcf5b786dba9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/fragments_and_hinclude.php @@ -0,0 +1,8 @@ +loadFromExtension('framework', [ + 'fragments' => [ + 'enabled' => true, + 'hinclude_default_template' => 'global_hinclude_template', + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/fragments_and_hinclude.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/fragments_and_hinclude.xml new file mode 100644 index 0000000000000..fb007313b9a71 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/fragments_and_hinclude.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/fragments_and_hinclude.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/fragments_and_hinclude.yml new file mode 100644 index 0000000000000..b03f37da7946e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/fragments_and_hinclude.yml @@ -0,0 +1,4 @@ +framework: + fragments: + enabled: true + hinclude_default_template: global_hinclude_template diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 8366faf918b5b..99d9fc6ecef9d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -170,6 +170,13 @@ public function testAmbiguousWhenBothTemplatingAndFragments() $this->createContainerFromFile('template_and_fragments'); } + public function testFragmentsAndHinclude() + { + $container = $this->createContainerFromFile('fragments_and_hinclude'); + $this->assertTrue($container->hasParameter('fragment.renderer.hinclude.global_template')); + $this->assertEquals('global_hinclude_template', $container->getParameter('fragment.renderer.hinclude.global_template')); + } + public function testSsi() { $container = $this->createContainerFromFile('full'); From ffbf31d8c63f2b1778d3855f006311da929348e8 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 10 Jan 2020 23:55:24 +0100 Subject: [PATCH 102/124] [SecurityBundle] Drop duplicated code --- .../SecurityBundle/Debug/TraceableListenerTrait.php | 10 ++++++++++ .../SecurityBundle/Debug/WrappedLazyListener.php | 10 ---------- .../Bundle/SecurityBundle/Debug/WrappedListener.php | 10 ---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php index 7b65d86b75d34..b758be6242660 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableListenerTrait.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\SecurityBundle\Debug; use Symfony\Component\Security\Http\Firewall\LegacyListenerTrait; +use Symfony\Component\VarDumper\Caster\ClassStub; /** * @author Robin Chalas @@ -39,4 +40,13 @@ public function getWrappedListener() { return $this->listener; } + + public function getInfo(): array + { + return [ + 'response' => $this->response, + 'time' => $this->time, + 'stub' => $this->stub ?? $this->stub = ClassStub::wrapCallable($this->listener), + ]; + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php index 649a4065efae3..eca63b4d4a2fc 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedLazyListener.php @@ -16,7 +16,6 @@ use Symfony\Component\Security\Core\Exception\LazyResponseException; use Symfony\Component\Security\Http\Firewall\AbstractListener; use Symfony\Component\Security\Http\Firewall\ListenerInterface; -use Symfony\Component\VarDumper\Caster\ClassStub; /** * Wraps a lazy security listener. @@ -60,13 +59,4 @@ public function authenticate(RequestEvent $event) return $ret; } - - public function getInfo(): array - { - return [ - 'response' => $this->response, - 'time' => $this->time, - 'stub' => $this->stub ?? $this->stub = ClassStub::wrapCallable($this->listener), - ]; - } } diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php index e7728f2fae7cd..7f9216497674e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/WrappedListener.php @@ -13,7 +13,6 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Http\Firewall\ListenerInterface; -use Symfony\Component\VarDumper\Caster\ClassStub; /** * Wraps a security listener for calls record. @@ -49,13 +48,4 @@ public function __invoke(RequestEvent $event) $this->time = microtime(true) - $startTime; $this->response = $event->getResponse(); } - - public function getInfo(): array - { - return [ - 'response' => $this->response, - 'time' => $this->time, - 'stub' => $this->stub ?? $this->stub = ClassStub::wrapCallable($this->listener), - ]; - } } From 45461c73bf78431c4f61933a92eee1422351f522 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 13 Jan 2020 09:00:59 +0100 Subject: [PATCH 103/124] fix PHP const mapping keys using the inline notation --- src/Symfony/Component/Yaml/Inline.php | 5 +++++ src/Symfony/Component/Yaml/Tests/InlineTest.php | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index aef68c7b2fa13..73aba3cb8b0dc 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -504,6 +504,11 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = [] $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true); $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true); + if ('!php/const' === $key) { + $key .= self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true); + $key = self::evaluateScalar($key, $flags); + } + if (':' !== $key && false === $i = strpos($mapping, ':', $i)) { break; } diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 3f3b913f7b6f1..54372d69505bc 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -58,6 +58,7 @@ public function getTestsForParsePhpConstants() ['!php/const PHP_INT_MAX', PHP_INT_MAX], ['[!php/const PHP_INT_MAX]', [PHP_INT_MAX]], ['{ foo: !php/const PHP_INT_MAX }', ['foo' => PHP_INT_MAX]], + ['{ !php/const PHP_INT_MAX: foo }', [PHP_INT_MAX => 'foo']], ['!php/const NULL', null], ]; } @@ -93,6 +94,7 @@ public function getTestsForParseLegacyPhpConstants() ['!php/const:PHP_INT_MAX', PHP_INT_MAX], ['[!php/const:PHP_INT_MAX]', [PHP_INT_MAX]], ['{ foo: !php/const:PHP_INT_MAX }', ['foo' => PHP_INT_MAX]], + ['{ !php/const:PHP_INT_MAX: foo }', [PHP_INT_MAX => 'foo']], ['!php/const:NULL', null], ]; } From 4aa953600f028612b08470c93de69f7beb07dec1 Mon Sep 17 00:00:00 2001 From: Armando Date: Mon, 13 Jan 2020 16:59:16 +0100 Subject: [PATCH 104/124] [HttpClient] Fix strict parsing of response status codes --- 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 c747f373a03a5..0452e9e7917eb 100644 --- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php @@ -223,7 +223,7 @@ private static function initialize(self $response): void private static function addResponseHeaders(array $responseHeaders, array &$info, array &$headers, string &$debug = ''): void { foreach ($responseHeaders as $h) { - if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([12345]\d\d) .*#', $h, $m)) { + if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? ([12345]\d\d)(?: |$)#', $h, $m)) { if ($headers) { $debug .= "< \r\n"; $headers = []; From fb48bbc05be5533a930bd31d211287a8f234bf78 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 2 Jan 2020 19:17:31 +0100 Subject: [PATCH 105/124] [PhpUnitBridge][SymfonyTestsListenerTrait] Remove some unneeded code --- .../PhpUnit/Legacy/SymfonyTestsListenerTrait.php | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 4591f67ed51b8..54c15b67ceedf 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -37,7 +37,6 @@ class SymfonyTestsListenerTrait private $gatheredDeprecations = array(); private $previousErrorHandler; private $testsWithWarnings; - private $reportUselessTests; private $error; private $runsInSeparateProcess = false; @@ -198,10 +197,6 @@ public function addSkippedTest($test, \Exception $e, $time) public function startTest($test) { if (-2 < $this->state && ($test instanceof \PHPUnit\Framework\TestCase || $test instanceof TestCase)) { - if (null !== $test->getTestResultObject()) { - $this->reportUselessTests = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything(); - } - // This event is triggered before the test is re-run in isolation if ($this->willBeIsolated($test)) { $this->runsInSeparateProcess = tempnam(sys_get_temp_dir(), 'deprec'); @@ -267,11 +262,6 @@ public function endTest($test, $time) $classGroups = $Test::getGroups($className); $groups = $Test::getGroups($className, $test->getName(false)); - if (null !== $this->reportUselessTests) { - $test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything($this->reportUselessTests); - $this->reportUselessTests = null; - } - if ($errored = null !== $this->error) { $test->getTestResultObject()->addError($test, $this->error, 0); $this->error = null; From f81161df8da765d19421940f3247b31bcfc20a4b Mon Sep 17 00:00:00 2001 From: David Maicher Date: Tue, 14 Jan 2020 12:21:57 +0100 Subject: [PATCH 106/124] [FrameworkBundle] remove messenger cache if not enabled --- .../DependencyInjection/FrameworkExtension.php | 1 + .../Resources/config/schema/symfony-1.0.xsd | 1 + .../Fixtures/php/messenger_disabled.php | 5 +++++ .../Fixtures/xml/messenger_disabled.xml | 11 +++++++++++ .../Fixtures/yml/messenger_disabled.yml | 2 ++ .../DependencyInjection/FrameworkExtensionTest.php | 14 ++++++++++++++ 6 files changed, 34 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_disabled.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_disabled.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_disabled.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index f29c72e95a6e2..41d50c26098ca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -292,6 +292,7 @@ public function load(array $configs, ContainerBuilder $container) $container->removeDefinition('console.command.messenger_failed_messages_retry'); $container->removeDefinition('console.command.messenger_failed_messages_show'); $container->removeDefinition('console.command.messenger_failed_messages_remove'); + $container->removeDefinition('cache.messenger.restart_workers_signal'); } $propertyInfoEnabled = $this->isConfigEnabled($container, $config['property_info']); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 69deb492a2c84..14ed3913b6afb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -414,6 +414,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_disabled.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_disabled.php new file mode 100644 index 0000000000000..e02542d9778c6 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_disabled.php @@ -0,0 +1,5 @@ +loadFromExtension('framework', [ + 'messenger' => false, +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_disabled.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_disabled.xml new file mode 100644 index 0000000000000..6f57398b30d2b --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_disabled.xml @@ -0,0 +1,11 @@ + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_disabled.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_disabled.yml new file mode 100644 index 0000000000000..1b2d2d1a4f475 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_disabled.yml @@ -0,0 +1,2 @@ +framework: + messenger: false diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 45a3c02e76c3c..33751dbf2dfb3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -659,9 +659,23 @@ public function testWebLink() $this->assertTrue($container->hasDefinition('web_link.add_link_header_listener')); } + public function testMessengerServicesRemovedWhenDisabled() + { + $container = $this->createContainerFromFile('messenger_disabled'); + $this->assertFalse($container->hasDefinition('console.command.messenger_consume_messages')); + $this->assertFalse($container->hasDefinition('console.command.messenger_debug')); + $this->assertFalse($container->hasDefinition('console.command.messenger_stop_workers')); + $this->assertFalse($container->hasDefinition('console.command.messenger_setup_transports')); + $this->assertFalse($container->hasDefinition('console.command.messenger_failed_messages_retry')); + $this->assertFalse($container->hasDefinition('console.command.messenger_failed_messages_show')); + $this->assertFalse($container->hasDefinition('console.command.messenger_failed_messages_remove')); + $this->assertFalse($container->hasDefinition('cache.messenger.restart_workers_signal')); + } + public function testMessenger() { $container = $this->createContainerFromFile('messenger'); + $this->assertTrue($container->hasDefinition('console.command.messenger_consume_messages')); $this->assertTrue($container->hasAlias('message_bus')); $this->assertTrue($container->getAlias('message_bus')->isPublic()); $this->assertTrue($container->hasAlias('messenger.default_bus')); From 6f4684f6184ac49b1a320b0cfaf11fd426885126 Mon Sep 17 00:00:00 2001 From: Thiago Cordeiro Date: Mon, 13 Jan 2020 16:57:05 +0100 Subject: [PATCH 107/124] Set booted flag to false when test kernel is unset --- src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php index a8fd09dc10121..c784748901c05 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php @@ -45,6 +45,7 @@ private function doTearDown() { static::ensureKernelShutdown(); static::$kernel = null; + static::$booted = false; } /** From 759e20e6d332d8a79d2608db9ebcb30a325cd019 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 14 Jan 2020 18:54:59 +0100 Subject: [PATCH 108/124] [String] add missing encoding when calling mb_ord() --- .../Component/String/AbstractUnicodeString.php | 12 +++++++++++- src/Symfony/Component/String/CodePointString.php | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/String/AbstractUnicodeString.php b/src/Symfony/Component/String/AbstractUnicodeString.php index 19ad5e8939d95..bc3e05cd6f10c 100644 --- a/src/Symfony/Component/String/AbstractUnicodeString.php +++ b/src/Symfony/Component/String/AbstractUnicodeString.php @@ -172,7 +172,17 @@ public function codePointsAt(int $offset): array { $str = $this->slice($offset, 1); - return '' === $str->string ? [] : array_map('mb_ord', preg_split('//u', $str->string, -1, PREG_SPLIT_NO_EMPTY)); + if ('' === $str->string) { + return []; + } + + $codePoints = []; + + foreach (preg_split('//u', $str->string, -1, PREG_SPLIT_NO_EMPTY) as $c) { + $codePoints[] = mb_ord($c, 'UTF-8'); + } + + return $codePoints; } public function folded(bool $compat = true): parent diff --git a/src/Symfony/Component/String/CodePointString.php b/src/Symfony/Component/String/CodePointString.php index 8a729bb9e1623..d1ac91570181d 100644 --- a/src/Symfony/Component/String/CodePointString.php +++ b/src/Symfony/Component/String/CodePointString.php @@ -79,7 +79,7 @@ public function codePointsAt(int $offset): array { $str = $offset ? $this->slice($offset, 1) : $this; - return '' === $str->string ? [] : [mb_ord($str->string)]; + return '' === $str->string ? [] : [mb_ord($str->string, 'UTF-8')]; } public function endsWith($suffix): bool From 207cdafd546d5f11e7fc425984934e2211a697f1 Mon Sep 17 00:00:00 2001 From: knezmilos13 Date: Tue, 14 Jan 2020 19:27:07 +0100 Subject: [PATCH 109/124] [Validator] Fix plurals for sr_Latn (Serbian language written in latin script) validation messages --- .../translations/validators.sr_Latn.xlf | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 018dd1233ac61..20dff43c6d904 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -24,11 +24,11 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Morate odabrati bar {{ limit }} mogućnost.|Morate odabrati bar {{ limit }} mogućnosti. + Morate odabrati bar {{ limit }} mogućnost.|Morate odabrati bar {{ limit }} mogućnosti.|Morate odabrati bar {{ limit }} mogućnosti. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Morate odabrati najviše {{ limit }} mogućnost.|Morate odabrati najviše {{ limit }} mogućnosti. + Morate odabrati najviše {{ limit }} mogućnost.|Morate odabrati najviše {{ limit }} mogućnosti.|Morate odabrati najviše {{ limit }} mogućnosti. One or more of the given values is invalid. @@ -76,7 +76,7 @@ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Vrednost je predugačka. Trebalo bi da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. + Vrednost je predugačka. Trebalo bi da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. This value should be {{ limit }} or more. @@ -84,7 +84,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Vrednost je prekratka. Trebalo bi da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. + Vrednost je prekratka. Trebalo bi da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. This value should not be blank. @@ -180,7 +180,7 @@ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Vrednost bi trebalo da ima tačno {{ limit }} karakter.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera. + Vrednost bi trebalo da ima tačno {{ limit }} karakter.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera. The file was only partially uploaded. @@ -204,15 +204,15 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata. + Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata. + Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Ova kolekcija bi trebalo da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elemenata. + Ova kolekcija bi trebalo da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elementa.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elemenata. Invalid card number. From a7d0d82768ec0906cec99cc974f9d6d2eef386a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 14 Jan 2020 13:04:40 +0100 Subject: [PATCH 110/124] Fix RememberMe with null password --- .../Http/RememberMe/TokenBasedRememberMeServices.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php index f11e1dc02f041..33427517ca4ee 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php @@ -91,12 +91,12 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt /** * Generates the cookie value. * - * @param int $expires The Unix timestamp when the cookie expires - * @param string $password The encoded password + * @param int $expires The Unix timestamp when the cookie expires + * @param string|null $password The encoded password * * @return string */ - protected function generateCookieValue(string $class, string $username, int $expires, string $password) + protected function generateCookieValue(string $class, string $username, int $expires, ?string $password) { // $username is encoded because it might contain COOKIE_DELIMITER, // we assume other values don't @@ -111,12 +111,12 @@ protected function generateCookieValue(string $class, string $username, int $exp /** * Generates a hash for the cookie to ensure it is not being tampered with. * - * @param int $expires The Unix timestamp when the cookie expires - * @param string $password The encoded password + * @param int $expires The Unix timestamp when the cookie expires + * @param string|null $password The encoded password * * @return string */ - protected function generateCookieHash(string $class, string $username, int $expires, string $password) + protected function generateCookieHash(string $class, string $username, int $expires, ?string $password) { return hash_hmac('sha256', $class.self::COOKIE_DELIMITER.$username.self::COOKIE_DELIMITER.$expires.self::COOKIE_DELIMITER.$password, $this->getSecret()); } From 820eb357c8afaf0d3868f9b778459dc644ff2804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Tue, 14 Jan 2020 22:28:32 +0100 Subject: [PATCH 111/124] Fix RememberMe with null password --- .../RememberMe/TokenBasedRememberMeServices.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php index afa12e4f03d20..3df2ced6223fa 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php @@ -89,10 +89,10 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt /** * Generates the cookie value. * - * @param string $class - * @param string $username The username - * @param int $expires The Unix timestamp when the cookie expires - * @param string $password The encoded password + * @param string $class + * @param string $username The username + * @param int $expires The Unix timestamp when the cookie expires + * @param string|null $password The encoded password * * @return string */ @@ -111,10 +111,10 @@ protected function generateCookieValue($class, $username, $expires, $password) /** * Generates a hash for the cookie to ensure it is not being tampered with. * - * @param string $class - * @param string $username The username - * @param int $expires The Unix timestamp when the cookie expires - * @param string $password The encoded password + * @param string $class + * @param string $username The username + * @param int $expires The Unix timestamp when the cookie expires + * @param string|null $password The encoded password * * @return string */ From 56e79fefa1c31a1e5e4e68dc82ee5eb8c7d493ae Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Wed, 15 Jan 2020 08:29:06 -0500 Subject: [PATCH 112/124] Revert "Fixed translations file dumper behavior" --- .../Translation/Dumper/FileDumper.php | 43 +++++++++---------- .../Tests/Dumper/FileDumperTest.php | 17 +++----- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/Symfony/Component/Translation/Dumper/FileDumper.php b/src/Symfony/Component/Translation/Dumper/FileDumper.php index 477fcfa19ee33..2009c53403f25 100644 --- a/src/Symfony/Component/Translation/Dumper/FileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/FileDumper.php @@ -67,37 +67,36 @@ public function dump(MessageCatalogue $messages, $options = []) throw new InvalidArgumentException('The file dumper needs a path option.'); } - $hasMessageFormatter = class_exists(\MessageFormatter::class); - // save a file for each domain foreach ($messages->getDomains() as $domain) { - if ($hasMessageFormatter) { - $defaultDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX; - $altDomain = $domain; - } else { - $defaultDomain = $domain; - $altDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX; - } - $defaultPath = $options['path'].'/'.$this->getRelativePath($defaultDomain, $messages->getLocale()); - $altPath = $options['path'].'/'.$this->getRelativePath($altDomain, $messages->getLocale()); - - if (!file_exists($defaultPath) && file_exists($altPath)) { - [$defaultPath, $altPath] = [$altPath, $defaultPath]; - } - - if (!file_exists($defaultPath)) { - $directory = \dirname($defaultPath); + $fullpath = $options['path'].'/'.$this->getRelativePath($domain, $messages->getLocale()); + if (!file_exists($fullpath)) { + $directory = \dirname($fullpath); if (!file_exists($directory) && !@mkdir($directory, 0777, true)) { throw new RuntimeException(sprintf('Unable to create directory "%s".', $directory)); } } - if (file_exists($altPath)) { - // clear alternative translation file - file_put_contents($altPath, $this->formatCatalogue(new MessageCatalogue($messages->getLocale()), $altDomain, $options)); + $intlDomain = $domain.MessageCatalogue::INTL_DOMAIN_SUFFIX; + $intlMessages = $messages->all($intlDomain); + + if ($intlMessages) { + $intlPath = $options['path'].'/'.$this->getRelativePath($intlDomain, $messages->getLocale()); + file_put_contents($intlPath, $this->formatCatalogue($messages, $intlDomain, $options)); + + $messages->replace([], $intlDomain); + + try { + if ($messages->all($domain)) { + file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options)); + } + continue; + } finally { + $messages->replace($intlMessages, $intlDomain); + } } - file_put_contents($defaultPath, $this->formatCatalogue($messages, $domain, $options)); + file_put_contents($fullpath, $this->formatCatalogue($messages, $domain, $options)); } } diff --git a/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php b/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php index 9dd1377e49729..6e42b1e5683e5 100644 --- a/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php +++ b/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php @@ -27,15 +27,11 @@ public function testDump() $dumper = new ConcreteFileDumper(); $dumper->dump($catalogue, ['path' => $tempDir]); - $suffix = class_exists(\MessageFormatter::class) ? '+intl-icu' : ''; - $this->assertFileExists($tempDir."/messages$suffix.en.concrete"); + $this->assertFileExists($tempDir.'/messages.en.concrete'); - @unlink($tempDir."/messages$suffix.en.concrete"); + @unlink($tempDir.'/messages.en.concrete'); } - /** - * @requires extension intl - */ public function testDumpIntl() { $tempDir = sys_get_temp_dir(); @@ -46,11 +42,13 @@ public function testDumpIntl() $catalogue->add(['bar' => 'foo'], 'd2+intl-icu'); $dumper = new ConcreteFileDumper(); + @unlink($tempDir.'/d2.en.concrete'); $dumper->dump($catalogue, ['path' => $tempDir]); - $this->assertFileNotExists($tempDir.'/d1.en.concrete'); + $this->assertStringEqualsFile($tempDir.'/d1.en.concrete', 'foo=bar'); + @unlink($tempDir.'/d1.en.concrete'); - $this->assertStringEqualsFile($tempDir.'/d1+intl-icu.en.concrete', 'bar=foo&foo=bar'); + $this->assertStringEqualsFile($tempDir.'/d1+intl-icu.en.concrete', 'bar=foo'); @unlink($tempDir.'/d1+intl-icu.en.concrete'); $this->assertFileNotExists($tempDir.'/d2.en.concrete'); @@ -62,8 +60,7 @@ public function testDumpCreatesNestedDirectoriesAndFile() { $tempDir = sys_get_temp_dir(); $translationsDir = $tempDir.'/test/translations'; - $suffix = class_exists(\MessageFormatter::class) ? '+intl-icu' : ''; - $file = $translationsDir."/messages$suffix.en.concrete"; + $file = $translationsDir.'/messages.en.concrete'; $catalogue = new MessageCatalogue('en'); $catalogue->add(['foo' => 'bar']); From 6b811e6b4c7c43be27b62141e2ee970ada660d69 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 16 Jan 2020 10:18:18 +0100 Subject: [PATCH 113/124] chown and chgrp should also accept int as owner and group --- src/Symfony/Component/Filesystem/Filesystem.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index cd456c7848b3d..7d7301c3a199f 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -211,7 +211,7 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) * Change the owner of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner - * @param string $user The new owner user name + * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * * @throws IOException When the change fails @@ -238,7 +238,7 @@ public function chown($files, $user, $recursive = false) * Change the group of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group - * @param string $group The group name + * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * * @throws IOException When the change fails From 6b4147c9916615acafadd54ab6d909cdc068d3d8 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 16 Jan 2020 15:27:16 +0100 Subject: [PATCH 114/124] [Yaml] Throw on unquoted exclamation mark --- src/Symfony/Component/Yaml/Inline.php | 4 ++ .../Component/Yaml/Tests/InlineTest.php | 65 +++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 0461150092a30..e8ef82122fecc 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -669,6 +669,10 @@ private static function parseTag(string $value, int &$i, int $flags): ?string $nextOffset = $i + $tagLength + 1; $nextOffset += strspn($value, ' ', $nextOffset); + if ('' === $tag && (!isset($value[$nextOffset]) || \in_array($value[$nextOffset], [']', '}', ','], true))) { + throw new ParseException(sprintf('Using the unquoted scalar value "!" is not supported. You must quote it.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename); + } + // Is followed by a scalar and is a built-in tag if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && ('!' === $tag[0] || 'str' === $tag || 'php/const' === $tag || 'php/object' === $tag)) { // Manage in {@link self::evaluateScalar()} diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index a8dfb0877437f..db74da698c1a2 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -736,4 +736,69 @@ public function getTestsForOctalNumbers() 'negative octal number' => [-28, '-034'], ]; } + + /** + * @dataProvider unquotedExclamationMarkThrowsProvider + */ + public function testUnquotedExclamationMarkThrows(string $value) + { + $this->expectException(ParseException::class); + $this->expectExceptionMessageRegExp('/^Using the unquoted scalar value "!" is not supported\. You must quote it at line 1 \(near "/'); + + Inline::parse($value); + } + + public function unquotedExclamationMarkThrowsProvider() + { + return [ + ['!'], + ['! '], + ['! '], + [' ! '], + ['[!]'], + ['[! ]'], + ['[! ]'], + ['[!, "foo"]'], + ['["foo", !, "ccc"]'], + ['{foo: !}'], + ['{foo: !}'], + ['{foo: !, bar: "ccc"}'], + ['{bar: "ccc", foo: ! }'], + ['!]]]'], + ['!}'], + ['!,}foo,]'], + ['! [!]'], + ]; + } + + /** + * @dataProvider quotedExclamationMarkProvider + */ + public function testQuotedExclamationMark($expected, string $value) + { + $this->assertSame($expected, Inline::parse($value)); + } + + // This provider should stay consistent with unquotedExclamationMarkThrowsProvider + public function quotedExclamationMarkProvider() + { + return [ + ['!', '"!"'], + ['! ', '"! "'], + [' !', '" !"'], + [' ! ', '" ! "'], + [['!'], '["!"]'], + [['! '], '["! "]'], + [['!', 'foo'], '["!", "foo"]'], + [['foo', '!', 'ccc'], '["foo", "!", "ccc"]'], + [['foo' => '!'], '{foo: "!"}'], + [['foo' => ' !'], '{foo: " !"}'], + [['foo' => '!', 'bar' => 'ccc'], '{foo: "!", bar: "ccc"}'], + [['bar' => 'ccc', 'foo' => '! '], '{bar: "ccc", foo: "! "}'], + ['!]]]', '"!]]]"'], + ['!}', '"!}"'], + ['!,}foo,]', '"!,}foo,]"'], + [['!'], '! ["!"]'], + ]; + } } From d18f5ed8511dbc75bd9d99ad6cee4c875b5f3195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Sch=C3=A4dlich?= Date: Fri, 17 Jan 2020 18:54:18 +0100 Subject: [PATCH 115/124] [FrameworkBundle] Fix small typo in output comment --- .../Bundle/FrameworkBundle/Command/SecretsListCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php index cc322847d0262..1210b40ee0b6a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsListCommand.php @@ -101,7 +101,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int (new SymfonyStyle($input, $output)) ->table(['Secret', 'Value'] + (null !== $localSecrets ? [2 => 'Local Value'] : []), $rows); - $io->comment("Local values override secret values.\nUse secrets:set --local to defined them."); + $io->comment("Local values override secret values.\nUse secrets:set --local to define them."); return 0; } From 75dbaf0cc55d8ab04bfd6858358e62f941b52c31 Mon Sep 17 00:00:00 2001 From: Dmitry Danilson Date: Sun, 19 Jan 2020 18:13:19 +0700 Subject: [PATCH 116/124] Fix #35385: Fix Console typehint --- src/Symfony/Component/Console/Input/Input.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php index 8c7905db78916..ff5d3170f4e04 100644 --- a/src/Symfony/Component/Console/Input/Input.php +++ b/src/Symfony/Component/Console/Input/Input.php @@ -104,7 +104,7 @@ public function getArguments() /** * {@inheritdoc} */ - public function getArgument($name) + public function getArgument(string $name) { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); @@ -116,7 +116,7 @@ public function getArgument($name) /** * {@inheritdoc} */ - public function setArgument($name, $value) + public function setArgument(string $name, $value) { if (!$this->definition->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist.', $name)); From 9ca872054b1c7391405a13c7ac85c521652f0d37 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Sun, 19 Jan 2020 19:23:22 -0500 Subject: [PATCH 117/124] Fixed #34713 Move new messages to intl domain when possible --- .../Command/TranslationUpdateCommand.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 32ff6cce551de..65b8013450e2d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -23,6 +23,7 @@ use Symfony\Component\Translation\Catalogue\TargetOperation; use Symfony\Component\Translation\Extractor\ExtractorInterface; use Symfony\Component\Translation\MessageCatalogue; +use Symfony\Component\Translation\MessageCatalogueInterface; use Symfony\Component\Translation\Reader\TranslationReaderInterface; use Symfony\Component\Translation\Writer\TranslationWriterInterface; @@ -254,6 +255,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int $resultMessage = 'Translation files were successfully updated'; + // move new messages to intl domain when possible + if (class_exists(\MessageFormatter::class)) { + foreach ($operation->getDomains() as $domain) { + $intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX; + $newMessages = $operation->getNewMessages($domain); + + if ([] === $newMessages || ([] === $currentCatalogue->all($intlDomain) && [] !== $currentCatalogue->all($domain))) { + continue; + } + + $result = $operation->getResult(); + $allIntlMessages = $result->all($intlDomain); + $currentMessages = array_diff_key($newMessages, $result->all($domain)); + $result->replace($currentMessages, $domain); + $result->replace($allIntlMessages + $newMessages, $intlDomain); + } + } + // show compiled list of messages if (true === $input->getOption('dump-messages')) { $extractedMessagesCount = 0; From e119aa6c483d81ca3b749964911e79aab2731977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 15 Jan 2020 23:34:01 +0100 Subject: [PATCH 118/124] [DI] Fix EnvVar not loaded when Loader requires an env var --- .../DependencyInjection/EnvVarProcessor.php | 41 +++++++++++------- .../Tests/EnvVarProcessorTest.php | 42 +++++++++++++++++++ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 724187b1dbfe7..1b8b64cac357f 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -30,8 +30,7 @@ class EnvVarProcessor implements EnvVarProcessorInterface public function __construct(ContainerInterface $container, \Traversable $loaders = null) { $this->container = $container; - $this->loaders = new \IteratorIterator($loaders ?? new \ArrayIterator()); - $this->loaders = $this->loaders->getInnerIterator(); + $this->loaders = $loaders ?? new \ArrayIterator(); } /** @@ -141,20 +140,32 @@ public function getEnv($prefix, $name, \Closure $getEnv) } } - $loaders = $this->loaders; - $this->loaders = new \ArrayIterator(); - - try { - while ((false === $env || null === $env) && $loaders->valid()) { - $loader = $loaders->current(); - $loaders->next(); - $this->loadedVars[] = $vars = $loader->loadEnvVars(); - $env = $vars[$name] ?? false; + if (false === $env || null === $env) { + $loaders = $this->loaders; + $this->loaders = new \ArrayIterator(); + + try { + $i = 0; + $ended = true; + $count = $loaders instanceof \Countable ? $loaders->count() : 0; + foreach ($loaders as $loader) { + if (\count($this->loadedVars) > $i++) { + continue; + } + $this->loadedVars[] = $vars = $loader->loadEnvVars(); + if (false !== $env = $vars[$name] ?? false) { + $ended = false; + break; + } + } + if ($ended || $count === $i) { + $loaders = $this->loaders; + } + } catch (ParameterCircularReferenceException $e) { + // skip loaders that need an env var that is not defined + } finally { + $this->loaders = $loaders; } - } catch (ParameterCircularReferenceException $e) { - // skip loaders that need an env var that is not defined - } finally { - $this->loaders = $loaders; } if (false === $env || null === $env) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index 9970eb474f6be..df329b4f7e316 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -3,10 +3,12 @@ namespace Symfony\Component\DependencyInjection\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\EnvVarLoaderInterface; use Symfony\Component\DependencyInjection\EnvVarProcessor; +use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException; class EnvVarProcessorTest extends TestCase { @@ -553,4 +555,44 @@ public function loadEnvVars(): array $result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {}); $this->assertSame('123', $result); // check twice } + + public function testCircularEnvLoader() + { + $container = new ContainerBuilder(); + $container->setParameter('env(FOO_CONTAINER)', 'foo'); + $container->compile(); + + $index = 0; + $loaders = function () use (&$index) { + if (0 === $index++) { + throw new ParameterCircularReferenceException(['FOO_CONTAINER']); + } + + yield new class() implements EnvVarLoaderInterface { + public function loadEnvVars(): array + { + return [ + 'FOO_ENV_LOADER' => '123', + ]; + } + }; + }; + + $processor = new EnvVarProcessor($container, new RewindableGenerator($loaders, 1)); + + $result = $processor->getEnv('string', 'FOO_CONTAINER', function () {}); + $this->assertSame('foo', $result); + + $result = $processor->getEnv('string', 'FOO_ENV_LOADER', function () {}); + $this->assertSame('123', $result); + + $result = $processor->getEnv('default', ':BAR_CONTAINER', function ($name) use ($processor) { + $this->assertSame('BAR_CONTAINER', $name); + + return $processor->getEnv('string', $name, function () {}); + }); + $this->assertNull($result); + + $this->assertSame(2, $index); + } } From eba5a0c3904b7530340bbaee359d4fc1e0629a95 Mon Sep 17 00:00:00 2001 From: Filippo Tessarotto Date: Thu, 16 Jan 2020 09:55:51 +0100 Subject: [PATCH 119/124] [Filesystem] chown and chgrp should also accept int as owner and group --- .../Component/Filesystem/Filesystem.php | 6 +- .../Filesystem/Tests/FilesystemTest.php | 66 +++++++++++++++++-- .../Filesystem/Tests/FilesystemTestCase.php | 21 +++++- 3 files changed, 84 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 76c10b015bccd..462949cde7648 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -207,10 +207,11 @@ public function chmod($files, int $mode, int $umask = 0000, bool $recursive = fa * Change the owner of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner + * @param string|int $user A user name or number * * @throws IOException When the change fails */ - public function chown($files, string $user, bool $recursive = false) + public function chown($files, $user, bool $recursive = false) { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { @@ -232,10 +233,11 @@ public function chown($files, string $user, bool $recursive = false) * Change the group of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group + * @param string|int $group A group name or number * * @throws IOException When the change fails */ - public function chgrp($files, string $group, bool $recursive = false) + public function chgrp($files, $group, bool $recursive = false) { foreach ($this->toIterable($files) as $file) { if ($recursive && is_dir($file) && !is_link($file)) { diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index d4299da4d93f3..dcd3c6140693e 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -521,7 +521,7 @@ public function testChmodChangesZeroModeOnSubdirectoriesOnRecursive() $this->assertFilePermissions(753, $subdirectory); } - public function testChown() + public function testChownByName() { $this->markAsSkippedIfPosixIsMissing(); @@ -534,7 +534,20 @@ public function testChown() $this->assertSame($owner, $this->getFileOwner($dir)); } - public function testChownRecursive() + public function testChownById() + { + $this->markAsSkippedIfPosixIsMissing(); + + $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; + mkdir($dir); + + $ownerId = $this->getFileOwnerId($dir); + $this->filesystem->chown($dir, $ownerId); + + $this->assertSame($ownerId, $this->getFileOwnerId($dir)); + } + + public function testChownRecursiveByName() { $this->markAsSkippedIfPosixIsMissing(); @@ -549,6 +562,21 @@ public function testChownRecursive() $this->assertSame($owner, $this->getFileOwner($file)); } + public function testChownRecursiveById() + { + $this->markAsSkippedIfPosixIsMissing(); + + $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; + mkdir($dir); + $file = $dir.\DIRECTORY_SEPARATOR.'file'; + touch($file); + + $ownerId = $this->getFileOwnerId($dir); + $this->filesystem->chown($dir, $ownerId, true); + + $this->assertSame($ownerId, $this->getFileOwnerId($file)); + } + public function testChownSymlink() { $this->markAsSkippedIfSymlinkIsMissing(); @@ -624,7 +652,7 @@ public function testChownFail() $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999)); } - public function testChgrp() + public function testChgrpByName() { $this->markAsSkippedIfPosixIsMissing(); @@ -637,6 +665,19 @@ public function testChgrp() $this->assertSame($group, $this->getFileGroup($dir)); } + public function testChgrpById() + { + $this->markAsSkippedIfPosixIsMissing(); + + $dir = $this->workspace.\DIRECTORY_SEPARATOR.'dir'; + mkdir($dir); + + $groupId = $this->getFileGroupId($dir); + $this->filesystem->chgrp($dir, $groupId); + + $this->assertSame($groupId, $this->getFileGroupId($dir)); + } + public function testChgrpRecursive() { $this->markAsSkippedIfPosixIsMissing(); @@ -652,7 +693,7 @@ public function testChgrpRecursive() $this->assertSame($group, $this->getFileGroup($file)); } - public function testChgrpSymlink() + public function testChgrpSymlinkByName() { $this->markAsSkippedIfSymlinkIsMissing(); @@ -669,6 +710,23 @@ public function testChgrpSymlink() $this->assertSame($group, $this->getFileGroup($link)); } + public function testChgrpSymlinkById() + { + $this->markAsSkippedIfSymlinkIsMissing(); + + $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; + $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; + + touch($file); + + $this->filesystem->symlink($file, $link); + + $groupId = $this->getFileGroupId($link); + $this->filesystem->chgrp($link, $groupId); + + $this->assertSame($groupId, $this->getFileGroupId($link)); + } + public function testChgrpLink() { $this->markAsSkippedIfLinkIsMissing(); diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php index 08afefbb24eff..396a3ab2e8634 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTestCase.php @@ -105,21 +105,36 @@ protected function assertFilePermissions($expectedFilePerms, $filePath) ); } + protected function getFileOwnerId($filepath) + { + $this->markAsSkippedIfPosixIsMissing(); + + $infos = stat($filepath); + + return $infos['uid']; + } + protected function getFileOwner($filepath) { $this->markAsSkippedIfPosixIsMissing(); + return ($datas = posix_getpwuid($this->getFileOwnerId($filepath))) ? $datas['name'] : null; + } + + protected function getFileGroupId($filepath) + { + $this->markAsSkippedIfPosixIsMissing(); + $infos = stat($filepath); - return ($datas = posix_getpwuid($infos['uid'])) ? $datas['name'] : null; + return $infos['gid']; } protected function getFileGroup($filepath) { $this->markAsSkippedIfPosixIsMissing(); - $infos = stat($filepath); - if ($datas = posix_getgrgid($infos['gid'])) { + if ($datas = posix_getgrgid($this->getFileGroupId($filepath))) { return $datas['name']; } From c80a7ad042ee3093fe2bb3446b755eac2e6e25cb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 Jan 2020 11:03:13 +0100 Subject: [PATCH 120/124] [HttpKernel] restore compat with clock mocking --- .../EventListener/DisallowRobotsIndexingListenerTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php index 53b317b7611ce..6534ebf4e2122 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/DisallowRobotsIndexingListenerTest.php @@ -24,8 +24,9 @@ class DisallowRobotsIndexingListenerTest extends TestCase /** * @dataProvider provideResponses */ - public function testInvoke(?string $expected, Response $response): void + public function testInvoke(?string $expected, array $responseArgs) { + $response = new Response(...$responseArgs); $listener = new DisallowRobotsIndexingListener(); $event = new ResponseEvent($this->createMock(HttpKernelInterface::class), $this->createMock(Request::class), KernelInterface::MASTER_REQUEST, $response); @@ -37,11 +38,11 @@ public function testInvoke(?string $expected, Response $response): void public function provideResponses(): iterable { - yield 'No header' => ['noindex', new Response()]; + yield 'No header' => ['noindex', []]; yield 'Header already set' => [ 'something else', - new Response('', 204, ['X-Robots-Tag' => 'something else']), + ['', 204, ['X-Robots-Tag' => 'something else']], ]; } } From 5714eaa0de711089edfc3458425cac8425c8ddb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFck=20Piera?= Date: Tue, 21 Jan 2020 09:22:22 +0100 Subject: [PATCH 121/124] Add link to messenger documentation in its README --- src/Symfony/Component/Messenger/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Messenger/README.md b/src/Symfony/Component/Messenger/README.md index 245224f5c9e7a..972d13b473f9a 100644 --- a/src/Symfony/Component/Messenger/README.md +++ b/src/Symfony/Component/Messenger/README.md @@ -12,6 +12,7 @@ are not covered by Symfony's Resources --------- + * [Documentation](https://symfony.com/doc/current/components/messenger.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) From 5521d3d45864a38fbd9781ee1b04d9352916044a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 21 Jan 2020 12:47:55 +0100 Subject: [PATCH 122/124] [SecurityBundle] fix tests --- .../Security/Core/User/ArrayUserProvider.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php index 7bb631b82aae0..5b50def554a5d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/SecuredPageBundle/Security/Core/User/ArrayUserProvider.php @@ -2,8 +2,10 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\SecuredPageBundle\Security\Core\User; +use Symfony\Bundle\SecurityBundle\Tests\Functional\UserWithoutEquatable; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\User\User; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; @@ -52,6 +54,6 @@ public function refreshUser(UserInterface $user) public function supportsClass($class) { - return 'Symfony\Component\Security\Core\User\User' === $class; + return User::class === $class || UserWithoutEquatable::class === $class; } } From 053cea50e08e8a4b7745c0ce6380b87ddeca0be0 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 21 Jan 2020 14:29:49 +0100 Subject: [PATCH 123/124] updated CHANGELOG for 5.0.3 --- CHANGELOG-5.0.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/CHANGELOG-5.0.md b/CHANGELOG-5.0.md index 438bdece7ac9d..a7af44177f3c7 100644 --- a/CHANGELOG-5.0.md +++ b/CHANGELOG-5.0.md @@ -7,6 +7,70 @@ in 5.0 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.0.0...v5.0.1 +* 5.0.3 (2020-01-21) + + * bug #35364 [Yaml] Throw on unquoted exclamation mark (fancyweb) + * bug #35065 [Security] Use supportsClass in addition to UnsupportedUserException (linaori) + * bug #35351 Revert #34797 "Fixed translations file dumper behavior" and fix #34713 (yceruto) + * bug #35356 [Filesystem] chown and chgrp should also accept int as owner and group (Slamdunk) + * bug #35335 [Security] Fix RememberMe with null password (jderusse) + * bug #35339 [String] add missing encoding when calling mb_ord() (nicolas-grekas) + * bug #35355 [DI] Fix EnvVar not loaded when Loader requires an env var (jderusse) + * bug #35343 [Security] Fix RememberMe with null password (jderusse) + * bug #34223 [DI] Suggest typed argument when binding fails with untyped argument (gudfar) + * bug #35323 [FrameworkBundle] Set booted flag to false when test kernel is unset (thiagocordeiro) + * bug #35324 [HttpClient] Fix strict parsing of response status codes (Armando-Walmeric) + * bug #35318 [Yaml] fix PHP const mapping keys using the inline notation (xabbuh) + * bug #35306 [FrameworkBundle] Make sure one can use fragments.hinclude_default_template (Nyholm) + * bug #35304 [HttpKernel] Fix that no-cache MUST revalidate with the origin (mpdude) + * bug #35299 Avoid `stale-if-error` in FrameworkBundle's HttpCache if kernel.debug = true (mpdude) + * bug #35240 [SecurityBundle] Fix collecting traceable listeners info on lazy firewalls (chalasr) + * bug #35151 [DI] deferred exceptions in ResolveParameterPlaceHoldersPass (Islam93) + * bug #35290 [Filesystem][FilesystemCommonTrait] Use a dedicated directory when there are no namespace (fancyweb) + * bug #35099 [FrameworkBundle] Do not throw exception on value generate key (jderusse) + * bug #35278 [EventDispatcher] expand listener in place (xabbuh) + * bug #35269 [HttpKernel][FileLocator] Fix deprecation message (fancyweb) + * bug #35254 [PHPUnit-Bridge] Fail-fast in simple-phpunit if one of the passthru() commands fails (mpdude) + * bug #35261 [Routing] Fix using a custom matcher & generator dumper class (fancyweb) + * bug #34643 [Dotenv] Fixed infinite loop with missing quote followed by quoted value (naitsirch) + * bug #35239 [Security\Http] Prevent canceled remember-me cookie from being accepted (chalasr) + * bug #35267 [Debug] fix ClassNotFoundFatalErrorHandler (nicolas-grekas) + * bug #35252 [Serializer] Fix cache in MetadataAwareNameConverter (bastnic) + * bug #35200 [TwigBridge] do not render preferred choices as selected (xabbuh) + * bug #35243 [HttpKernel] release lock explicitly (nicolas-grekas) + * bug #35193 [TwigBridge] button_widget now has its title attr translated even if its label = null or false (stephen-lewis) + * bug #35219 [PhpUnitBridge] When using phpenv + phpenv-composer plugin, composer executable is wrapped into a bash script (oleg-andreyev) + * bug #35150 [Messenger] Added check if json_encode succeeded (toooni) + * bug #35137 [Messenger] Added check if json_encode succeeded (toooni) + * bug #35170 [FrameworkBundle][TranslationUpdateCommand] Do not output positive feedback on stderr (fancyweb) + * bug #35245 [HttpClient] fix exception in case of PSR17 discovery failure (nicolas-grekas) + * bug #35244 [Cache] fix processing chain adapter based cache pool (xabbuh) + * bug #35247 [FrameworkBundle][ContainerLintCommand] Only skip .errored. services (fancyweb) + * bug #35225 [DependencyInjection] Handle ServiceClosureArgument for callable in container linting (shieldo) + * bug #35223 [HttpClient] Don't read from the network faster than the CPU can deal with (nicolas-grekas) + * bug #35214 [DI] DecoratorServicePass should keep container.service_locator on the decorated definition (malarzm) + * bug #35209 [HttpClient] fix support for non-blocking resource streams (nicolas-grekas) + * bug #35210 [HttpClient] NativeHttpClient should not send >1.1 protocol version (nicolas-grekas) + * bug #35162 [Mailer] Make sure you can pass custom headers to Mailgun (Nyholm) + * bug #33672 [Mailer] Remove line breaks in email attachment content (Stuart Fyfe) + * bug #35101 [Routing] Fix i18n routing when the url contains the locale (fancyweb) + * bug #35124 [TwigBridge][Form] Added missing help messages in form themes (cmen) + * bug #35195 [HttpClient] fix casting responses to PHP streams (nicolas-grekas) + * bug #35168 [HttpClient] fix capturing SSL certificates with NativeHttpClient (nicolas-grekas) + * bug #35134 [PropertyInfo] Fix BC issue in phpDoc Reflection library (jaapio) + * bug #35184 [Mailer] Payload sent to Sendgrid doesn't include names (versgui) + * bug #35173 [Mailer][MailchimpBridge] Fix missing attachments when sending via Mandrill API (vilius-g) + * bug #35172 [Mailer][MailchimpBridge] Fix incorrect sender address when sender has name (vilius-g) + * bug #35125 [Translator] fix performance issue in MessageCatalogue and catalogue operations (ArtemBrovko) + * bug #35120 [HttpClient] fix scheduling pending NativeResponse (nicolas-grekas) + * bug #35117 [Cache] do not overwrite variable value (xabbuh) + * bug #35113 [VarDumper] Fix "Undefined index: argv" when using CliContextProvider (xepozz) + * bug #34673 Migrate server:log command away from WebServerBundle (jderusse) + * bug #35103 [Translation] Use `locale_parse` for computing fallback locales (alanpoulain) + * bug #35060 [Security] Fix missing defaults for auto-migrating encoders (chalasr) + * bug #35067 [DependencyInjection][CheckTypeDeclarationsPass] Handle \Closure for callable (fancyweb) + * bug #35094 [Console] Fix filtering out identical alternatives when there is a command loader (fancyweb) + * 5.0.2 (2019-12-19) * bug #35051 [DependencyInjection] Fix binding tagged services to containers (nicolas-grekas) From f8c7fe871c1e55bf0f69b7bca8a09ad65aef6266 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 21 Jan 2020 14:29:58 +0100 Subject: [PATCH 124/124] updated VERSION for 5.0.3 --- 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 ff23192a54171..944c69ca884f2 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -68,12 +68,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - const VERSION = '5.0.3-DEV'; + const VERSION = '5.0.3'; const VERSION_ID = 50003; const MAJOR_VERSION = 5; const MINOR_VERSION = 0; const RELEASE_VERSION = 3; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2020'; const END_OF_LIFE = '07/2020';