From bc383215a38798f2de140df7f6685cb54f2c6097 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Mon, 7 Jun 2021 18:31:40 +0200 Subject: [PATCH 01/83] [MonologBridge] Fix the server:log help --filter sample --- src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php | 5 ++--- .../Bundle/WebServerBundle/Command/ServerLogCommand.php | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php b/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php index f2ad907d76978..977be786e5b71 100644 --- a/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php +++ b/src/Symfony/Bridge/Monolog/Command/ServerLogCommand.php @@ -67,10 +67,9 @@ protected function configure() php %command.full_name% -To get the information as a machine readable format, use the ---filter option: +To filter the log messages using any ExpressionLanguage compatible expression, use the --filter option: -php %command.full_name% --filter=port +php %command.full_name% --filter="level > 200 or channel in ['app', 'doctrine']" EOF ) ; diff --git a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php index b21368a4f99df..586f0747f30ac 100644 --- a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php +++ b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php @@ -69,10 +69,9 @@ protected function configure() php %command.full_name% -To get the information as a machine readable format, use the ---filter option: +To filter the log messages using any ExpressionLanguage compatible expression, use the --filter option: -php %command.full_name% --filter=port +php %command.full_name% --filter="level > 200 or channel in ['app', 'doctrine']" EOF ) ; From 608a3e596a2d576fac1014825319f8c12058eaee Mon Sep 17 00:00:00 2001 From: David Maicher Date: Thu, 10 Jun 2021 15:25:38 +0200 Subject: [PATCH 02/83] [Mailer] fix encoding of addresses using SmtpTransport --- .../Transport/Smtp/SmtpTransportTest.php | 19 +++++++++++++++++++ .../Mailer/Transport/Smtp/SmtpTransport.php | 4 ++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php index 72130dcee4037..956d3e269ef46 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php @@ -114,6 +114,25 @@ public function testSendInvalidMessage() $this->assertNotContains("\r\n.\r\n", $stream->getCommands()); $this->assertTrue($stream->isClosed()); } + + public function testWriteEncodedRecipientAndSenderAddresses() + { + $stream = new DummyStream(); + + $transport = new SmtpTransport($stream); + + $message = new Email(); + $message->from('sender@exämple.org'); + $message->addTo('recipient@exämple.org'); + $message->addTo('recipient2@example.org'); + $message->text('.'); + + $transport->send($message); + + $this->assertContains("MAIL FROM:\r\n", $stream->getCommands()); + $this->assertContains("RCPT TO:\r\n", $stream->getCommands()); + $this->assertContains("RCPT TO:\r\n", $stream->getCommands()); + } } class DummyStream extends AbstractStream diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index 2e1448f39a896..ac81d81a12e27 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -194,9 +194,9 @@ protected function doSend(SentMessage $message): void try { $envelope = $message->getEnvelope(); - $this->doMailFromCommand($envelope->getSender()->getAddress()); + $this->doMailFromCommand($envelope->getSender()->getEncodedAddress()); foreach ($envelope->getRecipients() as $recipient) { - $this->doRcptToCommand($recipient->getAddress()); + $this->doRcptToCommand($recipient->getEncodedAddress()); } $this->executeCommand("DATA\r\n", [354]); From f2b0822401952362b9029a603b392ecc2461863f Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Mon, 14 Jun 2021 16:11:26 +0200 Subject: [PATCH 03/83] [VarDumper] Fix tests for PHP 8.1 --- .../Tests/Caster/ReflectionCasterTest.php | 78 +++++++++++++++++-- 1 file changed, 72 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index 3f5497573afed..f9a8bd94400d7 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -122,8 +122,9 @@ public function testReflectionParameter() { $var = new \ReflectionParameter(reflectionParameterFixture::class, 0); - $this->assertDumpMatchesFormat( - <<<'EOTXT' + if (\PHP_VERSION_ID < 80100) { + $this->assertDumpMatchesFormat( + <<<'EOTXT' ReflectionParameter { +name: "arg1" position: 0 @@ -131,8 +132,21 @@ public function testReflectionParameter() default: null } EOTXT - , $var - ); + , $var + ); + } else { + $this->assertDumpMatchesFormat( + <<<'EOTXT' +ReflectionParameter { + +name: "arg1" + position: 0 + allowsNull: true + typeHint: "Symfony\Component\VarDumper\Tests\Fixtures\NotLoadableClass" +} +EOTXT + , $var + ); + } } public function testReflectionParameterScalar() @@ -406,7 +420,8 @@ public function testGenerator() $generator = new GeneratorDemo(); $generator = $generator->baz(); - $expectedDump = <<<'EODUMP' + if (\PHP_VERSION_ID < 80100) { + $expectedDump = <<<'EODUMP' Generator { this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} executing: { @@ -420,6 +435,23 @@ public function testGenerator() closed: false } EODUMP; + } else { + $expectedDump = <<<'EODUMP' +Generator { + this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} + trace: { + ./src/Symfony/Component/VarDumper/Tests/Fixtures/GeneratorDemo.php:13 { + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() + › public function baz() + › { + › yield from bar(); + } + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {} + } + closed: false +} +EODUMP; + } $this->assertDumpMatchesFormat($expectedDump, $generator); @@ -427,7 +459,8 @@ public function testGenerator() break; } - $expectedDump = <<<'EODUMP' + if (\PHP_VERSION_ID < 80100) { + $expectedDump = <<<'EODUMP' array:2 [ 0 => ReflectionGenerator { this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} @@ -456,6 +489,39 @@ public function testGenerator() } ] EODUMP; + } else { + $expectedDump = <<<'EODUMP' +array:2 [ + 0 => ReflectionGenerator { + this: Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo { …} + trace: { + %s%eTests%eFixtures%eGeneratorDemo.php:9 { + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() + › { + › yield 1; + › } + } + %s%eTests%eFixtures%eGeneratorDemo.php:20 { …} + %s%eTests%eFixtures%eGeneratorDemo.php:14 { …} + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo->baz() {} + } + closed: false + } + 1 => Generator { + trace: { + ./src/Symfony/Component/VarDumper/Tests/Fixtures/GeneratorDemo.php:9 { + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() + › { + › yield 1; + › } + } + Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo() {} + } + closed: false + } +] +EODUMP; + } $r = new \ReflectionGenerator($generator); $this->assertDumpMatchesFormat($expectedDump, [$r, $r->getExecutingGenerator()]); From 473f79c18a192f11fe6155a1d9176856a1c6e4ff Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 17 Jun 2021 16:21:12 +0200 Subject: [PATCH 04/83] Bump Symfony version to 5.3.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 1793992a9f451..5aaee87e04978 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,12 +75,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '5.3.2'; - public const VERSION_ID = 50302; + public const VERSION = '5.3.3-DEV'; + public const VERSION_ID = 50303; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 3; - public const RELEASE_VERSION = 2; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 3; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2022'; public const END_OF_LIFE = '01/2022'; From bdbf408aab1ecea2052206f6914c66fcc91a0e8f Mon Sep 17 00:00:00 2001 From: Ash014 <39002832+Ash014@users.noreply.github.com> Date: Thu, 17 Jun 2021 22:24:56 +0200 Subject: [PATCH 05/83] [Runtime] Fix project dir variable when vendor not in project root --- src/Symfony/Component/Runtime/Internal/ComposerPlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php b/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php index fc6e5a0c99166..77c48b3f0b380 100644 --- a/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php +++ b/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php @@ -93,7 +93,7 @@ public function updateAutoloadFile(): void if (!$nestingLevel) { $projectDir = '__'.'DIR__.'.var_export('/'.$projectDir, true); } else { - $projectDir = 'dirname(__'."DIR__, $nestingLevel)".('' !== $projectDir ? var_export('/'.$projectDir, true) : ''); + $projectDir = 'dirname(__'."DIR__, $nestingLevel)".('' !== $projectDir ? '.'.var_export('/'.$projectDir, true) : ''); } $runtimeClass = $extra['class'] ?? SymfonyRuntime::class; From 148750e38ffad65a404c2ac9d5597f3bbaa3e7ef Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 18 Jun 2021 09:55:37 +0200 Subject: [PATCH 06/83] make the getter usable if no user identifier is set --- .../Core/Exception/UserNotFoundException.php | 2 +- .../Exception/UserNotFoundExceptionTest.php | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Exception/UserNotFoundException.php b/src/Symfony/Component/Security/Core/Exception/UserNotFoundException.php index 685b079ef17e8..4f8b7ef77b192 100644 --- a/src/Symfony/Component/Security/Core/Exception/UserNotFoundException.php +++ b/src/Symfony/Component/Security/Core/Exception/UserNotFoundException.php @@ -32,7 +32,7 @@ public function getMessageKey() /** * Get the user identifier (e.g. username or e-mailaddress). */ - public function getUserIdentifier(): string + public function getUserIdentifier(): ?string { return $this->identifier; } diff --git a/src/Symfony/Component/Security/Core/Tests/Exception/UserNotFoundExceptionTest.php b/src/Symfony/Component/Security/Core/Tests/Exception/UserNotFoundExceptionTest.php index 559e62acd97d0..3d9de8f14a2ef 100644 --- a/src/Symfony/Component/Security/Core/Tests/Exception/UserNotFoundExceptionTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Exception/UserNotFoundExceptionTest.php @@ -12,8 +12,8 @@ namespace Symfony\Component\Security\Core\Tests\Exception; use PHPUnit\Framework\TestCase; -use Symfony\Component\Security\Core\Exception\UserNotFoundException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\Exception\UserNotFoundException; class UserNotFoundExceptionTest extends TestCase { @@ -25,6 +25,23 @@ public function testGetMessageData() $this->assertEquals(['{{ username }}' => 'username', '{{ user_identifier }}' => 'username'], $exception->getMessageData()); } + public function testUserIdentifierIsNotSetByDefault() + { + $exception = new UserNotFoundException(); + + $this->assertNull($exception->getUserIdentifier()); + } + + /** + * @group legacy + */ + public function testUsernameIsNotSetByDefault() + { + $exception = new UserNotFoundException(); + + $this->assertNull($exception->getUsername()); + } + /** * @group legacy */ From f3b11e70c0b0c3217bb91d3fa9b417256783ca4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Fri, 18 Jun 2021 10:01:04 +0200 Subject: [PATCH 07/83] [Security] Fix value lost in RememberMe update --- .../Http/RememberMe/PersistentRememberMeHandler.php | 2 +- .../RememberMe/PersistentRememberMeHandlerTest.php | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php index 2be8cbc0becff..f60bd9d6b9141 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php @@ -98,7 +98,7 @@ public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInte $this->tokenProvider->updateToken($series, $tokenValueHash, $tokenLastUsed); } - $this->createCookie($rememberMeDetails->withValue($tokenValue)); + $this->createCookie($rememberMeDetails->withValue($series.':'.$tokenValue)); } /** diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php index 44779829c613f..00ce37b8dac6e 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php @@ -92,8 +92,14 @@ public function testConsumeRememberMeCookieValid() /** @var Cookie $cookie */ $cookie = $this->request->attributes->get(ResponseListener::COOKIE_ATTR_NAME); - $this->assertNotEquals($rememberMeDetails->toString(), $cookie->getValue()); - $this->assertMatchesRegularExpression('{'.str_replace('\\', '\\\\', base64_decode($rememberMeDetails->withValue('[a-zA-Z0-9/+]+')->toString())).'}', base64_decode($cookie->getValue())); + $rememberParts = explode(':', base64_decode($rememberMeDetails->toString()), 4); + $cookieParts = explode(':', base64_decode($cookie->getValue()), 4); + + $this->assertSame($rememberParts[0], $cookieParts[0]); // class + $this->assertSame($rememberParts[1], $cookieParts[1]); // identifier + $this->assertSame($rememberParts[2], $cookieParts[2]); // expire + $this->assertNotSame($rememberParts[3], $cookieParts[3]); // value + $this->assertSame(explode(':', $rememberParts[3])[0], explode(':', $cookieParts[3])[0]); // series } public function testConsumeRememberMeCookieInvalidToken() From f8a082daebdd4e02e74eba0861dc6e160cdfc18c Mon Sep 17 00:00:00 2001 From: "simon.chrzanowski" Date: Fri, 18 Jun 2021 10:57:27 +0200 Subject: [PATCH 08/83] [HttpFoundation] allow savePath of NativeFileSessionHandler to be null --- .../Storage/Handler/SessionHandlerFactory.php | 4 +- .../Handler/SessionHandlerFactoryTest.php | 48 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/SessionHandlerFactoryTest.php diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/SessionHandlerFactory.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/SessionHandlerFactory.php index a5ebd29ebaa73..33453c320840f 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/SessionHandlerFactory.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/SessionHandlerFactory.php @@ -48,7 +48,9 @@ public static function createHandler($connection): AbstractSessionHandler case !\is_string($connection): throw new \InvalidArgumentException(sprintf('Unsupported Connection: "%s".', \get_class($connection))); case 0 === strpos($connection, 'file://'): - return new StrictSessionHandler(new NativeFileSessionHandler(substr($connection, 7))); + $savePath = substr($connection, 7); + + return new StrictSessionHandler(new NativeFileSessionHandler('' === $savePath ? null : $savePath)); case 0 === strpos($connection, 'redis:'): case 0 === strpos($connection, 'rediss:'): diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/SessionHandlerFactoryTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/SessionHandlerFactoryTest.php new file mode 100644 index 0000000000000..46d6cd40151d5 --- /dev/null +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/SessionHandlerFactoryTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\SessionHandlerFactory; +use Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler; + +/** + * Test class for SessionHandlerFactory. + * + * @author Simon + * + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + */ +class SessionHandlerFactoryTest extends TestCase +{ + /** + * @dataProvider provideConnectionDSN + */ + public function testCreateHandler(string $connectionDSN, string $expectedPath, string $expectedHandlerType) + { + $handler = SessionHandlerFactory::createHandler($connectionDSN); + + $this->assertInstanceOf($expectedHandlerType, $handler); + $this->assertEquals($expectedPath, ini_get('session.save_path')); + } + + public function provideConnectionDSN(): array + { + $base = sys_get_temp_dir(); + + return [ + 'native file handler using save_path from php.ini' => ['connectionDSN' => 'file://', 'expectedPath' => ini_get('session.save_path'), 'expectedHandlerType' => StrictSessionHandler::class], + 'native file handler using provided save_path' => ['connectionDSN' => 'file://'.$base.'/session/storage', 'expectedPath' => $base.'/session/storage', 'expectedHandlerType' => StrictSessionHandler::class], + ]; + } +} From fc9e9ff7a11c1b557a1d4aadf50dcf4f4de833b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Fri, 18 Jun 2021 08:45:09 +0200 Subject: [PATCH 09/83] Fix special char used to create cache key --- .../Authentication/RememberMe/CacheTokenVerifier.php | 12 +++++++++--- .../RememberMe/CacheTokenVerifierTest.php | 8 ++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Authentication/RememberMe/CacheTokenVerifier.php b/src/Symfony/Component/Security/Core/Authentication/RememberMe/CacheTokenVerifier.php index 1f4241e6a7712..2b96eff06287a 100644 --- a/src/Symfony/Component/Security/Core/Authentication/RememberMe/CacheTokenVerifier.php +++ b/src/Symfony/Component/Security/Core/Authentication/RememberMe/CacheTokenVerifier.php @@ -43,11 +43,12 @@ public function verifyToken(PersistentTokenInterface $token, string $tokenValue) return true; } - if (!$this->cache->hasItem($this->cacheKeyPrefix.$token->getSeries())) { + $cacheKey = $this->getCacheKey($token); + if (!$this->cache->hasItem($cacheKey)) { return false; } - $item = $this->cache->getItem($this->cacheKeyPrefix.$token->getSeries()); + $item = $this->cache->getItem($cacheKey); $outdatedToken = $item->get(); return hash_equals($outdatedToken, $tokenValue); @@ -60,9 +61,14 @@ public function updateExistingToken(PersistentTokenInterface $token, string $tok { // When a token gets updated, persist the outdated token for $outdatedTokenTtl seconds so we can // still accept it as valid in verifyToken - $item = $this->cache->getItem($this->cacheKeyPrefix.$token->getSeries()); + $item = $this->cache->getItem($this->getCacheKey($token)); $item->set($token->getTokenValue()); $item->expiresAfter($this->outdatedTokenTtl); $this->cache->save($item); } + + private function getCacheKey(PersistentTokenInterface $token): string + { + return $this->cacheKeyPrefix.rawurlencode($token->getSeries()); + } } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/RememberMe/CacheTokenVerifierTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/RememberMe/CacheTokenVerifierTest.php index 709ad2834a9cc..996a42e4a6abf 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/RememberMe/CacheTokenVerifierTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/RememberMe/CacheTokenVerifierTest.php @@ -21,22 +21,22 @@ class CacheTokenVerifierTest extends TestCase public function testVerifyCurrentToken() { $verifier = new CacheTokenVerifier(new ArrayAdapter()); - $token = new PersistentToken('class', 'user', 'series1', 'value', new \DateTime()); + $token = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTime()); $this->assertTrue($verifier->verifyToken($token, 'value')); } public function testVerifyFailsInvalidToken() { $verifier = new CacheTokenVerifier(new ArrayAdapter()); - $token = new PersistentToken('class', 'user', 'series1', 'value', new \DateTime()); + $token = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTime()); $this->assertFalse($verifier->verifyToken($token, 'wrong-value')); } public function testVerifyOutdatedToken() { $verifier = new CacheTokenVerifier(new ArrayAdapter()); - $outdatedToken = new PersistentToken('class', 'user', 'series1', 'value', new \DateTime()); - $newToken = new PersistentToken('class', 'user', 'series1', 'newvalue', new \DateTime()); + $outdatedToken = new PersistentToken('class', 'user', 'series1@special:chars=/', 'value', new \DateTime()); + $newToken = new PersistentToken('class', 'user', 'series1@special:chars=/', 'newvalue', new \DateTime()); $verifier->updateExistingToken($outdatedToken, 'newvalue', new \DateTime()); $this->assertTrue($verifier->verifyToken($newToken, 'value')); } From aa68e2cd314a0f69b462c9b0217c8b2ef6bcce0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Fri, 18 Jun 2021 12:01:08 +0200 Subject: [PATCH 10/83] [Security] Fix invalid cookie when migrating to new Security --- .../Security/Http/RememberMe/RememberMeDetails.php | 3 +++ .../Tests/Authenticator/RememberMeAuthenticatorTest.php | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/Symfony/Component/Security/Http/RememberMe/RememberMeDetails.php b/src/Symfony/Component/Security/Http/RememberMe/RememberMeDetails.php index 2e1e202808c4b..ba9b118a34af7 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/RememberMeDetails.php +++ b/src/Symfony/Component/Security/Http/RememberMe/RememberMeDetails.php @@ -40,6 +40,9 @@ public static function fromRawCookie(string $rawCookie): self if (false === $cookieParts[1] = base64_decode($cookieParts[1], true)) { throw new AuthenticationException('The user identifier contains a character from outside the base64 alphabet.'); } + if (4 !== \count($cookieParts)) { + throw new AuthenticationException('The cookie contains invalid data.'); + } return new static(...$cookieParts); } diff --git a/src/Symfony/Component/Security/Http/Tests/Authenticator/RememberMeAuthenticatorTest.php b/src/Symfony/Component/Security/Http/Tests/Authenticator/RememberMeAuthenticatorTest.php index 27adff550d784..b0b295d70db36 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authenticator/RememberMeAuthenticatorTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authenticator/RememberMeAuthenticatorTest.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\InMemoryUser; use Symfony\Component\Security\Http\Authenticator\RememberMeAuthenticator; use Symfony\Component\Security\Http\RememberMe\RememberMeDetails; @@ -80,4 +81,12 @@ public function testAuthenticateWithoutToken() $this->authenticator->authenticate(Request::create('/')); } + + public function testAuthenticateWithoutOldToken() + { + $this->expectException(AuthenticationException::class); + + $request = Request::create('/', 'GET', [], ['_remember_me_cookie' => base64_encode('foo:bar')]); + $this->authenticator->authenticate($request); + } } From de60ca4f07be4d948e54197220a9e50392ebdf07 Mon Sep 17 00:00:00 2001 From: Nyholm Date: Sat, 19 Jun 2021 17:02:03 +0200 Subject: [PATCH 11/83] Service 'security.command.debug_firewall' is only available if symfony/console is installed --- .../DependencyInjection/SecurityExtension.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 93781ef3a5231..f1ce0a9aabef2 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -529,8 +529,10 @@ private function createFirewall(ContainerBuilder $container, string $id, array $ $listeners[] = new Reference('security.firewall.authenticator.'.$id); // Add authenticators to the debug:firewall command - $debugCommand = $container->getDefinition('security.command.debug_firewall'); - $debugCommand->replaceArgument(3, array_merge($debugCommand->getArgument(3), [$id => $authenticators])); + if ($container->hasDefinition('security.command.debug_firewall')) { + $debugCommand = $container->getDefinition('security.command.debug_firewall'); + $debugCommand->replaceArgument(3, array_merge($debugCommand->getArgument(3), [$id => $authenticators])); + } } $config->replaceArgument(7, $configuredEntryPoint ?: $defaultEntryPoint); From 017b4b341c1868c43dc31d91be0bde641b5e81bb Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 19 Jun 2021 21:27:24 +0200 Subject: [PATCH 12/83] prevent reflection usages when classes do not exist --- src/Symfony/Component/Messenger/Envelope.php | 2 +- .../Messenger/Tests/EnvelopeTest.php | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Envelope.php b/src/Symfony/Component/Messenger/Envelope.php index aa56d1b584027..a066f5044d13c 100644 --- a/src/Symfony/Component/Messenger/Envelope.php +++ b/src/Symfony/Component/Messenger/Envelope.php @@ -127,6 +127,6 @@ private function resolveAlias(string $fqcn): string { static $resolved; - return $resolved[$fqcn] ?? ($resolved[$fqcn] = (new \ReflectionClass($fqcn))->getName()); + return $resolved[$fqcn] ?? ($resolved[$fqcn] = class_exists($fqcn) ? (new \ReflectionClass($fqcn))->getName() : $fqcn); } } diff --git a/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php b/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php index 9a041f71f0763..7f03307507dd9 100644 --- a/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php +++ b/src/Symfony/Component/Messenger/Tests/EnvelopeTest.php @@ -55,6 +55,13 @@ public function testWithoutAll() $this->assertCount(1, $envelope->all(DelayStamp::class)); } + public function testWithoutAllWithNonExistentStampClass() + { + $envelope = new Envelope(new DummyMessage('dummy')); + + $this->assertInstanceOf(Envelope::class, $envelope->withoutAll(NonExistentStamp::class)); + } + public function testWithoutStampsOfType() { $envelope = new Envelope(new DummyMessage('dummy'), [ @@ -77,6 +84,13 @@ public function testWithoutStampsOfType() $this->assertEmpty($envelope5->all()); } + public function testWithoutStampsOfTypeWithNonExistentStampClass() + { + $envelope = new Envelope(new DummyMessage('dummy')); + + $this->assertInstanceOf(Envelope::class, $envelope->withoutStampsOfType(NonExistentStamp::class)); + } + public function testLast() { $receivedStamp = new ReceivedStamp('transport'); @@ -86,6 +100,13 @@ public function testLast() $this->assertNull($envelope->last(ValidationStamp::class)); } + public function testLastWithNonExistentStampClass() + { + $envelope = new Envelope(new DummyMessage('dummy')); + + $this->assertNull($envelope->last(NonExistentStamp::class)); + } + public function testAll() { $envelope = (new Envelope($dummy = new DummyMessage('dummy'))) @@ -100,6 +121,13 @@ public function testAll() $this->assertSame($validationStamp, $stamps[ValidationStamp::class][0]); } + public function testAllWithNonExistentStampClass() + { + $envelope = new Envelope(new DummyMessage('dummy')); + + $this->assertSame([], $envelope->all(NonExistentStamp::class)); + } + public function testWrapWithMessage() { $message = new \stdClass(); From 69f6409731514202ae6d4b69a4aa588b1a1aa474 Mon Sep 17 00:00:00 2001 From: Tomas Date: Fri, 18 Jun 2021 06:38:56 +0300 Subject: [PATCH 13/83] Do not use static::class for final messages --- src/Symfony/Component/Notifier/Message/EmailMessage.php | 2 +- src/Symfony/Component/Notifier/Message/SmsMessage.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Notifier/Message/EmailMessage.php b/src/Symfony/Component/Notifier/Message/EmailMessage.php index 2f83a408813b4..b649dd9caf698 100644 --- a/src/Symfony/Component/Notifier/Message/EmailMessage.php +++ b/src/Symfony/Component/Notifier/Message/EmailMessage.php @@ -39,7 +39,7 @@ public function __construct(RawMessage $message, Envelope $envelope = null) public static function fromNotification(Notification $notification, EmailRecipientInterface $recipient): self { if ('' === $recipient->getEmail()) { - throw new InvalidArgumentException(sprintf('"%s" needs an email, it cannot be empty.', static::class)); + throw new InvalidArgumentException(sprintf('"%s" needs an email, it cannot be empty.', __CLASS__)); } if (!class_exists(NotificationEmail::class)) { diff --git a/src/Symfony/Component/Notifier/Message/SmsMessage.php b/src/Symfony/Component/Notifier/Message/SmsMessage.php index 2ea49a4dcf3c4..8a6e0bfd42ab6 100644 --- a/src/Symfony/Component/Notifier/Message/SmsMessage.php +++ b/src/Symfony/Component/Notifier/Message/SmsMessage.php @@ -29,7 +29,7 @@ final class SmsMessage implements MessageInterface public function __construct(string $phone, string $subject) { if ('' === $phone) { - throw new InvalidArgumentException(sprintf('"%s" needs a phone number, it cannot be empty.', static::class)); + throw new InvalidArgumentException(sprintf('"%s" needs a phone number, it cannot be empty.', __CLASS__)); } $this->subject = $subject; From 67fae67a9adc3c234366fb779bc13f1916ad5e20 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 21 Jun 2021 14:28:32 +0200 Subject: [PATCH 14/83] [DependencyInjection] fix accepted types on FactoryTrait::factory() --- .../Loader/Configurator/Traits/FactoryTrait.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/FactoryTrait.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/FactoryTrait.php index 3834d72acada1..9968d77ae916d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/FactoryTrait.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/FactoryTrait.php @@ -12,13 +12,14 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; +use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator; trait FactoryTrait { /** * Sets a factory. * - * @param string|array $factory A PHP callable reference + * @param string|array|ReferenceConfigurator $factory A PHP callable reference * * @return $this */ From 978747e6eaf2510e50f02d20c1878b6f88014a9d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 21 Jun 2021 16:51:25 +0200 Subject: [PATCH 15/83] [Config] fix tracking default values that reference the parent class --- .../Component/Config/Resource/ReflectionClassResource.php | 4 +++- .../Config/Tests/Resource/ReflectionClassResourceTest.php | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index a0aeb354c74ff..051158b2413f3 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -161,6 +161,8 @@ private function generateSignature(\ReflectionClass $class): iterable } } + $defined = \Closure::bind(static function ($c) { return \defined($c); }, null, $class->name); + foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { if (\PHP_VERSION_ID >= 80000) { foreach ($m->getAttributes() as $a) { @@ -187,7 +189,7 @@ private function generateSignature(\ReflectionClass $class): iterable continue; } - if (!$p->isDefaultValueConstant() || \defined($p->getDefaultValueConstantName())) { + if (!$p->isDefaultValueConstant() || $defined($p->getDefaultValueConstantName())) { $defaults[$p->name] = $p->getDefaultValue(); continue; diff --git a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php index 4f61c5bbd7c61..8ba3a8c2c93cf 100644 --- a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php @@ -164,6 +164,7 @@ public function provideHashedSignature(): iterable yield [true, 17, 'public function ccc($bar = 187) {}']; yield [true, 17, 'public function ccc($bar = ANOTHER_ONE_THAT_WILL_NEVER_BE_DEFINED_CCCCCCCCC) {}']; + yield [true, 17, 'public function ccc($bar = parent::BOOM) {}']; yield [true, 17, null, static function () { \define('A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC', 'foo'); }]; } From 8451a14cf6dcbc8f11f0d8f45860a0c3997103c1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 21 Jun 2021 17:14:10 +0200 Subject: [PATCH 16/83] [DependencyInjection] Fix binding "iterable $foo" when using the PHP-DSL --- .../DependencyInjection/Compiler/ResolveBindingsPass.php | 2 +- .../Loader/Configurator/Traits/BindTrait.php | 2 +- .../DependencyInjection/Tests/Fixtures/Prototype/Foo.php | 2 +- .../Tests/Fixtures/config/defaults.expected.yml | 3 ++- .../DependencyInjection/Tests/Fixtures/config/defaults.php | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php index 70dd04601cba4..695a916f867fc 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php @@ -134,7 +134,7 @@ protected function processValue($value, $isRoot = false) } if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) { - throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected null, "%s", "%s", "%s" or ServiceLocatorArgument, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, \gettype($bindingValue))); + throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, \gettype($bindingValue))); } } diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php index 3d16ad6f01c24..573b6f53a291d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/Traits/BindTrait.php @@ -34,7 +34,7 @@ trait BindTrait final public function bind(string $nameOrFqcn, $valueOrRef): self { $valueOrRef = static::processValue($valueOrRef, true); - if (!preg_match('/^(?:(?:array|bool|float|int|string)[ \t]*+)?\$/', $nameOrFqcn) && !$valueOrRef instanceof Reference) { + if (!preg_match('/^(?:(?:array|bool|float|int|string|iterable)[ \t]*+)?\$/', $nameOrFqcn) && !$valueOrRef instanceof Reference) { throw new InvalidArgumentException(sprintf('Invalid binding for service "%s": named arguments must start with a "$", and FQCN must map to references. Neither applies to binding "%s".', $this->id, $nameOrFqcn)); } $bindings = $this->definition->getBindings(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php index b6690a8d2680a..862e1b9cd9cec 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php @@ -4,7 +4,7 @@ class Foo implements FooInterface, Sub\BarInterface { - public function __construct($bar = null) + public function __construct($bar = null, iterable $foo) { } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.expected.yml index 2b389b694590a..13321967e3d6c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.expected.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.expected.yml @@ -15,13 +15,14 @@ services: - { name: t, a: b } autowire: true autoconfigure: true - arguments: ['@bar'] + arguments: ['@bar', !tagged_iterator foo] bar: class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo public: true tags: - { name: t, a: b } autowire: true + arguments: [null, !tagged_iterator foo] calls: - [setFoo, ['@bar']] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.php index b04413d2102f3..6123403394917 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/defaults.php @@ -14,6 +14,7 @@ ->autowire() ->tag('t', ['a' => 'b']) ->bind(Foo::class, ref('bar')) + ->bind('iterable $foo', tagged_iterator('foo')) ->public(); $s->set(Foo::class)->args([ref('bar')])->public(); From dffde22329a583a1f837487083fcd107feaded4d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 21 Jun 2021 18:18:56 +0200 Subject: [PATCH 17/83] [Cache] Disable locking on Windows by default --- src/Symfony/Component/Cache/LockRegistry.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php index d480257d3db71..70fcac9cc12af 100644 --- a/src/Symfony/Component/Cache/LockRegistry.php +++ b/src/Symfony/Component/Cache/LockRegistry.php @@ -27,7 +27,7 @@ final class LockRegistry { private static $openedFiles = []; - private static $lockedFiles = []; + private static $lockedFiles; /** * The number of items in this list controls the max number of concurrent processes. @@ -81,6 +81,11 @@ public static function setFiles(array $files): array public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null) { + if ('\\' === \DIRECTORY_SEPARATOR && null === self::$lockedFiles) { + // disable locking on Windows by default + self::$files = self::$lockedFiles = []; + } + $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1; if ($key < 0 || (self::$lockedFiles[$key] ?? false) || !$lock = self::open($key)) { From 9ed93df77ae0c1b199e36769e308e0fec2b548cc Mon Sep 17 00:00:00 2001 From: Pierrick Charron Date: Mon, 21 Jun 2021 16:27:34 -0400 Subject: [PATCH 18/83] [ErrorHandler][DebugClassLoader] Do not check Phake mocks classes --- src/Symfony/Component/ErrorHandler/DebugClassLoader.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php index 36fb2ded75b3e..0668489104625 100644 --- a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php +++ b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php @@ -15,6 +15,7 @@ use Doctrine\Common\Persistence\Proxy as LegacyProxy; use Doctrine\Persistence\Proxy; use Mockery\MockInterface; +use Phake\IMock; use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation; use PHPUnit\Framework\MockObject\MockObject; use Prophecy\Prophecy\ProphecySubjectInterface; @@ -310,6 +311,7 @@ public static function checkClasses(): bool && !is_subclass_of($symbols[$i], ProxyInterface::class) && !is_subclass_of($symbols[$i], LegacyProxy::class) && !is_subclass_of($symbols[$i], MockInterface::class) + && !is_subclass_of($symbols[$i], IMock::class) ) { $loader->checkClass($symbols[$i]); } From 7f9c9d64ab641c899a450a205caa6fbb16056a2f Mon Sep 17 00:00:00 2001 From: Denis Brumann Date: Sun, 20 Jun 2021 14:38:09 +0200 Subject: [PATCH 19/83] [PasswordHasher] UserPasswordHasher only calls getSalt when method exists --- .../Hasher/UserPasswordHasher.php | 26 +++++-- .../TestLegacyPasswordAuthenticatedUser.php | 53 +++++++++++++ .../TestPasswordAuthenticatedUser.php | 20 +++++ .../Tests/Hasher/UserPasswordHasherTest.php | 76 +++++++++++++------ 4 files changed, 147 insertions(+), 28 deletions(-) create mode 100644 src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestLegacyPasswordAuthenticatedUser.php create mode 100644 src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestPasswordAuthenticatedUser.php diff --git a/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php b/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php index f26164d7e51af..4ec8a1b6ab248 100644 --- a/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php +++ b/src/Symfony/Component/PasswordHasher/Hasher/UserPasswordHasher.php @@ -43,9 +43,16 @@ public function hashPassword($user, string $plainPassword): string trigger_deprecation('symfony/password-hasher', '5.3', 'The "%s()" method expects a "%s" instance as first argument. Not implementing it in class "%s" is deprecated.', __METHOD__, PasswordAuthenticatedUserInterface::class, get_debug_type($user)); } - $salt = $user->getSalt(); - if ($salt && !$user instanceof LegacyPasswordAuthenticatedUserInterface) { - trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); + $salt = null; + + if ($user instanceof LegacyPasswordAuthenticatedUserInterface) { + $salt = $user->getSalt(); + } elseif ($user instanceof UserInterface) { + $salt = $user->getSalt(); + + if (null !== $salt) { + trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); + } } $hasher = $this->hasherFactory->getPasswordHasher($user); @@ -65,9 +72,16 @@ public function isPasswordValid($user, string $plainPassword): bool trigger_deprecation('symfony/password-hasher', '5.3', 'The "%s()" method expects a "%s" instance as first argument. Not implementing it in class "%s" is deprecated.', __METHOD__, PasswordAuthenticatedUserInterface::class, get_debug_type($user)); } - $salt = $user->getSalt(); - if ($salt && !$user instanceof LegacyPasswordAuthenticatedUserInterface) { - trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); + $salt = null; + + if ($user instanceof LegacyPasswordAuthenticatedUserInterface) { + $salt = $user->getSalt(); + } elseif ($user instanceof UserInterface) { + $salt = $user->getSalt(); + + if (null !== $salt) { + trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user)); + } } if (null === $user->getPassword()) { diff --git a/src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestLegacyPasswordAuthenticatedUser.php b/src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestLegacyPasswordAuthenticatedUser.php new file mode 100644 index 0000000000000..b0d0949c5e4ec --- /dev/null +++ b/src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestLegacyPasswordAuthenticatedUser.php @@ -0,0 +1,53 @@ +roles = $roles; + $this->salt = $salt; + $this->password = $password; + $this->username = $username; + } + + public function getSalt(): ?string + { + return $this->salt; + } + + public function getPassword(): ?string + { + return $this->password; + } + + public function getRoles() + { + return $this->roles; + } + + public function eraseCredentials() + { + // Do nothing + return; + } + + public function getUsername() + { + return $this->username; + } + + public function getUserIdentifier() + { + return $this->username; + } +} diff --git a/src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestPasswordAuthenticatedUser.php b/src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestPasswordAuthenticatedUser.php new file mode 100644 index 0000000000000..a732ebb077751 --- /dev/null +++ b/src/Symfony/Component/PasswordHasher/Tests/Fixtures/TestPasswordAuthenticatedUser.php @@ -0,0 +1,20 @@ +password = $password; + } + + public function getPassword(): ?string + { + return $this->password; + } +} diff --git a/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php b/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php index fb9188083eab6..b483864d22d53 100644 --- a/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php +++ b/src/Symfony/Component/PasswordHasher/Tests/Hasher/UserPasswordHasherTest.php @@ -17,10 +17,10 @@ use Symfony\Component\PasswordHasher\Hasher\PasswordHasherFactoryInterface; use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasher; use Symfony\Component\PasswordHasher\PasswordHasherInterface; +use Symfony\Component\PasswordHasher\Tests\Fixtures\TestLegacyPasswordAuthenticatedUser; +use Symfony\Component\PasswordHasher\Tests\Fixtures\TestPasswordAuthenticatedUser; use Symfony\Component\Security\Core\User\InMemoryUser; -use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface; use Symfony\Component\Security\Core\User\User; -use Symfony\Component\Security\Core\User\UserInterface; class UserPasswordHasherTest extends TestCase { @@ -56,12 +56,9 @@ public function testHashWithNonPasswordAuthenticatedUser() $this->assertEquals('hash', $encoded); } - public function testHash() + public function testHashWithLegacyUser() { - $userMock = $this->createMock(TestPasswordAuthenticatedUser::class); - $userMock->expects($this->any()) - ->method('getSalt') - ->willReturn('userSalt'); + $user = new TestLegacyPasswordAuthenticatedUser('name', null, 'userSalt'); $mockHasher = $this->createMock(PasswordHasherInterface::class); $mockHasher->expects($this->any()) @@ -72,25 +69,42 @@ public function testHash() $mockPasswordHasherFactory = $this->createMock(PasswordHasherFactoryInterface::class); $mockPasswordHasherFactory->expects($this->any()) ->method('getPasswordHasher') - ->with($this->equalTo($userMock)) + ->with($user) ->willReturn($mockHasher); $passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory); - $encoded = $passwordHasher->hashPassword($userMock, 'plainPassword'); + $encoded = $passwordHasher->hashPassword($user, 'plainPassword'); $this->assertEquals('hash', $encoded); } - public function testVerify() + public function testHashWithPasswordAuthenticatedUser() { - $userMock = $this->createMock(TestPasswordAuthenticatedUser::class); - $userMock->expects($this->any()) - ->method('getSalt') - ->willReturn('userSalt'); - $userMock->expects($this->any()) - ->method('getPassword') + $user = new TestPasswordAuthenticatedUser(); + + $mockHasher = $this->createMock(PasswordHasherInterface::class); + $mockHasher->expects($this->any()) + ->method('hash') + ->with($this->equalTo('plainPassword'), $this->equalTo(null)) ->willReturn('hash'); + $mockPasswordHasherFactory = $this->createMock(PasswordHasherFactoryInterface::class); + $mockPasswordHasherFactory->expects($this->any()) + ->method('getPasswordHasher') + ->with($user) + ->willReturn($mockHasher); + + $passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory); + + $hashedPassword = $passwordHasher->hashPassword($user, 'plainPassword'); + + $this->assertSame('hash', $hashedPassword); + } + + public function testVerifyWithLegacyUser() + { + $user = new TestLegacyPasswordAuthenticatedUser('user', 'hash', 'userSalt'); + $mockHasher = $this->createMock(PasswordHasherInterface::class); $mockHasher->expects($this->any()) ->method('verify') @@ -100,12 +114,34 @@ public function testVerify() $mockPasswordHasherFactory = $this->createMock(PasswordHasherFactoryInterface::class); $mockPasswordHasherFactory->expects($this->any()) ->method('getPasswordHasher') - ->with($this->equalTo($userMock)) + ->with($user) + ->willReturn($mockHasher); + + $passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory); + + $isValid = $passwordHasher->isPasswordValid($user, 'plainPassword'); + $this->assertTrue($isValid); + } + + public function testVerify() + { + $user = new TestPasswordAuthenticatedUser('hash'); + + $mockHasher = $this->createMock(PasswordHasherInterface::class); + $mockHasher->expects($this->any()) + ->method('verify') + ->with($this->equalTo('hash'), $this->equalTo('plainPassword'), $this->equalTo(null)) + ->willReturn(true); + + $mockPasswordHasherFactory = $this->createMock(PasswordHasherFactoryInterface::class); + $mockPasswordHasherFactory->expects($this->any()) + ->method('getPasswordHasher') + ->with($user) ->willReturn($mockHasher); $passwordHasher = new UserPasswordHasher($mockPasswordHasherFactory); - $isValid = $passwordHasher->isPasswordValid($userMock, 'plainPassword'); + $isValid = $passwordHasher->isPasswordValid($user, 'plainPassword'); $this->assertTrue($isValid); } @@ -128,7 +164,3 @@ public function testNeedsRehash() $this->assertFalse($passwordHasher->needsRehash($user)); } } - -abstract class TestPasswordAuthenticatedUser implements LegacyPasswordAuthenticatedUserInterface, UserInterface -{ -} From 6bc8ec6c9a3f4e47ff59d4bab22e0c387d320c0e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 22 Jun 2021 09:19:59 +0200 Subject: [PATCH 20/83] [DependencyInjection] accept service locator definitions with no class --- .../Compiler/CheckDefinitionValidityPass.php | 2 +- .../Tests/Compiler/CheckDefinitionValidityPassTest.php | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php index bb87f47cddd47..c776195e2d6c6 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php @@ -44,7 +44,7 @@ public function process(ContainerBuilder $container) } // non-synthetic, non-abstract service has class - if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) { + if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && !$definition->hasTag('container.service_locator') && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) { if ($definition->getFactory()) { throw new RuntimeException(sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id)); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php index ed1e300ce053c..c683fdbbc118a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckDefinitionValidityPassTest.php @@ -37,6 +37,16 @@ public function testProcessDetectsNonSyntheticNonAbstractDefinitionWithoutClass( $this->process($container); } + public function testProcessAcceptsServiceLocatorWithoutClass() + { + $container = new ContainerBuilder(); + $container->register('a')->addTag('container.service_locator'); + + $this->process($container); + + $this->addToAssertionCount(1); + } + public function testProcessDetectsFactoryWithoutClass() { $container = new ContainerBuilder(); From 29903e2c35f3f9f20e2a3bdef761edbb2b274c27 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 21 Jun 2021 15:22:37 +0200 Subject: [PATCH 21/83] [WebLink] fix types on Link::withAttribute() --- src/Symfony/Component/WebLink/Link.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/WebLink/Link.php b/src/Symfony/Component/WebLink/Link.php index c0402c6dc0952..55a66e075b4b2 100644 --- a/src/Symfony/Component/WebLink/Link.php +++ b/src/Symfony/Component/WebLink/Link.php @@ -46,7 +46,7 @@ class Link implements EvolvableLinkInterface private $rel = []; /** - * @var string[] + * @var array */ private $attributes = []; @@ -132,6 +132,8 @@ public function withoutRel($rel) /** * {@inheritdoc} * + * @param string|bool|string[] $value + * * @return static */ public function withAttribute($attribute, $value) From 63e42698d95ea220d25d8c4f64566187713173d2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 22 Jun 2021 09:44:52 +0200 Subject: [PATCH 22/83] [WebLink] Sync type with parent interface --- src/Symfony/Component/WebLink/Link.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/WebLink/Link.php b/src/Symfony/Component/WebLink/Link.php index 55a66e075b4b2..ad4e7230741d4 100644 --- a/src/Symfony/Component/WebLink/Link.php +++ b/src/Symfony/Component/WebLink/Link.php @@ -132,7 +132,7 @@ public function withoutRel($rel) /** * {@inheritdoc} * - * @param string|bool|string[] $value + * @param string|\Stringable|int|float|bool|string[] $value * * @return static */ From b763a2951402a20cb93e183e095792f3ff500aef Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 22 Jun 2021 10:35:27 +0200 Subject: [PATCH 23/83] [DependencyInjection] throw proper exception when decorating a synthetic service --- .../Compiler/DecoratorServicePass.php | 7 +++++++ .../Compiler/DecoratorServicePassTest.php | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php index fed2916f34def..af7c957a308a2 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DecoratorServicePass.php @@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\Alias; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; use Symfony\Component\DependencyInjection\Reference; @@ -59,6 +60,7 @@ public function process(ContainerBuilder $container) $public = $alias->isPublic(); $private = $alias->isPrivate(); $container->setAlias($renamedId, new Alias((string) $alias, false)); + $decoratedDefinition = $container->findDefinition($alias); } elseif ($container->hasDefinition($inner)) { $decoratedDefinition = $container->getDefinition($inner); $public = $decoratedDefinition->isPublic(); @@ -72,10 +74,15 @@ public function process(ContainerBuilder $container) } elseif (ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) { $public = $definition->isPublic(); $private = $definition->isPrivate(); + $decoratedDefinition = null; } else { throw new ServiceNotFoundException($inner, $id); } + if ($decoratedDefinition && $decoratedDefinition->isSynthetic()) { + throw new InvalidArgumentException(sprintf('A synthetic service cannot be decorated: service "%s" cannot decorate "%s".', $id, $inner)); + } + if (isset($decoratingDefinitions[$inner])) { $decoratingDefinition = $decoratingDefinitions[$inner]; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php index a739dda3a679a..9a456335569d4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DecoratorServicePassTest.php @@ -16,6 +16,7 @@ use Symfony\Component\DependencyInjection\Compiler\DecoratorServicePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException; class DecoratorServicePassTest extends TestCase @@ -262,6 +263,23 @@ public function testProcessLeavesServiceSubscriberTagOnOriginalDefinition() $this->assertEquals(['bar' => ['attr' => 'baz'], 'foobar' => ['attr' => 'bar']], $container->getDefinition('baz')->getTags()); } + public function testCannotDecorateSyntheticService() + { + $container = new ContainerBuilder(); + $container + ->register('foo') + ->setSynthetic(true) + ; + $container + ->register('baz') + ->setDecoratedService('foo') + ; + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('A synthetic service cannot be decorated: service "baz" cannot decorate "foo".'); + $this->process($container); + } + protected function process(ContainerBuilder $container) { $repeatedPass = new DecoratorServicePass(); From 9589b52a78bbb21602043511209f46a37e9fc886 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Baptiste=20Clavi=C3=A9?= Date: Tue, 22 Jun 2021 10:57:19 +0200 Subject: [PATCH 24/83] Reapply the change to allow to set the composer binary path This change was somehow changed back during the renaming of the file I think. So this is just restoring the change. --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index e9088bfe44f74..6558f910b0a3b 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -150,12 +150,14 @@ putenv('SYMFONY_DEPRECATIONS_HELPER=disabled'); } -$COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar') - || ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar 2> NUL`) : `which composer.phar 2> /dev/null`))) - || ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer 2> NUL`) : `which composer 2> /dev/null`))) - || file_exists($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? `git rev-parse --show-toplevel 2> NUL` : `git rev-parse --show-toplevel 2> /dev/null`)).\DIRECTORY_SEPARATOR.'composer.phar') - ? ('#!/usr/bin/env php' === file_get_contents($COMPOSER, false, null, 0, 18) ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang - : 'composer'; +if (false === $COMPOSER = getenv('COMPOSER_BINARY')) { + $COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar') + || ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar 2> NUL`) : `which composer.phar 2> /dev/null`))) + || ($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer 2> NUL`) : `which composer 2> /dev/null`))) + || file_exists($COMPOSER = rtrim((string) ('\\' === \DIRECTORY_SEPARATOR ? `git rev-parse --show-toplevel 2> NUL` : `git rev-parse --show-toplevel 2> /dev/null`)).\DIRECTORY_SEPARATOR.'composer.phar') + ? ('#!/usr/bin/env php' === file_get_contents($COMPOSER, false, null, 0, 18) ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang + : 'composer'; +} $prevCacheDir = getenv('COMPOSER_CACHE_DIR'); if ($prevCacheDir) { From 05512adf3b321425f472524698e3dc08c2643764 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 22 Jun 2021 14:49:29 +0200 Subject: [PATCH 25/83] Fix references to CheckRememberMeConditionsListener MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit … in doc blocks Signed-off-by: Alexander M. Turek --- .../Http/Authenticator/Passport/Badge/RememberMeBadge.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php index 876677851fa69..35935f3ca1086 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php @@ -11,12 +11,14 @@ namespace Symfony\Component\Security\Http\Authenticator\Passport\Badge; +use Symfony\Component\Security\Http\EventListener\CheckRememberMeConditionsListener; + /** * Adds support for remember me to this authenticator. * * The presence of this badge doesn't create the remember-me cookie. The actual * cookie is only created if this badge is enabled. By default, this is done - * by the {@see RememberMeConditionsListener} if all conditions are met. + * by the {@see CheckRememberMeConditionsListener} if all conditions are met. * * @author Wouter de Jong * @@ -29,7 +31,7 @@ class RememberMeBadge implements BadgeInterface /** * Enables remember-me cookie creation. * - * In most cases, {@see RememberMeConditionsListener} enables this + * In most cases, {@see CheckRememberMeConditionsListener} enables this * automatically if always_remember_me is true or the remember_me_parameter * exists in the request. * From d12f76f58bd967c2dda4f2a1c7dadc0e5d3e7c13 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 22 Jun 2021 15:19:15 +0200 Subject: [PATCH 26/83] Implement fluent interface on RememberMeBadge::disable() Signed-off-by: Alexander M. Turek --- .../Http/Authenticator/Passport/Badge/RememberMeBadge.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php index 876677851fa69..fa9e0dad7a4c0 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/RememberMeBadge.php @@ -47,10 +47,14 @@ public function enable(): self * * The default is disabled, this can be called to suppress creation * after it was enabled. + * + * @return $this */ - public function disable(): void + public function disable(): self { $this->enabled = false; + + return $this; } public function isEnabled(): bool From 9c69e7780518740403ca3f2239b0871bf0add504 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 22 Jun 2021 17:42:29 +0200 Subject: [PATCH 27/83] Pin masterminds/html5 to the master branch for PHP 8.1 Signed-off-by: Alexander M. Turek --- .github/workflows/tests.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1e5bffaca5171..4b4f0ad84a048 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -141,6 +141,8 @@ jobs: run: | echo "::group::fake PHP version" composer config platform.php 8.0.99 + echo "::group::Adjust dependencies" + composer require --dev --no-update masterminds/html5:~2.7.5@dev echo "::group::composer update" composer update --no-progress --ansi echo "::endgroup::" From 7f1c76212fba0c0047e5362c518d89662cae1c04 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 22 Jun 2021 20:21:40 +0200 Subject: [PATCH 28/83] [FrameworkBundle] Replace var_export with VarExporter to use array short syntax --- src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php index 8b83224305221..b93c2d30a4348 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php +++ b/src/Symfony/Bundle/FrameworkBundle/Secrets/SodiumVault.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\Secrets; use Symfony\Component\DependencyInjection\EnvVarLoaderInterface; +use Symfony\Component\VarExporter\VarExporter; /** * @author Tobias Schultze @@ -89,7 +90,7 @@ public function seal(string $name, string $value): void $list = $this->list(); $list[$name] = null; uksort($list, 'strnatcmp'); - file_put_contents($this->pathPrefix.'list.php', sprintf("pathPrefix.'list.php', sprintf("lastMessage = sprintf('Secret "%s" encrypted in "%s"; you can commit it.', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR)); } @@ -141,7 +142,7 @@ public function remove(string $name): bool $list = $this->list(); unset($list[$name]); - file_put_contents($this->pathPrefix.'list.php', sprintf("pathPrefix.'list.php', sprintf("lastMessage = sprintf('Secret "%s" removed from "%s".', $name, $this->getPrettyPath(\dirname($this->pathPrefix).\DIRECTORY_SEPARATOR)); From 6f6e8cf184b66bc49c50cf9f069ffe1164f80272 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Fri, 18 Jun 2021 09:40:49 +0200 Subject: [PATCH 29/83] Avoid broken action URL in text notification mail Some mail clients make URLs clickable automatically which leads to broken URLs due to the appended ":" (colon) Fix this by moving the action text before the action URL. --- .../Resources/views/Email/zurb_2/notification/body.txt.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.txt.twig b/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.txt.twig index db855829703e4..c98bb08a74c03 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.txt.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Email/zurb_2/notification/body.txt.twig @@ -8,7 +8,7 @@ {% block action %} {% if action_url %} -{{ action_url }}: {{ action_text }} +{{ action_text }}: {{ action_url }} {% endif %} {% endblock %} From ee7bc0272e68fc85f5cabb6ad320cccc70fc0f7f Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Thu, 10 Jun 2021 20:42:23 +0000 Subject: [PATCH 30/83] [HttpKernel] [HttpCache] Keep s-maxage=0 from ESI sub-responses --- .../HttpCache/ResponseCacheStrategy.php | 6 ++++-- .../HttpCache/ResponseCacheStrategyTest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php index 1f099468464d2..47bbbb74317e8 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php @@ -81,8 +81,10 @@ public function add(Response $response) return; } - $this->storeRelativeAgeDirective('max-age', $response->headers->getCacheControlDirective('max-age'), $age); - $this->storeRelativeAgeDirective('s-maxage', $response->headers->getCacheControlDirective('s-maxage') ?: $response->headers->getCacheControlDirective('max-age'), $age); + $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age') : null; + $this->storeRelativeAgeDirective('max-age', $maxAge, $age); + $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int) $response->headers->getCacheControlDirective('s-maxage') : $maxAge; + $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $age); $expires = $response->getExpires(); $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null; diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php index 62179ba154fcd..4875870eef34c 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php @@ -377,6 +377,22 @@ public function cacheControlMergingProvider() ], ]; + yield 's-maxage may be set to 0' => [ + ['public' => true, 's-maxage' => '0', 'max-age' => null], + ['public' => true, 's-maxage' => '0'], + [ + ['public' => true, 's-maxage' => '60'], + ], + ]; + + yield 's-maxage may be set to 0, and works independently from maxage' => [ + ['public' => true, 's-maxage' => '0', 'max-age' => '30'], + ['public' => true, 's-maxage' => '0', 'max-age' => '30'], + [ + ['public' => true, 'max-age' => '60'], + ], + ]; + yield 'result is private when combining private responses' => [ ['no-cache' => false, 'must-revalidate' => false, 'private' => true], ['s-maxage' => 60, 'private' => true], From 5f15f5d65d01d73f0510ee5e338c62ea2c40279f Mon Sep 17 00:00:00 2001 From: Mathieu Piot Date: Thu, 20 May 2021 13:47:07 +0200 Subject: [PATCH 31/83] [Validator][Translation] Add ExpressionLanguageSyntax en and fr --- .../Validator/Resources/translations/validators.en.xlf | 4 ++++ .../Validator/Resources/translations/validators.fr.xlf | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index ecc73e48aa1ef..84cd9b9dcd9c2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). This value is not a valid International Securities Identification Number (ISIN). + + This value should be a valid expression. + This value should be a valid expression. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index a4dd54295b46a..c61ff92c6d473 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Cette valeur n'est pas un code international de sécurité valide (ISIN). + + This value should be a valid expression. + Cette valeur doit être une expression valide. + From cd129210ce93779b05276a0298c32b3b2562431f Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 23 Jun 2021 16:41:09 +0200 Subject: [PATCH 32/83] [Uid] Fix fromString() with low base58 values --- src/Symfony/Component/Uid/AbstractUid.php | 4 ++-- src/Symfony/Component/Uid/Tests/UlidTest.php | 5 +++++ src/Symfony/Component/Uid/Tests/UuidTest.php | 19 +++++++++++++++++-- src/Symfony/Component/Uid/Ulid.php | 2 +- src/Symfony/Component/Uid/Uuid.php | 2 +- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Uid/AbstractUid.php b/src/Symfony/Component/Uid/AbstractUid.php index f9455533d3df8..67145cfed4770 100644 --- a/src/Symfony/Component/Uid/AbstractUid.php +++ b/src/Symfony/Component/Uid/AbstractUid.php @@ -43,7 +43,7 @@ abstract public static function fromString(string $uid): self; abstract public function toBinary(): string; /** - * Returns the identifier as a base-58 case sensitive string. + * Returns the identifier as a base58 case sensitive string. */ public function toBase58(): string { @@ -51,7 +51,7 @@ public function toBase58(): string } /** - * Returns the identifier as a base-32 case insensitive string. + * Returns the identifier as a base32 case insensitive string. */ public function toBase32(): string { diff --git a/src/Symfony/Component/Uid/Tests/UlidTest.php b/src/Symfony/Component/Uid/Tests/UlidTest.php index 2e66026b66887..beb22976d303a 100644 --- a/src/Symfony/Component/Uid/Tests/UlidTest.php +++ b/src/Symfony/Component/Uid/Tests/UlidTest.php @@ -124,4 +124,9 @@ public function testFromStringOnExtendedClassReturnsStatic() { $this->assertInstanceOf(CustomUlid::class, CustomUlid::fromString((new CustomUlid())->toBinary())); } + + public function testFromStringBase58Padding() + { + $this->assertInstanceOf(Ulid::class, Ulid::fromString('111111111u9QRyVM94rdmZ')); + } } diff --git a/src/Symfony/Component/Uid/Tests/UuidTest.php b/src/Symfony/Component/Uid/Tests/UuidTest.php index 6b5b27f3b5001..94cf660eee42f 100644 --- a/src/Symfony/Component/Uid/Tests/UuidTest.php +++ b/src/Symfony/Component/Uid/Tests/UuidTest.php @@ -187,14 +187,24 @@ public function testCompare() $this->assertSame([$a, $b, $c, $d], $uuids); } - public function testNilUuid() + /** + * @testWith ["00000000-0000-0000-0000-000000000000"] + * ["1111111111111111111111"] + * ["00000000000000000000000000"] + */ + public function testNilUuid(string $uuid) { - $uuid = Uuid::fromString('00000000-0000-0000-0000-000000000000'); + $uuid = Uuid::fromString($uuid); $this->assertInstanceOf(NilUuid::class, $uuid); $this->assertSame('00000000-0000-0000-0000-000000000000', (string) $uuid); } + public function testNewNilUuid() + { + $this->assertSame('00000000-0000-0000-0000-000000000000', (string) new NilUuid()); + } + public function testFromStringOnExtendedClassReturnsStatic() { $this->assertInstanceOf(CustomUuid::class, CustomUuid::fromString(self::A_UUID_V4)); @@ -208,4 +218,9 @@ public function testGetTime() $this->assertSame(-0.0000001, (new UuidV1('13813fff-1dd2-11b2-a456-426655440000'))->getTime()); $this->assertSame(-12219292800.0, ((new UuidV1('00000000-0000-1000-a456-426655440000'))->getTime())); } + + public function testFromStringBase58Padding() + { + $this->assertInstanceOf(Uuid::class, Uuid::fromString('111111111u9QRyVM94rdmZ')); + } } diff --git a/src/Symfony/Component/Uid/Ulid.php b/src/Symfony/Component/Uid/Ulid.php index ebde9d824df68..205495322c0a9 100644 --- a/src/Symfony/Component/Uid/Ulid.php +++ b/src/Symfony/Component/Uid/Ulid.php @@ -61,7 +61,7 @@ public static function fromString(string $ulid): parent if (36 === \strlen($ulid) && Uuid::isValid($ulid)) { $ulid = (new Uuid($ulid))->toBinary(); } elseif (22 === \strlen($ulid) && 22 === strspn($ulid, BinaryUtil::BASE58[''])) { - $ulid = BinaryUtil::fromBase($ulid, BinaryUtil::BASE58); + $ulid = str_pad(BinaryUtil::fromBase($ulid, BinaryUtil::BASE58), 16, "\0", \STR_PAD_LEFT); } if (16 !== \strlen($ulid)) { diff --git a/src/Symfony/Component/Uid/Uuid.php b/src/Symfony/Component/Uid/Uuid.php index 4ed48b5735b9d..9a9b8516ea345 100644 --- a/src/Symfony/Component/Uid/Uuid.php +++ b/src/Symfony/Component/Uid/Uuid.php @@ -37,7 +37,7 @@ public function __construct(string $uuid) public static function fromString(string $uuid): parent { if (22 === \strlen($uuid) && 22 === strspn($uuid, BinaryUtil::BASE58[''])) { - $uuid = BinaryUtil::fromBase($uuid, BinaryUtil::BASE58); + $uuid = str_pad(BinaryUtil::fromBase($uuid, BinaryUtil::BASE58), 16, "\0", \STR_PAD_LEFT); } if (16 === \strlen($uuid)) { From 043ee56b98741b28bd7e1a61e2c49a4854f22f53 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Wed, 23 Jun 2021 17:37:19 +0200 Subject: [PATCH 33/83] [Uid] Prevent double validation in Uuid::fromString() with base32 values --- src/Symfony/Component/Uid/Ulid.php | 2 +- src/Symfony/Component/Uid/Uuid.php | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Uid/Ulid.php b/src/Symfony/Component/Uid/Ulid.php index d74ff6fb2aa6f..eba9f4172ded4 100644 --- a/src/Symfony/Component/Uid/Ulid.php +++ b/src/Symfony/Component/Uid/Ulid.php @@ -43,7 +43,7 @@ public function __construct(string $ulid = null) throw new \InvalidArgumentException(sprintf('Invalid ULID: "%s".', $ulid)); } - $this->uid = strtr($ulid, 'abcdefghjkmnpqrstvwxyz', 'ABCDEFGHJKMNPQRSTVWXYZ'); + $this->uid = strtoupper($ulid); } public static function isValid(string $ulid): bool diff --git a/src/Symfony/Component/Uid/Uuid.php b/src/Symfony/Component/Uid/Uuid.php index dc666d28e31ab..a6cb942e8c62f 100644 --- a/src/Symfony/Component/Uid/Uuid.php +++ b/src/Symfony/Component/Uid/Uuid.php @@ -54,7 +54,9 @@ public static function fromString(string $uuid): parent $uuid = substr_replace($uuid, '-', 18, 0); $uuid = substr_replace($uuid, '-', 23, 0); } elseif (26 === \strlen($uuid) && Ulid::isValid($uuid)) { - $uuid = (new Ulid($uuid))->toRfc4122(); + $ulid = new Ulid('00000000000000000000000000'); + $ulid->uid = strtoupper($uuid); + $uuid = $ulid->toRfc4122(); } if (__CLASS__ !== static::class || 36 !== \strlen($uuid)) { From 5f2d5e043757437beaa2a87f344a9ae1cc26bd08 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 22 Jun 2021 17:28:51 +0200 Subject: [PATCH 34/83] [Cache] fix eventual consistency when using RedisTagAwareAdapter with a cluster --- .../Cache/Adapter/RedisTagAwareAdapter.php | 148 +++++++++--------- .../Tests/Adapter/TagAwareAdapterTest.php | 5 + .../Cache/Tests/LockRegistryTest.php | 3 + .../Component/Cache/Traits/RedisTrait.php | 18 ++- 4 files changed, 88 insertions(+), 86 deletions(-) diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php index 9409c346fb817..6f4b75d313d72 100644 --- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php @@ -23,17 +23,13 @@ use Symfony\Component\Cache\Traits\RedisTrait; /** - * Stores tag id <> cache id relationship as a Redis Set, lookup on invalidation using RENAME+SMEMBERS. + * Stores tag id <> cache id relationship as a Redis Set. * * Set (tag relation info) is stored without expiry (non-volatile), while cache always gets an expiry (volatile) even * if not set by caller. Thus if you configure redis with the right eviction policy you can be safe this tag <> cache * relationship survives eviction (cache cleanup when Redis runs out of memory). * - * Requirements: - * - Client: PHP Redis or Predis - * Note: Due to lack of RENAME support it is NOT recommended to use Cluster on Predis, instead use phpredis. - * - Server: Redis 2.8+ - * Configured with any `volatile-*` eviction policy, OR `noeviction` if it will NEVER fill up memory + * Redis server 2.8+ with any `volatile-*` eviction policy, OR `noeviction` if you're sure memory will NEVER fill up * * Design limitations: * - Max 4 billion cache keys per cache tag as limited by Redis Set datatype. @@ -49,11 +45,6 @@ class RedisTagAwareAdapter extends AbstractTagAwareAdapter { use RedisTrait; - /** - * Limits for how many keys are deleted in batch. - */ - private const BULK_DELETE_LIMIT = 10000; - /** * On cache items without a lifetime set, we set it to 100 days. This is to make sure cache items are * preferred to be evicted over tag Sets, if eviction policy is configured according to requirements. @@ -96,7 +87,7 @@ protected function doSave(array $values, int $lifetime, array $addTagData = [], { $eviction = $this->getRedisEvictionPolicy(); if ('noeviction' !== $eviction && 0 !== strpos($eviction, 'volatile-')) { - throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction)); + throw new LogicException(sprintf('Redis maxmemory-policy setting "%s" is *not* supported by RedisTagAwareAdapter, use "noeviction" or "volatile-*" eviction policies.', $eviction)); } // serialize values @@ -159,15 +150,9 @@ protected function doDeleteYieldTags(array $ids): iterable return v:sub(14, 13 + v:byte(13) + v:byte(12) * 256 + v:byte(11) * 65536) EOLUA; - if ($this->redis instanceof \Predis\ClientInterface) { - $evalArgs = [$lua, 1, &$id]; - } else { - $evalArgs = [$lua, [&$id], 1]; - } - - $results = $this->pipeline(function () use ($ids, &$id, $evalArgs) { + $results = $this->pipeline(function () use ($ids, $lua) { foreach ($ids as $id) { - yield 'eval' => $evalArgs; + yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id] : [$lua, [$id], 1]; } }); @@ -185,12 +170,15 @@ protected function doDeleteYieldTags(array $ids): iterable */ protected function doDeleteTagRelations(array $tagData): bool { - $this->pipeline(static function () use ($tagData) { + $results = $this->pipeline(static function () use ($tagData) { foreach ($tagData as $tagId => $idList) { array_unshift($idList, $tagId); yield 'sRem' => $idList; } - })->rewind(); + }); + foreach ($results as $result) { + // no-op + } return true; } @@ -200,77 +188,81 @@ protected function doDeleteTagRelations(array $tagData): bool */ protected function doInvalidate(array $tagIds): bool { - if (!$this->redis instanceof \Predis\ClientInterface || !$this->redis->getConnection() instanceof PredisCluster) { - $movedTagSetIds = $this->renameKeys($this->redis, $tagIds); - } else { - $clusterConnection = $this->redis->getConnection(); - $tagIdsByConnection = new \SplObjectStorage(); - $movedTagSetIds = []; + // This script scans the set of items linked to tag: it empties the set + // and removes the linked items. When the set is still not empty after + // the scan, it means we're in cluster mode and that the linked items + // are on other nodes: we move the links to a temporary set and we + // gargage collect that set from the client side. - foreach ($tagIds as $id) { - $connection = $clusterConnection->getConnectionByKey($id); - $slot = $tagIdsByConnection[$connection] ?? $tagIdsByConnection[$connection] = new \ArrayObject(); - $slot[] = $id; - } + $lua = <<<'EOLUA' + local cursor = '0' + local id = KEYS[1] + repeat + local result = redis.call('SSCAN', id, cursor, 'COUNT', 5000); + cursor = result[1]; + local rems = {} + + for _, v in ipairs(result[2]) do + local ok, _ = pcall(redis.call, 'DEL', ARGV[1]..v) + if ok then + table.insert(rems, v) + end + end + if 0 < #rems then + redis.call('SREM', id, unpack(rems)) + end + until '0' == cursor; + + redis.call('SUNIONSTORE', '{'..id..'}'..id, id) + redis.call('DEL', id) + + return redis.call('SSCAN', '{'..id..'}'..id, '0', 'COUNT', 5000) +EOLUA; - foreach ($tagIdsByConnection as $connection) { - $slot = $tagIdsByConnection[$connection]; - $movedTagSetIds = array_merge($movedTagSetIds, $this->renameKeys(new $this->redis($connection, $this->redis->getOptions()), $slot->getArrayCopy())); + $results = $this->pipeline(function () use ($tagIds, $lua) { + if ($this->redis instanceof \Predis\ClientInterface) { + $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : ''; + } elseif (\is_array($prefix = $this->redis->getOption(\Redis::OPT_PREFIX) ?? '')) { + $prefix = current($prefix); } - } - // No Sets found - if (!$movedTagSetIds) { - return false; - } - - // Now safely take the time to read the keys in each set and collect ids we need to delete - $tagIdSets = $this->pipeline(static function () use ($movedTagSetIds) { - foreach ($movedTagSetIds as $movedTagId) { - yield 'sMembers' => [$movedTagId]; + foreach ($tagIds as $id) { + yield 'eval' => $this->redis instanceof \Predis\ClientInterface ? [$lua, 1, $id, $prefix] : [$lua, [$id, $prefix], 1]; } }); - // Return combination of the temporary Tag Set ids and their values (cache ids) - $ids = array_merge($movedTagSetIds, ...iterator_to_array($tagIdSets, false)); + $lua = <<<'EOLUA' + local id = KEYS[1] + local cursor = table.remove(ARGV) + redis.call('SREM', '{'..id..'}'..id, unpack(ARGV)) - // Delete cache in chunks to avoid overloading the connection - foreach (array_chunk(array_unique($ids), self::BULK_DELETE_LIMIT) as $chunkIds) { - $this->doDelete($chunkIds); - } + return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000) +EOLUA; - return true; - } + foreach ($results as $id => [$cursor, $ids]) { + while ($ids || '0' !== $cursor) { + $this->doDelete($ids); - /** - * Renames several keys in order to be able to operate on them without risk of race conditions. - * - * Filters out keys that do not exist before returning new keys. - * - * @see https://redis.io/commands/rename - * @see https://redis.io/topics/cluster-spec#keys-hash-tags - * - * @return array Filtered list of the valid moved keys (only those that existed) - */ - private function renameKeys($redis, array $ids): array - { - $newIds = []; - $uniqueToken = bin2hex(random_bytes(10)); + $evalArgs = [$id, $cursor]; + array_splice($evalArgs, 1, 0, $ids); - $results = $this->pipeline(static function () use ($ids, $uniqueToken) { - foreach ($ids as $id) { - yield 'rename' => [$id, '{'.$id.'}'.$uniqueToken]; - } - }, $redis); + if ($this->redis instanceof \Predis\ClientInterface) { + array_unshift($evalArgs, $lua, 1); + } else { + $evalArgs = [$lua, $evalArgs, 1]; + } - foreach ($results as $id => $result) { - if (true === $result || ($result instanceof Status && Status::get('OK') === $result)) { - // Only take into account if ok (key existed), will be false on phpredis if it did not exist - $newIds[] = '{'.$id.'}'.$uniqueToken; + $results = $this->pipeline(function () use ($evalArgs) { + yield 'eval' => $evalArgs; + }); + + foreach ($results as [$cursor, $ids]) { + // no-op + } } } - return $newIds; + return true; } private function getRedisEvictionPolicy(): string diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php index adef44b2c3d28..de7b81149d774 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Adapter\TagAwareAdapter; +use Symfony\Component\Cache\LockRegistry; use Symfony\Component\Cache\Tests\Fixtures\PrunableAdapter; /** @@ -199,6 +200,8 @@ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags public function testLog() { + $lockFiles = LockRegistry::setFiles([__FILE__]); + $logger = $this->createMock(LoggerInterface::class); $logger ->expects($this->atLeastOnce()) @@ -209,6 +212,8 @@ public function testLog() // Computing will produce at least one log $cache->get('foo', static function (): string { return 'ccc'; }); + + LockRegistry::setFiles($lockFiles); } /** diff --git a/src/Symfony/Component/Cache/Tests/LockRegistryTest.php b/src/Symfony/Component/Cache/Tests/LockRegistryTest.php index 0771347ed6fe3..30ff6774047a5 100644 --- a/src/Symfony/Component/Cache/Tests/LockRegistryTest.php +++ b/src/Symfony/Component/Cache/Tests/LockRegistryTest.php @@ -18,6 +18,9 @@ class LockRegistryTest extends TestCase { public function testFiles() { + if ('\\' === \DIRECTORY_SEPARATOR) { + $this->markTestSkipped('LockRegistry is disabled on Windows'); + } $lockFiles = LockRegistry::setFiles([]); LockRegistry::setFiles($lockFiles); $expected = array_map('realpath', glob(__DIR__.'/../Adapter/*')); diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 7aaca38292006..fcca8d652f33c 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -363,12 +363,6 @@ protected function doHave($id) protected function doClear($namespace) { $cleared = true; - if ($this->redis instanceof \Predis\ClientInterface) { - $evalArgs = [0, $namespace]; - } else { - $evalArgs = [[$namespace], 0]; - } - $hosts = $this->getHosts(); $host = reset($hosts); if ($host instanceof \Predis\Client && $host->getConnection() instanceof ReplicationInterface) { @@ -385,17 +379,20 @@ protected function doClear($namespace) $info = $host->info('Server'); $info = $info['Server'] ?? $info; + $pattern = $namespace.'*'; + if (!version_compare($info['redis_version'], '2.8', '>=')) { // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS // can hang your server when it is executed against large databases (millions of items). // Whenever you hit this scale, you should really consider upgrading to Redis 2.8 or above. - $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]..'*') for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $evalArgs[0], $evalArgs[1]) && $cleared; + $args = $this->redis instanceof \Predis\ClientInterface ? [0, $pattern] : [[$pattern], 0]; + $cleared = $host->eval("local keys=redis.call('KEYS',ARGV[1]) for i=1,#keys,5000 do redis.call('DEL',unpack(keys,i,math.min(i+4999,#keys))) end return 1", $args[0], $args[1]) && $cleared; continue; } $cursor = null; do { - $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $namespace.'*', 'COUNT', 1000) : $host->scan($cursor, $namespace.'*', 1000); + $keys = $host instanceof \Predis\ClientInterface ? $host->scan($cursor, 'MATCH', $pattern, 'COUNT', 1000) : $host->scan($cursor, $pattern, 1000); if (isset($keys[1]) && \is_array($keys[1])) { $cursor = $keys[0]; $keys = $keys[1]; @@ -507,6 +504,11 @@ private function pipeline(\Closure $generator, $redis = null): \Generator $results = $redis->exec(); } + if (!$redis instanceof \Predis\ClientInterface && 'eval' === $command && $redis->getLastError()) { + $e = new \RedisException($redis->getLastError()); + $results = array_map(function ($v) use ($e) { return false === $v ? $e : $v; }, $results); + } + foreach ($ids as $k => $id) { yield $id => $results[$k]; } From 7527b5a4f9ca79aac6dd9525f3c123ba992988d7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 22 Jun 2021 17:28:51 +0200 Subject: [PATCH 35/83] [Cache] handle prefixed redis connections when clearing pools --- .../Tests/Adapter/AbstractRedisAdapterTest.php | 16 +++++++++++++++- .../Cache/Tests/Adapter/PredisAdapterTest.php | 2 +- .../Tests/Adapter/PredisClusterAdapterTest.php | 2 +- .../Adapter/PredisRedisClusterAdapterTest.php | 2 +- .../Tests/Adapter/PredisTagAwareAdapterTest.php | 2 +- .../Adapter/PredisTagAwareClusterAdapterTest.php | 2 +- .../Tests/Adapter/RedisAdapterSentinelTest.php | 2 +- .../Cache/Tests/Adapter/RedisAdapterTest.php | 8 ++++++-- .../Tests/Adapter/RedisArrayAdapterTest.php | 1 + .../Tests/Adapter/RedisClusterAdapterTest.php | 7 ++++++- .../Tests/Adapter/RedisTagAwareAdapterTest.php | 6 +++++- .../Adapter/RedisTagAwareArrayAdapterTest.php | 6 +++++- .../Adapter/RedisTagAwareClusterAdapterTest.php | 6 +++++- .../Cache/Traits/RedisClusterNodeProxy.php | 5 +++++ .../Component/Cache/Traits/RedisTrait.php | 16 +++++++++++++++- 15 files changed, 69 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTest.php index 994ae81d5b3a6..9d14007fde75f 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AbstractRedisAdapterTest.php @@ -24,7 +24,7 @@ abstract class AbstractRedisAdapterTest extends AdapterTestCase protected static $redis; - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { return new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); } @@ -45,4 +45,18 @@ public static function tearDownAfterClass(): void { self::$redis = null; } + + /** + * @runInSeparateProcess + */ + public function testClearWithPrefix() + { + $cache = $this->createCachePool(0, __FUNCTION__); + + $cache->save($cache->getItem('foo')->set('bar')); + $this->assertTrue($cache->hasItem('foo')); + + $cache->clear(); + $this->assertFalse($cache->hasItem('foo')); + } } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php index e19f74f6745c2..a1a2b4dda3fc8 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisAdapterTest.php @@ -22,7 +22,7 @@ class PredisAdapterTest extends AbstractRedisAdapterTest public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); - self::$redis = new \Predis\Client(['host' => getenv('REDIS_HOST')]); + self::$redis = new \Predis\Client(['host' => getenv('REDIS_HOST')], ['prefix' => 'prefix_']); } public function testCreateConnection() diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php index e6989be292334..e2f09cd23ae44 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisClusterAdapterTest.php @@ -19,7 +19,7 @@ class PredisClusterAdapterTest extends AbstractRedisAdapterTest public static function setUpBeforeClass(): void { parent::setUpBeforeClass(); - self::$redis = new \Predis\Client([['host' => getenv('REDIS_HOST')]]); + self::$redis = new \Predis\Client([['host' => getenv('REDIS_HOST')]], ['prefix' => 'prefix_']); } public static function tearDownAfterClass(): void diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisClusterAdapterTest.php index 81dd0bc2a04cc..9db83c0db4126 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisClusterAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisRedisClusterAdapterTest.php @@ -24,7 +24,7 @@ public static function setUpBeforeClass(): void self::markTestSkipped('REDIS_CLUSTER_HOSTS env var is not defined.'); } - self::$redis = RedisAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['class' => \Predis\Client::class, 'redis_cluster' => true]); + self::$redis = RedisAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['class' => \Predis\Client::class, 'redis_cluster' => true, 'prefix' => 'prefix_']); } public static function tearDownAfterClass(): void diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php index 6cffbde7926f1..0971f80c553e5 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareAdapterTest.php @@ -27,7 +27,7 @@ protected function setUp(): void $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { $this->assertInstanceOf(\Predis\Client::class, self::$redis); $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php index 21120d606ac18..af25b2df52c45 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PredisTagAwareClusterAdapterTest.php @@ -27,7 +27,7 @@ protected function setUp(): void $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { $this->assertInstanceOf(\Predis\Client::class, self::$redis); $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php index 0eb407bafa5b9..20f0811863aaa 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterSentinelTest.php @@ -32,7 +32,7 @@ public static function setUpBeforeClass(): void self::markTestSkipped('REDIS_SENTINEL_SERVICE env var is not defined.'); } - self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['redis_sentinel' => $service]); + self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['redis_sentinel' => $service, 'prefix' => 'prefix_']); } public function testInvalidDSNHasBothClusterAndSentinel() diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php index b54a5acc84260..d961187aeca3a 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php @@ -28,9 +28,13 @@ public static function setUpBeforeClass(): void self::$redis = AbstractAdapter::createConnection('redis://'.getenv('REDIS_HOST'), ['lazy' => true]); } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { - $adapter = parent::createCachePool($defaultLifetime); + if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) { + self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX); + } + + $adapter = parent::createCachePool($defaultLifetime, $testMethod); $this->assertInstanceOf(RedisProxy::class, self::$redis); return $adapter; diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php index 70afe6dac97c9..6e0b448746e86 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php @@ -23,5 +23,6 @@ public static function setUpBeforeClass(): void self::markTestSkipped('The RedisArray class is required.'); } self::$redis = new \RedisArray([getenv('REDIS_HOST')], ['lazy_connect' => true]); + self::$redis->setOption(\Redis::OPT_PREFIX, 'prefix_'); } } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php index 1253aeb5007a7..011a36b338229 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisClusterAdapterTest.php @@ -32,10 +32,15 @@ public static function setUpBeforeClass(): void } self::$redis = AbstractAdapter::createConnection('redis:?host['.str_replace(' ', ']&host[', $hosts).']', ['lazy' => true, 'redis_cluster' => true]); + self::$redis->setOption(\Redis::OPT_PREFIX, 'prefix_'); } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { + if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) { + self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX); + } + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); $adapter = new RedisAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php index 5c82016be2adb..12e3b6ff55365 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareAdapterTest.php @@ -28,8 +28,12 @@ protected function setUp(): void $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { + if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) { + self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX); + } + $this->assertInstanceOf(RedisProxy::class, self::$redis); $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php index 3ec500a9010e9..b5823711dc858 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareArrayAdapterTest.php @@ -27,8 +27,12 @@ protected function setUp(): void $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { + if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) { + self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX); + } + $this->assertInstanceOf(\RedisArray::class, self::$redis); $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php index 50f078c04d4b0..d4a1bc97779ca 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisTagAwareClusterAdapterTest.php @@ -28,8 +28,12 @@ protected function setUp(): void $this->skippedTests['testTagItemExpiry'] = 'Testing expiration slows down the test suite'; } - public function createCachePool(int $defaultLifetime = 0): CacheItemPoolInterface + public function createCachePool(int $defaultLifetime = 0, string $testMethod = null): CacheItemPoolInterface { + if ('testClearWithPrefix' === $testMethod && \defined('Redis::SCAN_PREFIX')) { + self::$redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_PREFIX); + } + $this->assertInstanceOf(RedisClusterProxy::class, self::$redis); $adapter = new RedisTagAwareAdapter(self::$redis, str_replace('\\', '.', __CLASS__), $defaultLifetime); diff --git a/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php b/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php index 7818f0b8df9c9..deba74f6a3b7d 100644 --- a/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php +++ b/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php @@ -45,4 +45,9 @@ public function scan(&$iIterator, $strPattern = null, $iCount = null) { return $this->redis->scan($iIterator, $this->host, $strPattern, $iCount); } + + public function getOption($name) + { + return $this->redis->getOption($name); + } } diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index fcca8d652f33c..aaf4f1bd00e46 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -362,6 +362,11 @@ protected function doHave($id) */ protected function doClear($namespace) { + if ($this->redis instanceof \Predis\ClientInterface) { + $prefix = $this->redis->getOptions()->prefix ? $this->redis->getOptions()->prefix->getPrefix() : ''; + $prefixLen = \strlen($prefix); + } + $cleared = true; $hosts = $this->getHosts(); $host = reset($hosts); @@ -379,7 +384,11 @@ protected function doClear($namespace) $info = $host->info('Server'); $info = $info['Server'] ?? $info; - $pattern = $namespace.'*'; + if (!$host instanceof \Predis\ClientInterface) { + $prefix = \defined('Redis::SCAN_PREFIX') && (\Redis::SCAN_PREFIX & $host->getOption(\Redis::OPT_SCAN)) ? '' : $host->getOption(\Redis::OPT_PREFIX); + $prefixLen = \strlen($host->getOption(\Redis::OPT_PREFIX) ?? ''); + } + $pattern = $prefix.$namespace.'*'; if (!version_compare($info['redis_version'], '2.8', '>=')) { // As documented in Redis documentation (http://redis.io/commands/keys) using KEYS @@ -398,6 +407,11 @@ protected function doClear($namespace) $keys = $keys[1]; } if ($keys) { + if ($prefixLen) { + foreach ($keys as $i => $key) { + $keys[$i] = substr($key, $prefixLen); + } + } $this->doDelete($keys); } } while ($cursor = (int) $cursor); From 88c69c0ec02fb35ff7e9da9f4c76218857f256a9 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Thu, 10 Jun 2021 09:06:30 +0200 Subject: [PATCH 36/83] [DependencyInjection] Add support of PHP enumerations --- .../DependencyInjection/Dumper/PhpDumper.php | 2 ++ .../DependencyInjection/Dumper/XmlDumper.php | 5 ++++ .../DependencyInjection/Dumper/YamlDumper.php | 2 ++ .../Tests/Dumper/PhpDumperTest.php | 25 ++++++++++++++++ .../Tests/Dumper/XmlDumperTest.php | 19 ++++++++++++ .../Tests/Dumper/YamlDumperTest.php | 19 ++++++++++++ .../Fixtures/FooClassWithEnumAttribute.php | 18 ++++++++++++ .../Tests/Fixtures/FooUnitEnum.php | 8 +++++ .../xml/services_with_enumeration.xml | 9 ++++++ .../xml/services_with_invalid_enumeration.xml | 9 ++++++ .../yaml/services_with_enumeration.yml | 10 +++++++ .../services_with_invalid_enumeration.yml | 10 +++++++ .../Tests/Loader/XmlFileLoaderTest.php | 28 ++++++++++++++++++ .../Tests/Loader/YamlFileLoaderTest.php | 29 +++++++++++++++++++ src/Symfony/Component/Yaml/Inline.php | 2 ++ .../Yaml/Tests/Fixtures/FooUnitEnum.php | 8 +++++ .../Component/Yaml/Tests/InlineTest.php | 9 ++++++ 17 files changed, 212 insertions(+) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithEnumAttribute.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooUnitEnum.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_enumeration.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_enumeration.xml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml create mode 100644 src/Symfony/Component/Yaml/Tests/Fixtures/FooUnitEnum.php diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 711b631d54590..3ea0b1b93f731 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -1812,6 +1812,8 @@ private function dumpValue($value, bool $interpolate = true): string return $code; } + } elseif ($value instanceof \UnitEnum) { + return sprintf('\%s::%s', \get_class($value), $value->name); } elseif (\is_object($value) || \is_resource($value)) { throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index 02a501bd2c34c..8017fc579aaa2 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -313,6 +313,9 @@ private function convertParameters(array $parameters, string $type, \DOMElement $element->setAttribute('type', 'binary'); $text = $this->document->createTextNode(self::phpToXml(base64_encode($value))); $element->appendChild($text); + } elseif ($value instanceof \UnitEnum) { + $element->setAttribute('type', 'constant'); + $element->appendChild($this->document->createTextNode(self::phpToXml($value))); } else { if (\in_array($value, ['null', 'true', 'false'], true)) { $element->setAttribute('type', 'string'); @@ -366,6 +369,8 @@ public static function phpToXml($value): string return 'false'; case $value instanceof Parameter: return '%'.$value.'%'; + case $value instanceof \UnitEnum: + return sprintf('%s::%s', \get_class($value), $value->name); case \is_object($value) || \is_resource($value): throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); default: diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index c055a686128c2..5dce997d9df9d 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -286,6 +286,8 @@ private function dumpValue($value) return $this->getExpressionCall((string) $value); } elseif ($value instanceof Definition) { return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']); + } elseif ($value instanceof \UnitEnum) { + return new TaggedValue('php/const', sprintf('%s::%s', \get_class($value), $value->name)); } elseif (\is_object($value) || \is_resource($value)) { throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.'); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index b46fbf937b910..3468e35a944c1 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -40,6 +40,8 @@ use Symfony\Component\DependencyInjection\Tests\Compiler\Foo; use Symfony\Component\DependencyInjection\Tests\Compiler\Wither; use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory; use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator; use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1; @@ -1208,6 +1210,29 @@ public function testDumpHandlesObjectClassNames() $this->assertInstanceOf(\stdClass::class, $container->get('bar')); } + /** + * @requires PHP 8.1 + */ + public function testDumpHandlesEnumeration() + { + $container = new ContainerBuilder(); + $container + ->register('foo', FooClassWithEnumAttribute::class) + ->setPublic(true) + ->addArgument(FooUnitEnum::BAR); + + $container->compile(); + + $dumper = new PhpDumper($container); + eval('?>'.$dumper->dump([ + 'class' => 'Symfony_DI_PhpDumper_Test_Enumeration', + ])); + + $container = new \Symfony_DI_PhpDumper_Test_Enumeration(); + + $this->assertSame(FooUnitEnum::BAR, $container->get('foo')->getBar()); + } + public function testUninitializedSyntheticReference() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php index dda18a306207e..18caa150f278e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php @@ -21,6 +21,8 @@ use Symfony\Component\DependencyInjection\Dumper\XmlDumper; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; class XmlDumperTest extends TestCase { @@ -249,4 +251,21 @@ public function testDumpAbstractServices() $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_abstract.xml'), $dumper->dump()); } + + /** + * @requires PHP 8.1 + */ + public function testDumpHandlesEnumeration() + { + $container = new ContainerBuilder(); + $container + ->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class) + ->setPublic(true) + ->addArgument(FooUnitEnum::BAR); + + $container->compile(); + $dumper = new XmlDumper($container); + + $this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_with_enumeration.xml'), $dumper->dump()); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php index b359f668d7758..9a973afe69df7 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php @@ -22,6 +22,8 @@ use Symfony\Component\DependencyInjection\Dumper\YamlDumper; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\Yaml\Parser; use Symfony\Component\Yaml\Yaml; @@ -129,6 +131,23 @@ public function testServiceClosure() $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_service_closure.yml', $dumper->dump()); } + /** + * @requires PHP 8.1 + */ + public function testDumpHandlesEnumeration() + { + $container = new ContainerBuilder(); + $container + ->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class) + ->setPublic(true) + ->addArgument(FooUnitEnum::BAR); + + $container->compile(); + $dumper = new YamlDumper($container); + + $this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump()); + } + private function assertEqualYamlStructure(string $expected, string $yaml, string $message = '') { $parser = new Parser(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithEnumAttribute.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithEnumAttribute.php new file mode 100644 index 0000000000000..3b2235efdd76b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithEnumAttribute.php @@ -0,0 +1,18 @@ +bar = $bar; + } + + public function getBar(): FooUnitEnum + { + return $this->bar; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooUnitEnum.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooUnitEnum.php new file mode 100644 index 0000000000000..d51cf9c995e26 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooUnitEnum.php @@ -0,0 +1,8 @@ + + + + + + Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_enumeration.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_enumeration.xml new file mode 100644 index 0000000000000..8864e6d892857 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_enumeration.xml @@ -0,0 +1,9 @@ + + + + + + Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml new file mode 100644 index 0000000000000..46bf505d44b80 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_enumeration.yml @@ -0,0 +1,10 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute + public: true + arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR'] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml new file mode 100644 index 0000000000000..b9f74e0f468ab --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_with_invalid_enumeration.yml @@ -0,0 +1,10 @@ + +services: + service_container: + class: Symfony\Component\DependencyInjection\ContainerInterface + public: true + synthetic: true + Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute: + class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute + public: true + arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ'] diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 80d3393010602..ef00b2f721608 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -37,6 +37,8 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar; use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype; use Symfony\Component\ExpressionLanguage\Expression; @@ -827,6 +829,32 @@ public function testInstanceof() $this->assertSame(['foo' => [[]], 'bar' => [[]]], $definition->getTags()); } + /** + * @requires PHP 8.1 + */ + public function testEnumeration() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('services_with_enumeration.xml'); + $container->compile(); + + $definition = $container->getDefinition(FooClassWithEnumAttribute::class); + $this->assertSame([FooUnitEnum::BAR], $definition->getArguments()); + } + + /** + * @requires PHP 8.1 + */ + public function testInvalidEnumeration() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + + $this->expectException(\Error::class); + $loader->load('services_with_invalid_enumeration.xml'); + } + public function testInstanceOfAndChildDefinitionNotAllowed() { $this->expectException(InvalidArgumentException::class); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index f367bf3452384..910e7b2a243e5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -37,6 +37,8 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar; use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute; +use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype; use Symfony\Component\ExpressionLanguage\Expression; @@ -909,6 +911,33 @@ public function testDefaultValueOfTagged() $this->assertNull($iteratorArgument->getIndexAttribute()); } + /** + * @requires PHP 8.1 + */ + public function testEnumeration() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('services_with_enumeration.yml'); + $container->compile(); + + $definition = $container->getDefinition(FooClassWithEnumAttribute::class); + $this->assertSame([FooUnitEnum::BAR], $definition->getArguments()); + } + + /** + * @requires PHP 8.1 + */ + public function testInvalidEnumeration() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The constant "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not defined'); + $loader->load('services_with_invalid_enumeration.yml'); + } + public function testReturnsClone() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index a317bb0438e5f..10ed14fe5116b 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -127,6 +127,8 @@ public static function dump($value, int $flags = 0): string return self::dumpNull($flags); case $value instanceof \DateTimeInterface: return $value->format('c'); + case $value instanceof \UnitEnum: + return sprintf('!php/const %s::%s', \get_class($value), $value->name); case \is_object($value): if ($value instanceof TaggedValue) { return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags); diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/FooUnitEnum.php b/src/Symfony/Component/Yaml/Tests/Fixtures/FooUnitEnum.php new file mode 100644 index 0000000000000..59092e27e8728 --- /dev/null +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/FooUnitEnum.php @@ -0,0 +1,8 @@ +assertSame($expected, Inline::dump($dateTime)); } + /** + * @requires PHP 8.1 + */ + public function testDumpUnitEnum() + { + $this->assertSame("!php/const Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum::BAR", Inline::dump(FooUnitEnum::BAR)); + } + public function getDateTimeDumpTests() { $tests = []; From 974516133a21390e4f8e2b57c40863054cb858a2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 23 Jun 2021 22:56:48 +0200 Subject: [PATCH 37/83] [HttpClient] fix Psr18Client when allow_url_fopen=0 --- src/Symfony/Component/HttpClient/Response/StreamWrapper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php index 83f1562e84e35..644f2ee190f57 100644 --- a/src/Symfony/Component/HttpClient/Response/StreamWrapper.php +++ b/src/Symfony/Component/HttpClient/Response/StreamWrapper.php @@ -53,7 +53,7 @@ public static function createResource(ResponseInterface $response, HttpClientInt throw new \InvalidArgumentException(sprintf('Providing a client to "%s()" is required when the response doesn\'t have any "stream()" method.', __CLASS__)); } - if (false === stream_wrapper_register('symfony', __CLASS__, \STREAM_IS_URL)) { + if (false === stream_wrapper_register('symfony', __CLASS__)) { throw new \RuntimeException(error_get_last()['message'] ?? 'Registering the "symfony" stream wrapper failed.'); } From 07407c74cabe1a22199a5a27e2ccf47ded580a5f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 21 Jun 2021 14:19:38 +0200 Subject: [PATCH 38/83] [ErrorHandler] fix handling buffered SilencedErrorContext --- .../Component/ErrorHandler/Resources/views/logs.html.php | 2 +- src/Symfony/Component/ErrorHandler/ThrowableUtils.php | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/ErrorHandler/Resources/views/logs.html.php b/src/Symfony/Component/ErrorHandler/Resources/views/logs.html.php index f886200fb3b5b..bd2dbe2feebd1 100644 --- a/src/Symfony/Component/ErrorHandler/Resources/views/logs.html.php +++ b/src/Symfony/Component/ErrorHandler/Resources/views/logs.html.php @@ -17,7 +17,7 @@ $status = 'warning'; } else { $severity = 0; - if (($exception = $log['context']['exception'] ?? null) instanceof \ErrorException) { + if (($exception = $log['context']['exception'] ?? null) instanceof \ErrorException || $exception instanceof \Symfony\Component\ErrorHandler\Exception\SilencedErrorContext) { $severity = $exception->getSeverity(); } $status = \E_DEPRECATED === $severity || \E_USER_DEPRECATED === $severity ? 'warning' : 'normal'; diff --git a/src/Symfony/Component/ErrorHandler/ThrowableUtils.php b/src/Symfony/Component/ErrorHandler/ThrowableUtils.php index d6efcbefa0cc0..18d04988ac342 100644 --- a/src/Symfony/Component/ErrorHandler/ThrowableUtils.php +++ b/src/Symfony/Component/ErrorHandler/ThrowableUtils.php @@ -11,14 +11,19 @@ namespace Symfony\Component\ErrorHandler; +use Symfony\Component\ErrorHandler\Exception\SilencedErrorContext; + /** * @internal */ class ThrowableUtils { - public static function getSeverity(\Throwable $throwable): int + /** + * @param SilencedErrorContext|\Throwable + */ + public static function getSeverity($throwable): int { - if ($throwable instanceof \ErrorException) { + if ($throwable instanceof \ErrorException || $throwable instanceof SilencedErrorContext) { return $throwable->getSeverity(); } From 9f6a9bbda20369bfae476c49f8475a618fd65554 Mon Sep 17 00:00:00 2001 From: Mamikon Arakelyan Date: Thu, 24 Jun 2021 01:43:12 +0400 Subject: [PATCH 39/83] [Security]Added missing translations for Armenian (hy) --- .../Security/Core/Resources/translations/security.hy.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.hy.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.hy.xlf index da63a0047c664..459c292be31a6 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.hy.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.hy.xlf @@ -36,7 +36,7 @@ No session available, it either timed out or cookies are not enabled. - No session available, it either timed out or cookies are not enabled. + Հասանելի սեսիա չկա, կամ այն սպառվել է կամ cookie-ները անջատված են: No token could be found. From ad1f057ce208b507c18fbcd28907a0cf70ae1c6a Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Fri, 11 Jun 2021 05:58:59 +0000 Subject: [PATCH 40/83] Public responses without lifetime should not remove lifetime for the resulting response --- .../HttpCache/ResponseCacheStrategy.php | 29 +++++++++++++++---- .../HttpCache/ResponseCacheStrategyTest.php | 26 ++++++++++++++++- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php index 47bbbb74317e8..17a7e87fe95e1 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php @@ -81,14 +81,15 @@ public function add(Response $response) return; } + $isHeuristicallyCacheable = $response->headers->hasCacheControlDirective('public'); $maxAge = $response->headers->hasCacheControlDirective('max-age') ? (int) $response->headers->getCacheControlDirective('max-age') : null; - $this->storeRelativeAgeDirective('max-age', $maxAge, $age); + $this->storeRelativeAgeDirective('max-age', $maxAge, $age, $isHeuristicallyCacheable); $sharedMaxAge = $response->headers->hasCacheControlDirective('s-maxage') ? (int) $response->headers->getCacheControlDirective('s-maxage') : $maxAge; - $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $age); + $this->storeRelativeAgeDirective('s-maxage', $sharedMaxAge, $age, $isHeuristicallyCacheable); $expires = $response->getExpires(); $expires = null !== $expires ? (int) $expires->format('U') - (int) $response->getDate()->format('U') : null; - $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0); + $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0, $isHeuristicallyCacheable); } /** @@ -199,11 +200,29 @@ private function willMakeFinalResponseUncacheable(Response $response): bool * we have to subtract the age so that the value is normalized for an age of 0. * * If the value is lower than the currently stored value, we update the value, to keep a rolling - * minimal value of each instruction. If the value is NULL, the directive will not be set on the final response. + * minimal value of each instruction. + * + * If the value is NULL and the isHeuristicallyCacheable parameter is false, the directive will + * not be set on the final response. In this case, not all responses had the directive set and no + * value can be found that satisfies the requirements of all responses. The directive will be dropped + * from the final response. + * + * If the isHeuristicallyCacheable parameter is true, however, the current response has been marked + * as cacheable in a public (shared) cache, but did not provide an explicit lifetime that would serve + * as an upper bound. In this case, we can proceed and possibly keep the directive on the final response. */ - private function storeRelativeAgeDirective(string $directive, ?int $value, int $age) + private function storeRelativeAgeDirective(string $directive, ?int $value, int $age, bool $isHeuristicallyCacheable) { if (null === $value) { + if ($isHeuristicallyCacheable) { + /* + * See https://datatracker.ietf.org/doc/html/rfc7234#section-4.2.2 + * This particular response does not require maximum lifetime; heuristics might be applied. + * Other responses, however, might have more stringent requirements on maximum lifetime. + * So, return early here so that the final response can have the more limiting value set. + */ + return; + } $this->ageDirectives[$directive] = false; } diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php index 4875870eef34c..4d56b2428583c 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php @@ -370,7 +370,7 @@ public function cacheControlMergingProvider() ]; yield 'merge max-age and s-maxage' => [ - ['public' => true, 's-maxage' => '60', 'max-age' => null], + ['public' => true, 'max-age' => '60'], ['public' => true, 's-maxage' => 3600], [ ['public' => true, 'max-age' => 60], @@ -393,6 +393,30 @@ public function cacheControlMergingProvider() ], ]; + yield 'public subresponse without lifetime does not remove lifetime for main response' => [ + ['public' => true, 's-maxage' => '30', 'max-age' => null], + ['public' => true, 's-maxage' => '30'], + [ + ['public' => true], + ], + ]; + + yield 'lifetime for subresponse is kept when main response has no lifetime' => [ + ['public' => true, 'max-age' => '30'], + ['public' => true], + [ + ['public' => true, 'max-age' => '30'], + ], + ]; + + yield 's-maxage on the subresponse implies public, so the result is public as well' => [ + ['public' => true, 'max-age' => '10', 's-maxage' => null], + ['public' => true, 'max-age' => '10'], + [ + ['max-age' => '30', 's-maxage' => '20'], + ], + ]; + yield 'result is private when combining private responses' => [ ['no-cache' => false, 'must-revalidate' => false, 'private' => true], ['s-maxage' => 60, 'private' => true], From 7685645b463e6a8f8ffef486e555f6ac48dcb362 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 24 Jun 2021 10:08:16 +0200 Subject: [PATCH 41/83] [DI] fix fixture --- .../DependencyInjection/Tests/Fixtures/Prototype/Foo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php index 862e1b9cd9cec..1544dfd12c670 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Prototype/Foo.php @@ -4,7 +4,7 @@ class Foo implements FooInterface, Sub\BarInterface { - public function __construct($bar = null, iterable $foo) + public function __construct($bar = null, iterable $foo = null) { } From 0c97c8ac84f6dddd847b01de1b9db54f04280d7f Mon Sep 17 00:00:00 2001 From: Ana Raro Date: Thu, 24 Jun 2021 11:04:45 +0100 Subject: [PATCH 42/83] (#41826) missing translations for portuguese --- .../Validator/Resources/translations/validators.pt.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 71bdaf8bc19f1..5caa804dd1712 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Este valor não é um Número Internacional de Identificação de Segurança (ISIN) válido. + + This value should be a valid expression. + Este valor deve ser uma expressão válida. + From b244cc994eecd4573eeae87663c4faa212bb8714 Mon Sep 17 00:00:00 2001 From: Storkeus Date: Thu, 24 Jun 2021 21:15:04 +0200 Subject: [PATCH 43/83] Add missing translation for Polish --- .../Validator/Resources/translations/validators.pl.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index 561a7d40500b5..0881f3167293a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Ta wartość nie jest prawidłowym Międzynarodowym Numerem Identyfikacyjnym Papierów Wartościowych (ISIN). + + This value should be a valid expression. + Ta wartość powinna być prawidłowym wyrażeniem. + From 52807cbdfc8545350d96a7e903250cbda973e7ce Mon Sep 17 00:00:00 2001 From: Marcos Rezende Date: Fri, 25 Jun 2021 13:42:34 +0100 Subject: [PATCH 44/83] [Validator] Missing translations for Brazilian Portuguese (pt_BR) --- .../Validator/Resources/translations/validators.pt_BR.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index 2dbd009ccdd53..c6297ca90157a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Este valor não é um Número de Identificação de Títulos Internacionais (ISIN) válido. + + This value should be a valid expression. + Este valor deve ser uma expressão válida. + From e89b823c12fac5d4410dfdf0b47aace5faae8c86 Mon Sep 17 00:00:00 2001 From: Petr Duda Date: Fri, 25 Jun 2021 18:48:41 +0200 Subject: [PATCH 45/83] [Validator] Add missing Czech translations --- .../Validator/Resources/translations/validators.cs.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index 0cf53015addb6..4d990e4d49358 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Tato hodnota není platné mezinárodní identifikační číslo cenného papíru (ISIN). + + This value should be a valid expression. + Tato hodnota musí být platný výraz. + From e52ecc759017db010cf16991cf845a75a487a53b Mon Sep 17 00:00:00 2001 From: zors1 <78965690+zors1@users.noreply.github.com> Date: Fri, 25 Jun 2021 21:33:17 +0300 Subject: [PATCH 46/83] [Validator] Add missing translations for Russian --- .../Validator/Resources/translations/validators.ru.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 516fa2cf2a8bb..fe2bd4ef91c3b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Значение не является корректным международным идентификационным номером ценных бумаг (ISIN). + + This value should be a valid expression. + Это значение должно быть корректным выражением. + From 69781f764b2ef79d31038decf001e788e6b5b423 Mon Sep 17 00:00:00 2001 From: Vasilij Dusko Date: Sat, 26 Jun 2021 06:12:56 +0300 Subject: [PATCH 47/83] * validators.lt.xlf - added missing 100 message --- .../Validator/Resources/translations/validators.lt.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index fef436539f296..5f0e680cc0872 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Ši reišmė neatitinka tarptautinio vertybinių popierių identifikavimo numerio formato (ISIN). + + This value should be a valid expression. + Ši vertė turėtų būti teisinga išraiška. + From b91d488ce60a29d3562043de1eaf978135204c07 Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" Date: Thu, 24 Jun 2021 19:27:39 +0100 Subject: [PATCH 48/83] Closing tag typo --- .../DependencyInjection/Fixtures/xml/logout_delete_cookies.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml index 34b4a429e5fc3..6b4f60560e64f 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml @@ -18,5 +18,5 @@ - + From 6713ab3291b3ce41eb7ab5d702000239a460c1e7 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 26 Jun 2021 13:19:39 +0200 Subject: [PATCH 49/83] [#41846] Revert change in closing tag --- .../DependencyInjection/Fixtures/xml/logout_delete_cookies.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml index 6b4f60560e64f..34b4a429e5fc3 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml @@ -18,5 +18,5 @@ - + From ff0747b6853c249e3fa425b0079726f159ef7ef5 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 26 Jun 2021 13:20:35 +0200 Subject: [PATCH 50/83] [#41846] Fix typo in opening tag --- .../DependencyInjection/Fixtures/xml/logout_delete_cookies.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml index 78fdc86f8d04f..e817b48901311 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/logout_delete_cookies.xml @@ -8,7 +8,7 @@ http://symfony.com/schema/dic/security https://symfony.com/schema/dic/security/security-1.0.xsd"> - + From b8182a8eccd57bf3f4f771a941b6faafd7516b5c Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 10 Jun 2021 22:12:04 +0200 Subject: [PATCH 51/83] PHPUnit on GitHub Actions --- .github/workflows/tests.yml | 98 +++++++++++++++---- .travis.yml | 50 ++-------- .../VarExporter/Tests/VarExporterTest.php | 18 ++-- 3 files changed, 100 insertions(+), 66 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4b4f0ad84a048..c5233c0c11a8a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -77,12 +77,19 @@ jobs: entrypoint: /bin/bash args: -c "(/opt/bitnami/openldap/bin/ldapwhoami -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony||sleep 5) && /opt/bitnami/openldap/bin/ldapadd -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/fixtures.ldif && /opt/bitnami/openldap/bin/ldapdelete -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony cn=a,ou=users,dc=symfony,dc=com" + - name: Detect Symfony version + id: symfony-versions + run: | + echo "::set-output name=symfony-major-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" + echo "::set-output name=symfony-minor-version::$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" + echo "::set-output name=symfony-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+').$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" + - name: Configure composer run: | COMPOSER_HOME="$(composer config home)" - composer self-update ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV + + echo "COMPOSER_ROOT_VERSION=${{ steps.symfony-versions.outputs.symfony-version }}.x-dev" >> $GITHUB_ENV - name: Install dependencies run: | @@ -115,41 +122,82 @@ jobs: # sudo rm -rf .phpunit # [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit - nightly: - name: PHPUnit on PHP nightly + phpunit: + name: PHPUnit runs-on: Ubuntu-20.04 + env: + extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis + EXCLUDE_GROUPS: benchmark,intl-data,tty,integration + + strategy: + matrix: + php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + fail-fast: false + steps: - name: Checkout uses: actions/checkout@v2 + - name: Configure extensions + if: "${{ matrix.php == '8.0' }}" + # TODO: memcached is excluded because of compatibility issues with PHP 8 + run: echo "extensions=amqp,apcu,igbinary,intl,mbstring,:memcached,mongodb,redis" >> $GITHUB_ENV + + - name: Configure extensions + if: "${{ matrix.php == '8.1' }}" + # Test on PHP 8.1 with bundled extensions only and allow tests to fail for now. + run: | + echo "extensions=mbstring" >> $GITHUB_ENV + echo "ALLOW_FAILURE=yes" >> $GITHUB_ENV + - name: Setup PHP uses: shivammathur/setup-php@v2 with: coverage: "none" - ini-values: "memory_limit=-1" - php-version: "8.1" + ini-values: date.timezone=Europe/Paris,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,apc.enable_cli=1 + php-version: "${{ matrix.php }}" + extensions: "${{ env.extensions }}" + tools: flex + + - name: Fake PHP version + if: "${{ matrix.php == '8.1' }}" + run: composer config platform.php 8.0.99 + + - name: Detect Symfony version + id: symfony-versions + run: | + echo "::set-output name=symfony-major-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" + echo "::set-output name=symfony-minor-version::$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" + echo "::set-output name=symfony-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+').$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - name: Configure composer run: | COMPOSER_HOME="$(composer config home)" - composer self-update ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV + + echo 'COMPOSER_ROOT_VERSION=${{ steps.symfony-versions.outputs.symfony-version }}.x-dev' >> $GITHUB_ENV + echo 'SYMFONY_REQUIRE=>=${{ steps.symfony-versions.outputs.symfony-version }}' >> $GITHUB_ENV - name: Install dependencies run: | - echo "::group::fake PHP version" - composer config platform.php 8.0.99 - echo "::group::Adjust dependencies" - composer require --dev --no-update masterminds/html5:~2.7.5@dev echo "::group::composer update" + composer require --dev --no-update masterminds/html5:~2.7.5@dev composer update --no-progress --ansi echo "::endgroup::" echo "::group::install phpunit" ./phpunit install echo "::endgroup::" + - name: Patch return types + if: "${{ matrix.php == '8.0' }}" + run: | + sed -i 's/"\*\*\/Tests\/"//' composer.json + composer install --optimize-autoloader + SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php + SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php # ensure the script is idempotent + echo EXCLUDE_GROUPS="$EXCLUDE_GROUPS,legacy" >> $GITHUB_ENV + - name: Run tests run: | _run_tests() { @@ -157,17 +205,33 @@ jobs: echo "::group::$1" # Run the tests - ./phpunit --colors=always --exclude-group tty,benchmark,intl-data ./$1 2>&1 || ok=1 - echo ::endgroup:: + ./phpunit --colors=always --exclude-group $EXCLUDE_GROUPS ./$1 2>&1 || ok=1 + + echo "" + echo "::endgroup::" if [ $ok -ne 0 ]; then echo "::error::$1 failed" fi - # Make the tests always pass because we don't want the build to fail (yet). - return 0 - #return $ok + if [ "$ALLOW_FAILURE" = "yes" ]; then + # Make the tests always pass because we don't want the build to fail (yet). + return 0 + fi + + return $ok } export -f _run_tests find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -print0 | xargs -0 -n1 dirname | sort | parallel _run_tests + + - name: Run tests with SIGCHLD enabled PHP + if: "${{ matrix.php == '7.1' }}" + run: | + mkdir build + cd build + wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-pcntl-sigchild.tar.bz2 + tar -xjf php-7.1.3-pcntl-sigchild.tar.bz2 + cd .. + + ./build/php/bin/php ./phpunit --colors=always src/Symfony/Component/Process diff --git a/.travis.yml b/.travis.yml index d0dd9bb830613..bdb4861074d66 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,8 +24,6 @@ env: matrix: include: - - php: 7.1 - env: php_extra="7.2 7.3 8.0" - php: 7.4 env: deps=high - php: 8.0 @@ -109,22 +107,13 @@ before_install: } export -f tpecl - - | - # Install sigchild-enabled PHP to test the Process component on the lowest PHP matrix line - if [[ ! $deps && $TRAVIS_PHP_VERSION = ${MIN_PHP%.*} && ! -d php-$MIN_PHP/sapi ]]; then - wget http://php.net/get/php-$MIN_PHP.tar.bz2/from/this/mirror -O - | tar -xj && - (cd php-$MIN_PHP && ./configure --enable-sigchild --enable-pcntl && make -j2) - fi - - | # php.ini configuration ( - for PHP in $TRAVIS_PHP_VERSION $php_extra; do - ([[ $PHP != 7.4 ]] && phpenv global $PHP 2>/dev/null) || (cd / && wget https://storage.googleapis.com/travis-ci-language-archives/php/binaries/ubuntu/18.04/x86_64/php-$PHP.tar.bz2 -O - | tar -xj) & - done + ([[ $TRAVIS_PHP_VERSION != 7.4 ]] && phpenv global $TRAVIS_PHP_VERSION 2>/dev/null) || (cd / && wget https://storage.googleapis.com/travis-ci-language-archives/php/binaries/ubuntu/18.04/x86_64/php-$TRAVIS_PHP_VERSION.tar.bz2 -O - | tar -xj) & wait ) - for PHP in $TRAVIS_PHP_VERSION $php_extra; do + for PHP in $TRAVIS_PHP_VERSION; do INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini echo date.timezone = Europe/Paris >> $INI echo memory_limit = -1 >> $INI @@ -140,7 +129,7 @@ before_install: - | # Install extra PHP extensions - for PHP in $TRAVIS_PHP_VERSION $php_extra; do + for PHP in $TRAVIS_PHP_VERSION; do export PHP=$PHP phpenv global $PHP INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini @@ -203,12 +192,6 @@ install: export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) fi - - | - # Skip the phpunit-bridge on bugfix-branches when $deps is empty - if [[ ! $deps && $SYMFONY_VERSION != $SYMFONY_FEATURE_BRANCH ]]; then - export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort) - fi - - | # Install symfony/flex if [[ $deps = low ]]; then @@ -223,7 +206,7 @@ install: [[ $deps = high && $SYMFONY_VERSION = *.4 ]] && export LEGACY=,legacy export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev - if [[ $deps ]]; then mv composer.json.phpunit composer.json; fi + mv composer.json.phpunit composer.json - | # phpinfo @@ -234,7 +217,7 @@ install: } export -f phpinfo - for PHP in $TRAVIS_PHP_VERSION $php_extra; do + for PHP in $TRAVIS_PHP_VERSION; do tfold phpinfo phpinfo $PHP done @@ -249,7 +232,7 @@ install: fi phpenv global $PHP rm vendor/composer/package-versions-deprecated -Rf - ([[ $deps ]] && cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb) + cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb tfold 'composer update' $COMPOSER_UP tfold 'phpunit install' ./phpunit install if [[ $deps = high ]]; then @@ -274,28 +257,9 @@ install: [[ ! $X ]] || (exit 1) elif [[ $deps = low ]]; then echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT_X'" - else - if [[ $PHP = 8.0* ]]; then - # add return types before running the test suite - sed -i 's/"\*\*\/Tests\/"//' composer.json - composer install --optimize-autoloader - SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php - SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php # ensure the script is idempotent - PHPUNIT_X="$PHPUNIT_X,legacy" - fi - - echo "$COMPONENTS" | parallel --gnu "tfold {} $PHPUNIT_X {}" - - tfold src/Symfony/Component/Console.tty $PHPUNIT src/Symfony/Component/Console --group tty - tfold src/Symfony/Bridge/Twig.tty $PHPUNIT src/Symfony/Bridge/Twig --group tty - - if [[ $PHP = ${MIN_PHP%.*} ]]; then - export PHP=$MIN_PHP - tfold src/Symfony/Component/Process.sigchild SYMFONY_DEPRECATIONS_HELPER=weak php-$MIN_PHP/sapi/cli/php ./phpunit --colors=always src/Symfony/Component/Process/ - fi fi } export -f run_tests script: - echo $TRAVIS_PHP_VERSION $php_extra | xargs -n1 bash -c '( Date: Sat, 26 Jun 2021 11:34:46 -0700 Subject: [PATCH 52/83] [Validator] Added missing spanish translation --- .../Validator/Resources/translations/validators.es.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 2c586ca4a2571..c73138b0ee277 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Este valor no es un número de identificación internacional de valores (ISIN) válido. + + This value should be a valid expression. + Este valor debería ser una expresión válida. + From 78745133b39e6d340a300e0e4f79a0b4f8261309 Mon Sep 17 00:00:00 2001 From: Daniel Tiringer Date: Sat, 26 Jun 2021 22:36:12 +0200 Subject: [PATCH 53/83] Add new translation in Hungarian --- .../Validator/Resources/translations/validators.hu.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index acd69a1009c13..a3264d5543af4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Ez az érték nem egy érvényes nemzetközi értékpapír-azonosító szám (ISIN). + + This value should be a valid expression. + Ennek az értéknek érvényes kifejezésnek kell lennie. + From fa5ed19ab8a601f5832605ca57277c3c6147befb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 25 Jun 2021 10:27:06 +0200 Subject: [PATCH 54/83] - --- .appveyor.yml | 2 +- .github/workflows/integration-tests.yml | 119 +++++++++ .github/workflows/intl-data-tests.yml | 4 +- .github/workflows/psalm.yml | 13 +- .github/workflows/tests.yml | 237 ------------------ .github/workflows/unit-tests.yml | 214 ++++++++++++++++ .travis.yml | 161 +----------- .../Handler/MemcachedSessionHandlerTest.php | 10 +- .../Tests/Command/DebugCommandTest.php | 2 +- .../Translation/Test/TranslatorTest.php | 5 +- 10 files changed, 363 insertions(+), 404 deletions(-) create mode 100644 .github/workflows/integration-tests.yml delete mode 100644 .github/workflows/tests.yml create mode 100644 .github/workflows/unit-tests.yml diff --git a/.appveyor.yml b/.appveyor.yml index 5077eea33d60a..38f7468b9a99a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -51,7 +51,7 @@ install: - php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex - git config --global user.email "" - git config --global user.name "Symfony" - - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*'"`) DO (SET SYMFONY_VERSION=%%F) + - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+'"`) DO (SET SYMFONY_VERSION=%%F) - php .github/build-packages.php HEAD^ %SYMFONY_VERSION% src\Symfony\Bridge\PhpUnit - SET "SYMFONY_REQUIRE=>=%SYMFONY_VERSION%" - SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000000000..97946446e959b --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,119 @@ +name: Integration + +on: + push: + pull_request: + +defaults: + run: + shell: bash + +jobs: + + tests: + name: Tests + runs-on: Ubuntu-20.04 + + strategy: + matrix: + php: ['7.1', '8.0'] + + services: + ldap: + image: bitnami/openldap + ports: + - 3389:3389 + env: + LDAP_ADMIN_USERNAME: admin + LDAP_ADMIN_PASSWORD: symfony + LDAP_ROOT: dc=symfony,dc=com + LDAP_PORT_NUMBER: 3389 + LDAP_USERS: a + LDAP_PASSWORDS: a + redis: + image: redis:6.0.0 + ports: + - 6379:6379 + redis-cluster: + image: grokzen/redis-cluster:5.0.4 + ports: + - 7000:7000 + - 7001:7001 + - 7002:7002 + - 7003:7003 + - 7004:7004 + - 7005:7005 + - 7006:7006 + env: + STANDALONE: 1 + redis-sentinel: + image: bitnami/redis-sentinel:6.0 + ports: + - 26379:26379 + env: + REDIS_MASTER_HOST: redis + REDIS_MASTER_SET: redis_sentinel + REDIS_SENTINEL_QUORUM: 1 + memcached: + image: memcached:1.6.5 + ports: + - 11211:11211 + rabbitmq: + image: rabbitmq:3.8.3 + ports: + - 5672:5672 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + coverage: "none" + extensions: "memcached,redis,xsl,ldap" + ini-values: "memory_limit=-1" + php-version: "${{ matrix.php }}" + + - name: Load fixtures + uses: docker://bitnami/openldap + with: + entrypoint: /bin/bash + args: -c "(/opt/bitnami/openldap/bin/ldapwhoami -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony||sleep 5) && /opt/bitnami/openldap/bin/ldapadd -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/fixtures.ldif && /opt/bitnami/openldap/bin/ldapdelete -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony cn=a,ou=users,dc=symfony,dc=com" + + - name: Install dependencies + run: | + COMPOSER_HOME="$(composer config home)" + ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev + echo COMPOSER_ROOT_VERSION=$COMPOSER_ROOT_VERSION >> $GITHUB_ENV + + echo "::group::composer update" + composer update --no-progress --ansi + echo "::endgroup::" + + echo "::group::install phpunit" + ./phpunit install + echo "::endgroup::" + + - name: Run tests + run: ./phpunit --group integration -v + env: + REDIS_HOST: localhost + REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' + REDIS_SENTINEL_HOSTS: 'localhost:26379' + REDIS_SENTINEL_SERVICE: redis_sentinel + MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages + MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages + MEMCACHED_HOST: localhost + LDAP_HOST: localhost + LDAP_PORT: 3389 + + #- name: Run HTTP push tests + # if: matrix.php == '8.0' + # run: | + # [ -d .phpunit ] && mv .phpunit .phpunit.bak + # wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz -O - | tar xz && mv vulcain /usr/local/bin + # docker run --rm -e COMPOSER_ROOT_VERSION -v $(pwd):/app -v $(which composer):/usr/local/bin/composer -v $(which vulcain):/usr/local/bin/vulcain -w /app php:8.0-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push + # sudo rm -rf .phpunit + # [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit diff --git a/.github/workflows/intl-data-tests.yml b/.github/workflows/intl-data-tests.yml index 0ca0322281448..f695bca201426 100644 --- a/.github/workflows/intl-data-tests.yml +++ b/.github/workflows/intl-data-tests.yml @@ -1,4 +1,4 @@ -name: Intl data tests +name: Intl data on: push: @@ -14,7 +14,7 @@ defaults: jobs: tests: - name: Tests (intl-data) + name: Tests runs-on: Ubuntu-20.04 steps: diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 3a2ec919a49ad..f5807849e6f3e 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -13,7 +13,7 @@ jobs: runs-on: Ubuntu-20.04 steps: - - name: Set up PHP + - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.0' @@ -29,22 +29,19 @@ jobs: - name: Checkout PR uses: actions/checkout@v2 - - name: Configure composer + - name: Install dependencies run: | COMPOSER_HOME="$(composer config home)" ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - echo "COMPOSER_ROOT_VERSION=$(grep -m1 SYMFONY_VERSION .travis.yml | grep -o '[0-9.x]*').x-dev" >> $GITHUB_ENV - - - name: Install Psalm - run: | - echo "::group::modify composer.json" + export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev composer remove --no-update --no-interaction symfony/phpunit-bridge composer require --no-update psalm/phar phpunit/phpunit:^9.5 php-http/discovery psr/event-dispatcher - echo "::endgroup::" + echo "::group::composer update" composer update --no-progress --ansi git checkout composer.json echo "::endgroup::" + ./vendor/bin/psalm.phar --version - name: Generate Psalm baseline diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index c5233c0c11a8a..0000000000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,237 +0,0 @@ -name: Tests - -on: - push: - pull_request: - -jobs: - - integration: - name: Integration - runs-on: Ubuntu-20.04 - - strategy: - matrix: - php: ['7.1', '8.0'] - - services: - ldap: - image: bitnami/openldap - ports: - - 3389:3389 - env: - LDAP_ADMIN_USERNAME: admin - LDAP_ADMIN_PASSWORD: symfony - LDAP_ROOT: dc=symfony,dc=com - LDAP_PORT_NUMBER: 3389 - LDAP_USERS: a - LDAP_PASSWORDS: a - redis: - image: redis:6.0.0 - ports: - - 6379:6379 - redis-cluster: - image: grokzen/redis-cluster:5.0.4 - ports: - - 7000:7000 - - 7001:7001 - - 7002:7002 - - 7003:7003 - - 7004:7004 - - 7005:7005 - - 7006:7006 - env: - STANDALONE: 1 - redis-sentinel: - image: bitnami/redis-sentinel:6.0 - ports: - - 26379:26379 - env: - REDIS_MASTER_HOST: redis - REDIS_MASTER_SET: redis_sentinel - REDIS_SENTINEL_QUORUM: 1 - memcached: - image: memcached:1.6.5 - ports: - - 11211:11211 - rabbitmq: - image: rabbitmq:3.8.3 - ports: - - 5672:5672 - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - coverage: "none" - extensions: "memcached,redis,xsl,ldap" - ini-values: "memory_limit=-1" - php-version: "${{ matrix.php }}" - - - name: Load fixtures - uses: docker://bitnami/openldap - with: - entrypoint: /bin/bash - args: -c "(/opt/bitnami/openldap/bin/ldapwhoami -h localhost:3389 -D cn=admin,dc=symfony,dc=com -w symfony||sleep 5) && /opt/bitnami/openldap/bin/ldapadd -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony -f src/Symfony/Component/Ldap/Tests/Fixtures/data/fixtures.ldif && /opt/bitnami/openldap/bin/ldapdelete -h ldap:3389 -D cn=admin,dc=symfony,dc=com -w symfony cn=a,ou=users,dc=symfony,dc=com" - - - name: Detect Symfony version - id: symfony-versions - run: | - echo "::set-output name=symfony-major-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - echo "::set-output name=symfony-minor-version::$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - echo "::set-output name=symfony-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+').$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - - - name: Configure composer - run: | - COMPOSER_HOME="$(composer config home)" - ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - - echo "COMPOSER_ROOT_VERSION=${{ steps.symfony-versions.outputs.symfony-version }}.x-dev" >> $GITHUB_ENV - - - name: Install dependencies - run: | - echo "::group::composer update" - composer update --no-progress --ansi - echo "::endgroup::" - echo "::group::install phpunit" - ./phpunit install - echo "::endgroup::" - - - name: Run tests - run: ./phpunit --group integration -v - env: - REDIS_HOST: localhost - REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' - REDIS_SENTINEL_HOSTS: 'localhost:26379' - REDIS_SENTINEL_SERVICE: redis_sentinel - MESSENGER_REDIS_DSN: redis://127.0.0.1:7006/messages - MESSENGER_AMQP_DSN: amqp://localhost/%2f/messages - MEMCACHED_HOST: localhost - LDAP_HOST: localhost - LDAP_PORT: 3389 - - #- name: Run HTTP push tests - # if: matrix.php == '8.0' - # run: | - # [ -d .phpunit ] && mv .phpunit .phpunit.bak - # wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/vulcain_0.1.3_Linux_x86_64.tar.gz -O - | tar xz && mv vulcain /usr/local/bin - # docker run --rm -e COMPOSER_ROOT_VERSION -v $(pwd):/app -v $(which composer):/usr/local/bin/composer -v $(which vulcain):/usr/local/bin/vulcain -w /app php:8.0-alpine ./phpunit src/Symfony/Component/HttpClient/Tests/CurlHttpClientTest.php --filter testHttp2Push - # sudo rm -rf .phpunit - # [ -d .phpunit.bak ] && mv .phpunit.bak .phpunit - - phpunit: - name: PHPUnit - runs-on: Ubuntu-20.04 - - env: - extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis - EXCLUDE_GROUPS: benchmark,intl-data,tty,integration - - strategy: - matrix: - php: ['7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] - fail-fast: false - - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Configure extensions - if: "${{ matrix.php == '8.0' }}" - # TODO: memcached is excluded because of compatibility issues with PHP 8 - run: echo "extensions=amqp,apcu,igbinary,intl,mbstring,:memcached,mongodb,redis" >> $GITHUB_ENV - - - name: Configure extensions - if: "${{ matrix.php == '8.1' }}" - # Test on PHP 8.1 with bundled extensions only and allow tests to fail for now. - run: | - echo "extensions=mbstring" >> $GITHUB_ENV - echo "ALLOW_FAILURE=yes" >> $GITHUB_ENV - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - coverage: "none" - ini-values: date.timezone=Europe/Paris,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,apc.enable_cli=1 - php-version: "${{ matrix.php }}" - extensions: "${{ env.extensions }}" - tools: flex - - - name: Fake PHP version - if: "${{ matrix.php == '8.1' }}" - run: composer config platform.php 8.0.99 - - - name: Detect Symfony version - id: symfony-versions - run: | - echo "::set-output name=symfony-major-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - echo "::set-output name=symfony-minor-version::$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - echo "::set-output name=symfony-version::$(grep "const MAJOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+').$(grep "const MINOR_VERSION =" ./src/Symfony/Component/HttpKernel/Kernel.php | egrep -o '[0-9]+')" - - - name: Configure composer - run: | - COMPOSER_HOME="$(composer config home)" - ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - - echo 'COMPOSER_ROOT_VERSION=${{ steps.symfony-versions.outputs.symfony-version }}.x-dev' >> $GITHUB_ENV - echo 'SYMFONY_REQUIRE=>=${{ steps.symfony-versions.outputs.symfony-version }}' >> $GITHUB_ENV - - - name: Install dependencies - run: | - echo "::group::composer update" - composer require --dev --no-update masterminds/html5:~2.7.5@dev - composer update --no-progress --ansi - echo "::endgroup::" - echo "::group::install phpunit" - ./phpunit install - echo "::endgroup::" - - - name: Patch return types - if: "${{ matrix.php == '8.0' }}" - run: | - sed -i 's/"\*\*\/Tests\/"//' composer.json - composer install --optimize-autoloader - SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php - SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php # ensure the script is idempotent - echo EXCLUDE_GROUPS="$EXCLUDE_GROUPS,legacy" >> $GITHUB_ENV - - - name: Run tests - run: | - _run_tests() { - ok=0 - echo "::group::$1" - - # Run the tests - ./phpunit --colors=always --exclude-group $EXCLUDE_GROUPS ./$1 2>&1 || ok=1 - - echo "" - echo "::endgroup::" - - if [ $ok -ne 0 ]; then - echo "::error::$1 failed" - fi - - if [ "$ALLOW_FAILURE" = "yes" ]; then - # Make the tests always pass because we don't want the build to fail (yet). - return 0 - fi - - return $ok - } - export -f _run_tests - - find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -print0 | xargs -0 -n1 dirname | sort | parallel _run_tests - - - name: Run tests with SIGCHLD enabled PHP - if: "${{ matrix.php == '7.1' }}" - run: | - mkdir build - cd build - wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-pcntl-sigchild.tar.bz2 - tar -xjf php-7.1.3-pcntl-sigchild.tar.bz2 - cd .. - - ./build/php/bin/php ./phpunit --colors=always src/Symfony/Component/Process diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000000000..b7fd0de88c307 --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,214 @@ +name: PHPUnit + +on: + push: + pull_request: + +defaults: + run: + shell: bash + +jobs: + + tests: + name: Tests + runs-on: Ubuntu-20.04 + + env: + extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis + + strategy: + matrix: + include: + - php: '7.2' + - php: '8.0' + - php: '7.4' + mode: high-deps + - php: '8.0' + mode: low-deps + - php: '8.1' + mode: experimental + fail-fast: false + + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 2 + + - name: Configure for PHP 8.1 + if: "${{ matrix.php == '8.1' }}" + run: | + echo "extensions=mbstring" >> $GITHUB_ENV + composer config platform.php 8.0.99 + composer require --dev --no-update masterminds/html5:~2.7.5@dev + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + coverage: "none" + ini-values: date.timezone=Europe/Paris,memory_limit=-1,default_socket_timeout=10,session.gc_probability=0,apc.enable_cli=1 + php-version: "${{ matrix.php }}" + extensions: "${{ env.extensions }}" + tools: flex + + - name: Configure environment + run: | + git config --global user.email "" + git config --global user.name "Symfony" + git config --global init.defaultBranch main + + COMPOSER_HOME="$(composer config home)" + ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + + echo COLUMNS=120 >> $GITHUB_ENV + echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV + echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV + + SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) + SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+') + SYMFONY_FEATURE_BRANCH=$(curl -s https://flex.symfony.com/versions.json | jq -r '."dev-name"') + + # Install the phpunit-bridge from a PR if required + # + # To run a PR with a patched phpunit-bridge, first submit the patch for the + # phpunit-bridge as a separate PR against the next feature-branch then + # uncomment and update the following line with that PR number + #SYMFONY_PHPUNIT_BRIDGE_PR=32886 + + if [[ $SYMFONY_PHPUNIT_BRIDGE_PR ]]; then + git fetch --depth=2 origin refs/pull/$SYMFONY_PHPUNIT_BRIDGE_PR/head + git rm -rq src/Symfony/Bridge/PhpUnit + git checkout -q FETCH_HEAD -- src/Symfony/Bridge/PhpUnit + SYMFONY_PHPUNIT_BRIDGE_REF=$(curl -s https://api.github.com/repos/symfony/symfony/pulls/$SYMFONY_PHPUNIT_BRIDGE_PR | jq -r .base.ref) + sed -i 's/"symfony\/phpunit-bridge": ".*"/"symfony\/phpunit-bridge": "'$SYMFONY_PHPUNIT_BRIDGE_REF'.x@dev"/' composer.json + rm -rf .phpunit + fi + + # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components + if [[ ! "${{ matrix.mode }}" = *-deps ]]; then + php .github/build-packages.php HEAD^ $SYMFONY_VERSION src/Symfony/Bridge/PhpUnit + else + echo SYMFONY_DEPRECATIONS_HELPER=weak >> $GITHUB_ENV + cp composer.json composer.json.orig + echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json + php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n') + mv composer.json composer.json.phpunit + mv composer.json.orig composer.json + fi + if [[ $SYMFONY_PHPUNIT_BRIDGE_PR ]]; then + git rm -fq -- src/Symfony/Bridge/PhpUnit/composer.json + git diff --staged -- src/Symfony/Bridge/PhpUnit/ | git apply -R --index + fi + + # For the highest branch, in high-deps mode, the version before it is checked out and tested with the locally patched components + if [[ "${{ matrix.mode }}" = high-deps && $SYMFONY_VERSION = $(echo "$SYMFONY_VERSIONS" | tail -n 1 | sed s/.//) ]]; then + echo FLIP='🙃' >> $GITHUB_ENV + SYMFONY_VERSION=$(echo "$SYMFONY_VERSIONS" | grep -FB1 /$SYMFONY_VERSION | head -n 1 | sed s/.//) + git fetch --depth=2 origin $SYMFONY_VERSION + git checkout -m FETCH_HEAD + echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h ') >> $GITHUB_ENV + fi + + # Skip the phpunit-bridge on bugfix-branches when not in *-deps mode + if [[ ! "${{ matrix.mode }}" = *-deps && $SYMFONY_VERSION != $SYMFONY_FEATURE_BRANCH ]]; then + echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h ') >> $GITHUB_ENV + else + echo COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h ') >> $GITHUB_ENV + fi + + # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one + [[ "${{ matrix.mode }}" = high-deps && $SYMFONY_VERSION = *.4 ]] && echo LEGACY=,legacy >> $GITHUB_ENV || true + + echo SYMFONY_VERSION=$SYMFONY_VERSION >> $GITHUB_ENV + echo COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev >> $GITHUB_ENV + echo SYMFONY_REQUIRE=">=$([ '${{ matrix.mode }}' = low-deps ] && echo 3.4 || echo $SYMFONY_VERSION)" >> $GITHUB_ENV + [[ "${{ matrix.mode }}" = *-deps ]] && mv composer.json.phpunit composer.json || true + + - name: Install dependencies + run: | + echo "::group::composer update" + $COMPOSER_UP + echo "::endgroup::" + + echo "::group::install phpunit" + ./phpunit install + echo "::endgroup::" + + - name: Patch return types + if: "${{ matrix.php == '8.0' && ! matrix.mode }}" + run: | + sed -i 's/"\*\*\/Tests\/"//' composer.json + composer install --optimize-autoloader + SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php + SYMFONY_PATCH_TYPE_DECLARATIONS=force=1 php .github/patch-types.php # ensure the script is idempotent + echo PHPUNIT="$PHPUNIT,legacy" >> $GITHUB_ENV + + - name: Run tests + run: | + _run_tests() { + local ok=0 + local title="$1 $FLIP" + local start=$(date -u +%s) + OUTPUT=$(bash -xc "$2" 2>&1) || ok=1 + local end=$(date -u +%s) + + if [[ $ok -ne 0 ]]; then + printf "\n%-70s%10s\n" $title $(($end-$start))s + echo "$OUTPUT" + echo -e "\n\\e[41mKO\\e[0m $title\\n" + else + printf "::group::%-68s%10s\n" $title $(($end-$start))s + echo "$OUTPUT" + echo -e "\n\\e[32mOK\\e[0m $title\\n\\n::endgroup::" + fi + + [[ "${{ matrix.mode }}" = experimental ]] || (exit $ok) + } + export -f _run_tests + + if [[ ! "${{ matrix.mode }}" = *-deps ]]; then + echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} '$PHPUNIT {}'" + + exit 0 + fi + + (cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb) + + if [[ "${{ matrix.mode }}" = low-deps ]]; then + echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT'" + + exit 0 + fi + + # matrix.mode = high-deps + echo "$COMPONENTS" | xargs -n1 | parallel -j +3 "_run_tests {} 'cd {} && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1 + + (cd src/Symfony/Component/HttpFoundation; mv composer.bak composer.json) + COMPONENTS=$(git diff --name-only src/ | grep composer.json || true) + + if [[ $COMPONENTS && $SYMFONY_VERSION = *.4 ]]; then + export FLIP='🙃' + SYMFONY_VERSION=$(echo $SYMFONY_VERSION | awk '{print $1 - 1}') + echo -e "\\n\\e[33;1mChecking out Symfony $SYMFONY_VERSION and running tests with patched components as deps\\e[0m" + export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev + export SYMFONY_REQUIRE=">=$SYMFONY_VERSION" + git fetch --depth=2 origin $SYMFONY_VERSION + git checkout -m FETCH_HEAD + COMPONENTS=$(echo "$COMPONENTS" | xargs dirname | xargs -n1 -I{} bash -c "[ -e '{}/phpunit.xml.dist' ] && echo '{}'" | sort || true) + (cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) + [[ ! $COMPONENTS ]] || echo "$COMPONENTS" | parallel -j +3 "_run_tests {} 'cd {} && rm composer.lock vendor/ -Rf && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1 + fi + + [[ ! $X ]] || (exit 1) + + - name: Run tests with SIGCHLD enabled PHP + if: "${{ matrix.php == '7.1' }}" + run: | + mkdir build + cd build + wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-pcntl-sigchild.tar.bz2 + tar -xjf php-7.1.3-pcntl-sigchild.tar.bz2 + cd .. + + ./build/php/bin/php ./phpunit --colors=always src/Symfony/Component/Process diff --git a/.travis.yml b/.travis.yml index bdb4861074d66..f6abaa2eadd8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,37 +3,22 @@ language: php dist: bionic git: - depth: 2 + depth: 1 addons: apt_packages: - parallel - - language-pack-fr-base - zookeeperd - libzookeeper-mt-dev - - librabbitmq-dev - - libsodium-dev - - libtidy-dev - -env: - global: - - SYMFONY_VERSION=4.4 - - MIN_PHP=7.1.3 - - SYMFONY_PROCESS_PHP_TEST_BINARY=~/.phpenv/shims/php - - SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 matrix: include: - - php: 7.4 - env: deps=high - - php: 8.0 - env: deps=low + - php: 7.3 fast_finish: true cache: directories: - .phpunit - - php-$MIN_PHP - ~/php-ext before_install: @@ -43,14 +28,6 @@ before_install: stty cols 120 sudo sed -i 's/127\.0\.1\.1 localhost/127.0.0.1 localhost/' /etc/hosts cp .github/composer-config.json "$(composer config home)/config.json" - git config --global user.email "" - git config --global user.name "Symfony" - export PHPUNIT=$(readlink -f ./phpunit) - export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data" - export COMPOSER_UP='composer update --no-progress --ansi' - export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) - export SYMFONY_FEATURE_BRANCH=$(curl -s https://flex.symfony.com/versions.json | jq -r '."dev-name"') - export SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) nanoseconds () { local cmd="date" @@ -109,11 +86,7 @@ before_install: - | # php.ini configuration - ( - ([[ $TRAVIS_PHP_VERSION != 7.4 ]] && phpenv global $TRAVIS_PHP_VERSION 2>/dev/null) || (cd / && wget https://storage.googleapis.com/travis-ci-language-archives/php/binaries/ubuntu/18.04/x86_64/php-$TRAVIS_PHP_VERSION.tar.bz2 -O - | tar -xj) & - wait - ) - for PHP in $TRAVIS_PHP_VERSION; do + for PHP in $TRAVIS_PHP_VERSION $php_extra; do INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini echo date.timezone = Europe/Paris >> $INI echo memory_limit = -1 >> $INI @@ -129,7 +102,7 @@ before_install: - | # Install extra PHP extensions - for PHP in $TRAVIS_PHP_VERSION; do + for PHP in $TRAVIS_PHP_VERSION $php_extra; do export PHP=$PHP phpenv global $PHP INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini @@ -139,127 +112,15 @@ before_install: if [[ $PHP != 8.* ]]; then tfold ext.zookeeper tpecl zookeeper-0.7.2 zookeeper.so $INI fi - tfold ext.memcached tpecl memcached-3.1.5 memcached.so $INI - tfold ext.amqp tpecl amqp-1.11.0beta amqp.so $INI - tfold ext.apcu tpecl apcu-5.1.19 apcu.so $INI - tfold ext.igbinary tpecl igbinary-3.1.6 igbinary.so $INI - tfold ext.redis tpecl redis-5.2.3 redis.so $INI "no" - tfold ext.mongodb tpecl mongodb-1.10.0alpha1 mongodb.so $INI done install: - - | - # Install the phpunit-bridge from a PR if required - # - # To run a PR with a patched phpunit-bridge, first submit the patch for the - # phpunit-bridge as a separate PR against the next feature-branch then - # uncomment and update the following line with that PR number - #SYMFONY_PHPUNIT_BRIDGE_PR=32886 - - if [[ $SYMFONY_PHPUNIT_BRIDGE_PR ]]; then - git fetch --depth=2 origin refs/pull/$SYMFONY_PHPUNIT_BRIDGE_PR/head - git rm -rq src/Symfony/Bridge/PhpUnit - git checkout -q FETCH_HEAD -- src/Symfony/Bridge/PhpUnit - SYMFONY_PHPUNIT_BRIDGE_REF=$(curl -s https://api.github.com/repos/symfony/symfony/pulls/$SYMFONY_PHPUNIT_BRIDGE_PR | jq -r .base.ref) - sed -i 's/"symfony\/phpunit-bridge": ".*"/"symfony\/phpunit-bridge": "'$SYMFONY_PHPUNIT_BRIDGE_REF'.x@dev"/' composer.json - rm -rf .phpunit - fi - - - | - # Create local composer packages for each patched components and reference them in composer.json files when cross-testing components - if [[ ! $deps ]]; then - php .github/build-packages.php HEAD^ $SYMFONY_VERSION src/Symfony/Bridge/PhpUnit - else - export SYMFONY_DEPRECATIONS_HELPER=weak && - cp composer.json composer.json.orig && - echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json && - php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | sort) && - mv composer.json composer.json.phpunit && - mv composer.json.orig composer.json - fi - if [[ $SYMFONY_PHPUNIT_BRIDGE_PR ]]; then - git rm -fq -- src/Symfony/Bridge/PhpUnit/composer.json - git diff --staged -- src/Symfony/Bridge/PhpUnit/ | git apply -R --index - fi - - - | - # For the highest branch, when deps=high, the version before it is checked out and tested with the locally patched components - if [[ $deps = high && $SYMFONY_VERSION = $(echo "$SYMFONY_VERSIONS" | tail -n 1 | sed s/.//) ]]; then - export FLIP='^' - export SYMFONY_VERSION=$(echo "$SYMFONY_VERSIONS" | grep -FB1 /$SYMFONY_VERSION | head -n 1 | sed s/.//) && - git fetch --depth=2 origin $SYMFONY_VERSION && - git checkout -m FETCH_HEAD && - export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort) - fi - - - | - # Install symfony/flex - if [[ $deps = low ]]; then - export SYMFONY_REQUIRE='>=2.3' - else - export SYMFONY_REQUIRE=">=$SYMFONY_VERSION" - fi - composer global require --no-progress --no-scripts --no-plugins symfony/flex - - - | - # Legacy tests are skipped when deps=high and when the current branch version has not the same major version number as the next one - [[ $deps = high && $SYMFONY_VERSION = *.4 ]] && export LEGACY=,legacy - - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev - mv composer.json.phpunit composer.json - - - | - # phpinfo - phpinfo() { - phpenv global $1 - php -r 'foreach (get_loaded_extensions() as $extension) echo $extension . " " . phpversion($extension) . PHP_EOL;' - php -i - } - export -f phpinfo - - for PHP in $TRAVIS_PHP_VERSION; do - tfold phpinfo phpinfo $PHP - done - - - | - run_tests () { - set -e - export PHP=$1 - - if [[ $PHP != 8.0* && $PHP != $TRAVIS_PHP_VERSION && $TRAVIS_PULL_REQUEST != false ]]; then - echo -e "\\n\\e[33;1mIntermediate PHP version $PHP is skipped for pull requests.\\e[0m" - return - fi - phpenv global $PHP - rm vendor/composer/package-versions-deprecated -Rf - cd src/Symfony/Component/HttpFoundation; cp composer.json composer.bak; composer require --dev --no-update mongodb/mongodb - tfold 'composer update' $COMPOSER_UP - tfold 'phpunit install' ./phpunit install - if [[ $deps = high ]]; then - echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" || X=1 - (cd src/Symfony/Component/HttpFoundation; mv composer.bak composer.json) - COMPONENTS=$(git diff --name-only src/ | grep composer.json || true) - - if [[ $COMPONENTS && $SYMFONY_VERSION = *.4 && $TRAVIS_PULL_REQUEST != false ]]; then - export FLIP='^' - SYMFONY_VERSION=$(echo $SYMFONY_VERSION | awk '{print $1 - 1}') - echo -e "\\n\\e[33;1mChecking out Symfony $SYMFONY_VERSION and running tests with patched components as deps\\e[0m" - export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev - export SYMFONY_REQUIRE=">=$SYMFONY_VERSION" - git fetch --depth=2 origin $SYMFONY_VERSION - git checkout -m FETCH_HEAD - COMPONENTS=$(echo "$COMPONENTS" | xargs dirname | xargs -n1 -I{} bash -c "[ -e '{}/phpunit.xml.dist' ] && echo '{}'" | sort) - (cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) - [[ ! $COMPONENTS ]] || tfold 'phpunit install' SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT=1 ./phpunit install - [[ ! $COMPONENTS ]] || echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && rm composer.lock vendor/ -Rf && $COMPOSER_UP && $PHPUNIT_X$LEGACY'" || X=1 - fi - - [[ ! $X ]] || (exit 1) - elif [[ $deps = low ]]; then - echo "$COMPONENTS" | parallel --gnu "tfold {} 'cd {} && $COMPOSER_UP --prefer-lowest --prefer-stable && $PHPUNIT_X'" - fi - } - export -f run_tests + - export COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -not -wholename '*/Bridge/PhpUnit/*' -printf '%h\n' | sort) + - export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev + - composer update --no-progress --ansi + - ./phpunit install script: - run_tests $TRAVIS_PHP_VERSION + - echo "$COMPONENTS" | parallel --gnu "tfold {} ./phpunit --exclude-group tty,benchmark,intl-data {}" + - tfold src/Symfony/Component/Console.tty ./phpunit src/Symfony/Component/Console --group tty + - tfold src/Symfony/Bridge/Twig.tty ./phpunit src/Symfony/Bridge/Twig --group tty diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php index 2663fba6b4b69..a7f7e8f81751e 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcachedSessionHandlerTest.php @@ -38,7 +38,15 @@ protected function setUp(): void $this->markTestSkipped('Tests can only be run with memcached extension 2.1.0 or lower, or 3.0.0b1 or higher'); } - $this->memcached = $this->createMock(\Memcached::class); + $r = new \ReflectionClass(\Memcached::class); + $methodsToMock = array_map(function ($m) { return $m->name; }, $r->getMethods(\ReflectionMethod::IS_PUBLIC)); + $methodsToMock = array_diff($methodsToMock, ['getDelayed','getDelayedByKey']); + + $this->memcached = $this->getMockBuilder(\Memcached::class) + ->disableOriginalConstructor() + ->setMethods($methodsToMock) + ->getMock(); + $this->storage = new MemcachedSessionHandler( $this->memcached, ['prefix' => self::PREFIX, 'expiretime' => self::TTL] diff --git a/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php index 790f1b462026c..90fcdb3311649 100644 --- a/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php @@ -34,7 +34,7 @@ protected function setUp(): void protected function tearDown(): void { - putenv('COLUMNS='); + putenv('COLUMNS'); } public function testOutput() diff --git a/src/Symfony/Contracts/Translation/Test/TranslatorTest.php b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php index 89d9fc06d159b..196ec1859f812 100644 --- a/src/Symfony/Contracts/Translation/Test/TranslatorTest.php +++ b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php @@ -35,6 +35,7 @@ class TranslatorTest extends TestCase protected function setUp(): void { $this->defaultLocale = \Locale::getDefault(); + \Locale::setDefault('en'); } protected function tearDown(): void @@ -65,7 +66,6 @@ public function testTrans($expected, $id, $parameters) public function testTransChoiceWithExplicitLocale($expected, $id, $number) { $translator = $this->getTranslator(); - $translator->setLocale('en'); $this->assertEquals($expected, $translator->trans($id, ['%count%' => $number])); } @@ -75,8 +75,6 @@ public function testTransChoiceWithExplicitLocale($expected, $id, $number) */ public function testTransChoiceWithDefaultLocale($expected, $id, $number) { - \Locale::setDefault('en'); - $translator = $this->getTranslator(); $this->assertEquals($expected, $translator->trans($id, ['%count%' => $number])); @@ -85,7 +83,6 @@ public function testTransChoiceWithDefaultLocale($expected, $id, $number) public function testGetSetLocale() { $translator = $this->getTranslator(); - $translator->setLocale('en'); $this->assertEquals('en', $translator->getLocale()); } From 5b56d05ce180b601e9eac4bc11a7ab5279cf5cac Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 11:17:32 +0200 Subject: [PATCH 55/83] - --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f6abaa2eadd8e..bad53d76b76c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ addons: - parallel - zookeeperd - libzookeeper-mt-dev + - libsodium-dev matrix: include: From b32ab9353e5eed50dafbddc6e8d4e3bf03df4e46 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 11:20:13 +0200 Subject: [PATCH 56/83] - --- .travis.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 53ab8e28ec5cb..9139826da8049 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,11 +10,10 @@ addons: - parallel - zookeeperd - libzookeeper-mt-dev - - libsodium-dev matrix: include: - - php: 7.2 + - php: 7.4 fast_finish: true cache: @@ -107,9 +106,6 @@ before_install: export PHP=$PHP phpenv global $PHP INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini - if ! php --ri sodium > /dev/null; then - tfold ext.libsodium tpecl libsodium sodium.so $INI - fi if [[ $PHP != 8.* ]]; then tfold ext.zookeeper tpecl zookeeper-0.7.2 zookeeper.so $INI fi From 021a0a2bfd1a1c6db33da0bfed19c25fb0a99b89 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 11:27:06 +0200 Subject: [PATCH 57/83] - --- .github/workflows/unit-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index d49e783567488..f35ed1a432fda 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -203,12 +203,12 @@ jobs: [[ ! $X ]] || (exit 1) - name: Run tests with SIGCHLD enabled PHP - if: "${{ matrix.php == '7.1' }}" + if: "${{ matrix.php == '7.3' }}" run: | mkdir build cd build - wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-pcntl-sigchild.tar.bz2 - tar -xjf php-7.1.3-pcntl-sigchild.tar.bz2 + wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.2.5-pcntl-sigchild.tar.bz2 + tar -xjf php-7.2.5-pcntl-sigchild.tar.bz2 cd .. ./build/php/bin/php ./phpunit --colors=always src/Symfony/Component/Process From 9a20e25ba944cb5b81831adbb51ff5bfda108e35 Mon Sep 17 00:00:00 2001 From: Vasilij Dusko Date: Sun, 27 Jun 2021 08:52:30 +0300 Subject: [PATCH 58/83] * validators.(ru|lt).xlf - wrong trans-unit ids --- .../Resources/translations/validators.lt.xlf | 14 +++++++------- .../Resources/translations/validators.ru.xlf | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index 5f0e680cc0872..eeb0727349573 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -131,25 +131,25 @@ Ši reikšmė turi būti skaičius. - This value is not a valid country. - Ši reikšmė nėra tinkama šalis. - - This file is not a valid image. Byla nėra paveikslėlis. - + This is not a valid IP address. Ši reikšmė nėra tinkamas IP adresas. - + This value is not a valid language. Ši reikšmė nėra tinkama kalba. - + This value is not a valid locale. Ši reikšmė nėra tinkama lokalė. + + This value is not a valid country. + Ši reikšmė nėra tinkama šalis. + This value is already used. Ši reikšmė jau yra naudojama. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index fe2bd4ef91c3b..2c7a0444ef51e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -131,25 +131,25 @@ Значение должно быть числом. - This value is not a valid country. - Значение не является допустимой страной. - - This file is not a valid image. Файл не является допустимым форматом изображения. - + This is not a valid IP address. Значение не является допустимым IP адресом. - + This value is not a valid language. Значение не является допустимым языком. - + This value is not a valid locale. Значение не является допустимой локалью. + + This value is not a valid country. + Значение не является допустимой страной. + This value is already used. Это значение уже используется. From bb59651e4804fe8eb934ddb56afe1505fa768d95 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 13:30:21 +0200 Subject: [PATCH 59/83] Fix CI --- .github/workflows/unit-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index b7fd0de88c307..5aa50094bff97 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -203,12 +203,12 @@ jobs: [[ ! $X ]] || (exit 1) - name: Run tests with SIGCHLD enabled PHP - if: "${{ matrix.php == '7.1' }}" + if: "${{ matrix.php == '7.2' && ! matrix.mode }}" run: | mkdir build cd build - wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-pcntl-sigchild.tar.bz2 - tar -xjf php-7.1.3-pcntl-sigchild.tar.bz2 + wget -q https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.2.5-pcntl-sigchild.tar.bz2 + tar -xjf php-7.2.5-pcntl-sigchild.tar.bz2 cd .. ./build/php/bin/php ./phpunit --colors=always src/Symfony/Component/Process From 41ebc32373196071256725a3518d1692237f0c5a Mon Sep 17 00:00:00 2001 From: Antoine Makdessi Date: Sat, 15 May 2021 20:39:48 +0200 Subject: [PATCH 60/83] [SecurityBundle] Change n/a information label from red to yellow --- .../Resources/views/Collector/security.html.twig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig index 9f69abcaf2d8e..910f4a7020718 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -6,8 +6,10 @@ {% if collector.token %} {% set is_authenticated = collector.enabled and collector.authenticated %} {% set color_code = is_authenticated ? '' : 'yellow' %} + {% elseif collector.enabled %} + {% set color_code = collector.authenticatorManagerEnabled ? 'yellow' : 'red' %} {% else %} - {% set color_code = collector.enabled ? 'red' : '' %} + {% set color_code = '' %} {% endif %} {% set icon %} @@ -35,7 +37,7 @@
Authenticated - {{ is_authenticated ? 'Yes' : 'No' }} + {{ is_authenticated ? 'Yes' : 'No' }}
@@ -45,7 +47,7 @@ {% else %}
Authenticated - No + No
{% endif %} From 1bbacd5c86e7058f05e27b360091440f1331e26a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 13:42:59 +0200 Subject: [PATCH 61/83] Fix CI --- .github/workflows/unit-tests.yml | 4 ++-- src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php | 4 ++++ .../Component/String/Tests/AbstractUnicodeTestCase.php | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 93ce61cc18a34..5aa50094bff97 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -20,7 +20,7 @@ jobs: strategy: matrix: include: - - php: '7.4' + - php: '7.2' - php: '8.0' - php: '7.4' mode: high-deps @@ -203,7 +203,7 @@ jobs: [[ ! $X ]] || (exit 1) - name: Run tests with SIGCHLD enabled PHP - if: "${{ matrix.php == '7.4' && ! matrix.mode }}" + if: "${{ matrix.php == '7.2' && ! matrix.mode }}" run: | mkdir build cd build diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index d9598d73637c3..70e4ba311d7a6 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -36,6 +36,8 @@ public function testCreateFromEmptyString() /** * @dataProvider provideBytesAt + * + * @requires extension intl 66.2 */ public function testBytesAt(array $expected, string $string, int $offset, int $form = null) { @@ -157,6 +159,8 @@ public static function provideWrap(): array /** * @dataProvider provideLength + * + * @requires extension intl 66.2 */ public function testLength(int $length, string $string) { diff --git a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php index 5617bc051e14c..0f2a58404c41a 100644 --- a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php @@ -57,6 +57,8 @@ public static function provideBytesAt(): array /** * @dataProvider provideCodePointsAt + * + * @requires extension intl 66.2 */ public function testCodePointsAt(array $expected, string $string, int $offset, int $form = null) { From aecaf6b49d2db03c17f3f95a1d9a1bc6777f012e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 13:47:28 +0200 Subject: [PATCH 62/83] [travis] raise concurrency --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index bad53d76b76c2..065a71677ff0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -122,6 +122,6 @@ install: - ./phpunit install script: - - echo "$COMPONENTS" | parallel --gnu "tfold {} ./phpunit --exclude-group tty,benchmark,intl-data {}" + - echo "$COMPONENTS" | parallel --gnu -j +3 "tfold {} ./phpunit --exclude-group tty,benchmark,intl-data {}" - tfold src/Symfony/Component/Console.tty ./phpunit src/Symfony/Component/Console --group tty - tfold src/Symfony/Bridge/Twig.tty ./phpunit src/Symfony/Bridge/Twig --group tty From c2e4ac613ca5dfcc60cc56f492ee04b52f010e4d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 13:58:40 +0200 Subject: [PATCH 63/83] - --- .github/workflows/unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 5aa50094bff97..6baa73e8fc02d 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -61,7 +61,6 @@ jobs: COMPOSER_HOME="$(composer config home)" ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" - echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV @@ -150,6 +149,7 @@ jobs: local ok=0 local title="$1 $FLIP" local start=$(date -u +%s) + export COLUMNS=120 OUTPUT=$(bash -xc "$2" 2>&1) || ok=1 local end=$(date -u +%s) From 0ef5ec8f8101750873e59f2f9e7313c884e4c48a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 14:04:45 +0200 Subject: [PATCH 64/83] - --- .github/workflows/intl-data-tests.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/intl-data-tests.yml b/.github/workflows/intl-data-tests.yml index f695bca201426..a449e9c91fc73 100644 --- a/.github/workflows/intl-data-tests.yml +++ b/.github/workflows/intl-data-tests.yml @@ -36,9 +36,15 @@ jobs: - name: Install dependencies run: | + COMPOSER_HOME="$(composer config home)" + ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev + echo COMPOSER_ROOT_VERSION=$COMPOSER_ROOT_VERSION >> $GITHUB_ENV + echo "::group::composer update" - composer update --no-progress --no-suggest --ansi + composer update --no-progress --ansi echo "::endgroup::" + echo "::group::install phpunit" ./phpunit install echo "::endgroup::" From fdb8b9e64cac2fa782d2a2ffe44a9c84c6d27990 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 14:09:48 +0200 Subject: [PATCH 65/83] [travis] keep compiling sodium --- .travis.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 065a71677ff0c..c07e7cc6775b7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,6 @@ addons: - parallel - zookeeperd - libzookeeper-mt-dev - - libsodium-dev matrix: include: @@ -107,9 +106,6 @@ before_install: export PHP=$PHP phpenv global $PHP INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini - if ! php --ri sodium > /dev/null; then - tfold ext.libsodium tpecl libsodium sodium.so $INI - fi if [[ $PHP != 8.* ]]; then tfold ext.zookeeper tpecl zookeeper-0.7.2 zookeeper.so $INI fi From 058168e2ed0e45027f20e3d59da2be42d3155aa8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 14:13:22 +0200 Subject: [PATCH 66/83] [gha] Define COLUMNS properly This reverts commit c2e4ac613ca5dfcc60cc56f492ee04b52f010e4d. --- .github/workflows/unit-tests.yml | 2 +- .../Console/Descriptor/TextDescriptorTest.php | 7 +++++-- .../UserPasswordEncoderCommandTest.php | 17 ++++++++++++----- .../Console/Descriptor/JsonDescriptorTest.php | 7 +++++-- .../Console/Descriptor/TextDescriptorTest.php | 7 +++++-- .../Tests/Command/DebugCommandTest.php | 5 ++++- 6 files changed, 32 insertions(+), 13 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 6baa73e8fc02d..5aa50094bff97 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -61,6 +61,7 @@ jobs: COMPOSER_HOME="$(composer config home)" ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" + echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV @@ -149,7 +150,6 @@ jobs: local ok=0 local title="$1 $FLIP" local start=$(date -u +%s) - export COLUMNS=120 OUTPUT=$(bash -xc "$2" 2>&1) || ok=1 local end=$(date -u +%s) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php index 4ed0446320c1c..5a57a6f0c2423 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php @@ -15,14 +15,17 @@ class TextDescriptorTest extends AbstractDescriptorTest { + private $colSize; + protected function setUp(): void { - putenv('COLUMNS=121'); + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); } protected function tearDown(): void { - putenv('COLUMNS'); + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); } protected function getDescriptor() diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 5846f386b7fca..e8481f31c539b 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -29,6 +29,18 @@ class UserPasswordEncoderCommandTest extends AbstractWebTestCase { /** @var CommandTester */ private $passwordEncoderCommandTester; + private $colSize; + + protected function setUp(): void + { + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); + } + + protected function tearDown(): void + { + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); + } public function testEncodePasswordEmptySalt() { @@ -314,7 +326,6 @@ public function testThrowsExceptionOnNoConfiguredEncoders() protected function setUp(): void { - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); $kernel = $this->createKernel(['test_case' => 'PasswordEncode']); $kernel->boot(); @@ -332,7 +343,6 @@ protected function tearDown(): void private function setupArgon2i() { - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2i.yml']); $kernel->boot(); @@ -345,7 +355,6 @@ private function setupArgon2i() private function setupArgon2id() { - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'argon2id.yml']); $kernel->boot(); @@ -358,7 +367,6 @@ private function setupArgon2id() private function setupBcrypt() { - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'bcrypt.yml']); $kernel->boot(); @@ -371,7 +379,6 @@ private function setupBcrypt() private function setupSodium() { - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); $kernel = $this->createKernel(['test_case' => 'PasswordEncode', 'root_config' => 'sodium.yml']); $kernel->boot(); diff --git a/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php b/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php index 5926fe527738f..8aa46f714d759 100644 --- a/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php +++ b/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php @@ -15,14 +15,17 @@ class JsonDescriptorTest extends AbstractDescriptorTest { + private $colSize; + protected function setUp(): void { - putenv('COLUMNS=121'); + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); } protected function tearDown(): void { - putenv('COLUMNS'); + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); } protected function getDescriptor() diff --git a/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php b/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php index ed1582e6b21ba..b3bfbaa5388ca 100644 --- a/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php +++ b/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php @@ -15,14 +15,17 @@ class TextDescriptorTest extends AbstractDescriptorTest { + private $colSize; + protected function setUp(): void { - putenv('COLUMNS=121'); + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); } protected function tearDown(): void { - putenv('COLUMNS'); + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); } protected function getDescriptor() diff --git a/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php index 90fcdb3311649..dc06144df4cc4 100644 --- a/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Messenger/Tests/Command/DebugCommandTest.php @@ -27,14 +27,17 @@ */ class DebugCommandTest extends TestCase { + private $colSize; + protected function setUp(): void { + $this->colSize = getenv('COLUMNS'); putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); } protected function tearDown(): void { - putenv('COLUMNS'); + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); } public function testOutput() From decf443a204a13e431a05cb921cb59d473451ad7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 14:24:10 +0200 Subject: [PATCH 67/83] - --- .../Functional/UserPasswordEncoderCommandTest.php | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index e8481f31c539b..78864da648876 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -31,17 +31,6 @@ class UserPasswordEncoderCommandTest extends AbstractWebTestCase private $passwordEncoderCommandTester; private $colSize; - protected function setUp(): void - { - $this->colSize = getenv('COLUMNS'); - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); - } - - protected function tearDown(): void - { - putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); - } - public function testEncodePasswordEmptySalt() { $this->passwordEncoderCommandTester->execute([ @@ -326,6 +315,9 @@ public function testThrowsExceptionOnNoConfiguredEncoders() protected function setUp(): void { + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); + $kernel = $this->createKernel(['test_case' => 'PasswordEncode']); $kernel->boot(); @@ -339,6 +331,7 @@ protected function setUp(): void protected function tearDown(): void { $this->passwordEncoderCommandTester = null; + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); } private function setupArgon2i() From c6193bf85d78f2b71cdcede2d70bcf0975152123 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 14:32:53 +0200 Subject: [PATCH 68/83] - --- .../Console/Descriptor/AbstractDescriptorTest.php | 13 +++++++++++++ .../Tests/Console/Descriptor/TextDescriptorTest.php | 13 ------------- .../Console/Descriptor/AbstractDescriptorTest.php | 13 +++++++++++++ .../Tests/Console/Descriptor/JsonDescriptorTest.php | 13 ------------- .../Tests/Console/Descriptor/TextDescriptorTest.php | 13 ------------- 5 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php index c4c3f7df03cbc..30cc22e2039de 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php @@ -25,6 +25,19 @@ abstract class AbstractDescriptorTest extends TestCase { + private $colSize; + + protected function setUp(): void + { + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS=121'); + } + + protected function tearDown(): void + { + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); + } + /** @dataProvider getDescribeRouteCollectionTestData */ public function testDescribeRouteCollection(RouteCollection $routes, $expectedDescription) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php index 5a57a6f0c2423..ce4f377c508fd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/TextDescriptorTest.php @@ -15,19 +15,6 @@ class TextDescriptorTest extends AbstractDescriptorTest { - private $colSize; - - protected function setUp(): void - { - $this->colSize = getenv('COLUMNS'); - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); - } - - protected function tearDown(): void - { - putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); - } - protected function getDescriptor() { return new TextDescriptor(); diff --git a/src/Symfony/Component/Form/Tests/Console/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Component/Form/Tests/Console/Descriptor/AbstractDescriptorTest.php index f50a79ec00fcf..78e0f0bbda34e 100644 --- a/src/Symfony/Component/Form/Tests/Console/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Component/Form/Tests/Console/Descriptor/AbstractDescriptorTest.php @@ -28,6 +28,19 @@ abstract class AbstractDescriptorTest extends TestCase { + private $colSize; + + protected function setUp(): void + { + $this->colSize = getenv('COLUMNS'); + putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); + } + + protected function tearDown(): void + { + putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); + } + /** @dataProvider getDescribeDefaultsTestData */ public function testDescribeDefaults($object, array $options, $fixtureName) { diff --git a/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php b/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php index 8aa46f714d759..c035be6bcd9cf 100644 --- a/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php +++ b/src/Symfony/Component/Form/Tests/Console/Descriptor/JsonDescriptorTest.php @@ -15,19 +15,6 @@ class JsonDescriptorTest extends AbstractDescriptorTest { - private $colSize; - - protected function setUp(): void - { - $this->colSize = getenv('COLUMNS'); - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); - } - - protected function tearDown(): void - { - putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); - } - protected function getDescriptor() { return new JsonDescriptor(); diff --git a/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php b/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php index b3bfbaa5388ca..c970eba96e62f 100644 --- a/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php +++ b/src/Symfony/Component/Form/Tests/Console/Descriptor/TextDescriptorTest.php @@ -15,19 +15,6 @@ class TextDescriptorTest extends AbstractDescriptorTest { - private $colSize; - - protected function setUp(): void - { - $this->colSize = getenv('COLUMNS'); - putenv('COLUMNS='.(119 + \strlen(\PHP_EOL))); - } - - protected function tearDown(): void - { - putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS'); - } - protected function getDescriptor() { return new TextDescriptor(); From 70a025648271c45be5d4936965eb7416541388b7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 14:41:38 +0200 Subject: [PATCH 69/83] - --- .../FrameworkBundle/Tests/Fixtures/Descriptor/route_1_link.txt | 2 +- .../FrameworkBundle/Tests/Fixtures/Descriptor/route_2_link.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1_link.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1_link.txt index 8d86bc7be8ddb..4d4a18e5a71b8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1_link.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_1_link.txt @@ -10,7 +10,7 @@ | Method | GET|HEAD | | Requirements | name: [a-z]+ | | Class | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\RouteStub | -| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=68\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ | +| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=58\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ | | | name: Joseph | | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | | | opt1: val1 | diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2_link.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2_link.txt index a244b515cabbf..a690b9798d90a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2_link.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2_link.txt @@ -10,7 +10,7 @@ | Method | PUT|POST | | Requirements | NO CUSTOM | | Class | Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\RouteStub | -| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=68\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ | +| Defaults | _controller: ]8;;myeditor://open?file=[:file:]&line=58\Symfony\Bundle\FrameworkBundle\Tests\Console\Descriptor\MyController::__invoke()]8;;\ | | Options | compiler_class: Symfony\Component\Routing\RouteCompiler | | | opt1: val1 | | | opt2: val2 | From bd412f2616ab63d9741cd977d23a82a44af0276d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sun, 27 Jun 2021 18:37:09 +0200 Subject: [PATCH 70/83] Tweak GHA --- .github/workflows/unit-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 5aa50094bff97..68a48d226695e 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -57,6 +57,7 @@ jobs: git config --global user.email "" git config --global user.name "Symfony" git config --global init.defaultBranch main + git config --global advice.detachedHead false COMPOSER_HOME="$(composer config home)" ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" @@ -148,7 +149,7 @@ jobs: run: | _run_tests() { local ok=0 - local title="$1 $FLIP" + local title="$1$FLIP" local start=$(date -u +%s) OUTPUT=$(bash -xc "$2" 2>&1) || ok=1 local end=$(date -u +%s) From ab2a0fe653851718ff5dc6c3e935cffb63ae78f6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 28 Jun 2021 11:03:12 +0200 Subject: [PATCH 71/83] Tweak CI --- .appveyor.yml | 2 +- .github/workflows/unit-tests.yml | 4 ++-- .travis.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 38f7468b9a99a..d3d4660290489 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -51,7 +51,7 @@ install: - php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex - git config --global user.email "" - git config --global user.name "Symfony" - - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+'"`) DO (SET SYMFONY_VERSION=%%F) + - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -o '[0-9][0-9]*\.[0-9]'"`) DO (SET SYMFONY_VERSION=%%F) - php .github/build-packages.php HEAD^ %SYMFONY_VERSION% src\Symfony\Bridge\PhpUnit - SET "SYMFONY_REQUIRE=>=%SYMFONY_VERSION%" - SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 68a48d226695e..db8acbc3dc8dd 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -104,7 +104,7 @@ jobs: # For the highest branch, in high-deps mode, the version before it is checked out and tested with the locally patched components if [[ "${{ matrix.mode }}" = high-deps && $SYMFONY_VERSION = $(echo "$SYMFONY_VERSIONS" | tail -n 1 | sed s/.//) ]]; then - echo FLIP='🙃' >> $GITHUB_ENV + echo FLIP='^' >> $GITHUB_ENV SYMFONY_VERSION=$(echo "$SYMFONY_VERSIONS" | grep -FB1 /$SYMFONY_VERSION | head -n 1 | sed s/.//) git fetch --depth=2 origin $SYMFONY_VERSION git checkout -m FETCH_HEAD @@ -189,7 +189,7 @@ jobs: COMPONENTS=$(git diff --name-only src/ | grep composer.json || true) if [[ $COMPONENTS && $SYMFONY_VERSION = *.4 ]]; then - export FLIP='🙃' + export FLIP='^' SYMFONY_VERSION=$(echo $SYMFONY_VERSION | awk '{print $1 - 1}') echo -e "\\n\\e[33;1mChecking out Symfony $SYMFONY_VERSION and running tests with patched components as deps\\e[0m" export COMPOSER_ROOT_VERSION=$SYMFONY_VERSION.x-dev diff --git a/.travis.yml b/.travis.yml index c07e7cc6775b7..2836521932ddf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,7 +44,7 @@ before_install: # tfold is a helper to create folded reports tfold () { - local title="$PHP $1 $FLIP" + local title="$PHP $1" local fold=$(echo $title | sed -r 's/[^-_A-Za-z0-9]+/./g') shift local id=$(printf %08x $(( RANDOM * RANDOM ))) From ac2c3a936d0bb33e1cc868ba28a2437f88f69f00 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 28 Jun 2021 11:04:43 +0200 Subject: [PATCH 72/83] Tweak CI --- .github/workflows/unit-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index db8acbc3dc8dd..9607f1810a8ce 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -157,7 +157,7 @@ jobs: if [[ $ok -ne 0 ]]; then printf "\n%-70s%10s\n" $title $(($end-$start))s echo "$OUTPUT" - echo -e "\n\\e[41mKO\\e[0m $title\\n" + echo -e "\n::error::\\e[41mKO\\e[0m $title\\n" else printf "::group::%-68s%10s\n" $title $(($end-$start))s echo "$OUTPUT" From 21621ab78361c90c56cfb0571a08a23aabf5672b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 28 Jun 2021 17:26:46 +0200 Subject: [PATCH 73/83] [FrameworkBundle] fix tests --- .github/workflows/unit-tests.yml | 7 ++++++- .../Tests/Console/Descriptor/ObjectsProvider.php | 2 +- .../Descriptor/event_dispatcher_1_event1.json | 2 +- .../Fixtures/Descriptor/event_dispatcher_1_event1.md | 2 +- .../Descriptor/event_dispatcher_1_event1.txt | 12 ++++++------ .../Descriptor/event_dispatcher_1_event1.xml | 2 +- .../Descriptor/event_dispatcher_1_events.json | 2 +- .../Fixtures/Descriptor/event_dispatcher_1_events.md | 2 +- .../Descriptor/event_dispatcher_1_events.txt | 12 ++++++------ .../Descriptor/event_dispatcher_1_events.xml | 2 +- .../Bundle/TwigBundle/Resources/config/twig.xml | 2 +- 11 files changed, 26 insertions(+), 21 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 9607f1810a8ce..7a8998a51ba99 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -198,7 +198,12 @@ jobs: git checkout -m FETCH_HEAD COMPONENTS=$(echo "$COMPONENTS" | xargs dirname | xargs -n1 -I{} bash -c "[ -e '{}/phpunit.xml.dist' ] && echo '{}'" | sort || true) (cd src/Symfony/Component/HttpFoundation; composer require --dev --no-update mongodb/mongodb) - [[ ! $COMPONENTS ]] || echo "$COMPONENTS" | parallel -j +3 "_run_tests {} 'cd {} && rm composer.lock vendor/ -Rf && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1 + if [[ $COMPONENTS ]]; then + echo "::group::install phpunit" + ./phpunit install + echo "::endgroup::" + echo "$COMPONENTS" | parallel -j +3 "_run_tests {} 'cd {} && rm composer.lock vendor/ -Rf && $COMPOSER_UP && $PHPUNIT$LEGACY'" || X=1 + fi fi [[ ! $X ]] || (exit 1) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index 84f05c64874ea..071ca83ca68b3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -200,7 +200,7 @@ public static function getEventDispatchers() { $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addListener('event1', 'global_function', 255); + $eventDispatcher->addListener('event1', 'var_dump', 255); $eventDispatcher->addListener('event1', function () { return 'Closure'; }, -1); $eventDispatcher->addListener('event2', new CallableClass()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json index 4b68f0cefc0e4..dc9957f7141e5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.json @@ -1,7 +1,7 @@ [ { "type": "function", - "name": "global_function", + "name": "var_dump", "priority": 255 }, { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md index 98b81ecdce422..826ab219ed1fa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.md @@ -3,7 +3,7 @@ ## Listener 1 - Type: `function` -- Name: `global_function` +- Name: `var_dump` - Priority: `255` ## Listener 2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt index f7a3cb0bd90ca..0f0879f421b05 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.txt @@ -2,10 +2,10 @@ Registered Listeners for "event1" Event ======================================= - ------- ------------------- ---------- -  Order   Callable   Priority  - ------- ------------------- ---------- - #1 global_function() 255 - #2 Closure() -1 - ------- ------------------- ---------- + ------- ------------ ---------- +  Order   Callable   Priority  + ------- ------------ ---------- + #1 var_dump() 255 + #2 Closure() -1 + ------- ------------ ---------- diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml index bc03189af7b80..3d387b44bbf27 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_event1.xml @@ -1,5 +1,5 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json index 30772d9a4a212..f79f79f99e21d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.json @@ -2,7 +2,7 @@ "event1": [ { "type": "function", - "name": "global_function", + "name": "var_dump", "priority": 255 }, { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md index eb809789d5f17..ba407bef0c09d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.md @@ -5,7 +5,7 @@ ### Listener 1 - Type: `function` -- Name: `global_function` +- Name: `var_dump` - Priority: `255` ### Listener 2 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt index 475ad24cfda20..35c68295b8bfa 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.txt @@ -5,12 +5,12 @@ "event1" event -------------- - ------- ------------------- ---------- -  Order   Callable   Priority  - ------- ------------------- ---------- - #1 global_function() 255 - #2 Closure() -1 - ------- ------------------- ---------- + ------- ------------ ---------- +  Order   Callable   Priority  + ------- ------------ ---------- + #1 var_dump() 255 + #2 Closure() -1 + ------- ------------ ---------- "event2" event -------------- diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml index d7443f9743666..57a4b3a5cf6cd 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/event_dispatcher_1_events.xml @@ -1,7 +1,7 @@ - + diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index 9a7dc42e77967..709522e44dcaf 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -166,7 +166,7 @@ - + %kernel.debug% From f549d9cd9c809bc6027e683fed79cf020fcda7fe Mon Sep 17 00:00:00 2001 From: elattariyassine <45572720+ELATTARIYassine@users.noreply.github.com> Date: Mon, 28 Jun 2021 19:06:40 +0100 Subject: [PATCH 74/83] added missing Arabic translations --- .../Validator/Resources/translations/validators.ar.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index fa87a3753de67..c6a38c57dab7e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). صالح (ISIN) هذه القيمة ليست رقم تعريف الأوراق المالية الدولي. + + This value should be a valid expression. + يجب أن تكون هذه القيمة تعبيرًا صالحًا. + From e29dcea3eaffcc5aa6c67d44f4cc7fbd46436fd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Mon, 28 Jun 2021 14:38:59 +0200 Subject: [PATCH 75/83] Fix SessionTokenStorage reuse with Request --- .../TokenStorage/SessionTokenStorageTest.php | 49 +++++++++++++++++++ .../Csrf/TokenStorage/SessionTokenStorage.php | 4 +- 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php b/src/Symfony/Component/Security/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php index 230f33fb257f3..6c9bf9820b0c7 100644 --- a/src/Symfony/Component/Security/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php +++ b/src/Symfony/Component/Security/Csrf/Tests/TokenStorage/SessionTokenStorageTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Security\Csrf\Tests\TokenStorage; use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Session\Session; @@ -24,6 +25,8 @@ */ class SessionTokenStorageTest extends TestCase { + use ExpectDeprecationTrait; + private const SESSION_NAMESPACE = 'foobar'; /** @@ -159,4 +162,50 @@ public function testClearDoesNotRemoveNonNamespacedSessionValues() $this->assertTrue($this->session->has('foo')); $this->assertSame('baz', $this->session->get('foo')); } + + /** + * @group legacy + */ + public function testMockSessionIsCreatedWhenMissing() + { + $this->expectDeprecation('Since symfony/security-csrf 5.3: Using the "Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage" without a session has no effect and is deprecated. It will throw a "Symfony\Component\HttpFoundation\Exception\SessionNotFoundException" in Symfony 6.0'); + + $this->storage->setToken('token_id', 'TOKEN'); + + $requestStack = new RequestStack(); + $storage = new SessionTokenStorage($requestStack, self::SESSION_NAMESPACE); + + $this->assertFalse($storage->hasToken('foo')); + $storage->setToken('foo', 'bar'); + $this->assertTrue($storage->hasToken('foo')); + $this->assertSame('bar', $storage->getToken('foo')); + + $session = new Session(new MockArraySessionStorage()); + $request = new Request(); + $request->setSession($session); + $requestStack->push($request); + } + + /** + * @group legacy + */ + public function testMockSessionIsReusedEvenWhenRequestHasSession() + { + $this->expectDeprecation('Since symfony/security-csrf 5.3: Using the "Symfony\Component\Security\Csrf\TokenStorage\SessionTokenStorage" without a session has no effect and is deprecated. It will throw a "Symfony\Component\HttpFoundation\Exception\SessionNotFoundException" in Symfony 6.0'); + + $this->storage->setToken('token_id', 'TOKEN'); + + $requestStack = new RequestStack(); + $storage = new SessionTokenStorage($requestStack, self::SESSION_NAMESPACE); + + $storage->setToken('foo', 'bar'); + $this->assertSame('bar', $storage->getToken('foo')); + + $session = new Session(new MockArraySessionStorage()); + $request = new Request(); + $request->setSession($session); + $requestStack->push($request); + + $this->assertSame('bar', $storage->getToken('foo')); + } } diff --git a/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php b/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php index 70613f5f26f25..5b86499bc9e8a 100644 --- a/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php +++ b/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php @@ -34,7 +34,7 @@ class SessionTokenStorage implements ClearableTokenStorageInterface private $requestStack; private $namespace; /** - * Tp be remove in Symfony 6.0 + * To be removed in Symfony 6.0. */ private $session; @@ -130,7 +130,7 @@ public function clear() private function getSession(): SessionInterface { try { - return $this->requestStack->getSession(); + return $this->session ?? $this->requestStack->getSession(); } catch (SessionNotFoundException $e) { trigger_deprecation('symfony/security-csrf', '5.3', 'Using the "%s" without a session has no effect and is deprecated. It will throw a "%s" in Symfony 6.0', __CLASS__, SessionNotFoundException::class); From edf74fa9ab419dff1f6cd3860ec530b68a803509 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 29 Jun 2021 11:23:13 +0200 Subject: [PATCH 76/83] Tweak GHA --- .github/workflows/psalm.yml | 4 ++-- .github/workflows/unit-tests.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index f5807849e6f3e..a9adb8e7cf532 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -34,8 +34,8 @@ jobs: COMPOSER_HOME="$(composer config home)" ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev - composer remove --no-update --no-interaction symfony/phpunit-bridge - composer require --no-update psalm/phar phpunit/phpunit:^9.5 php-http/discovery psr/event-dispatcher + composer remove --dev --no-update --no-interaction symfony/phpunit-bridge + composer require --no-update psalm/phar phpunit/phpunit:^9.5 php-http/discovery psr/event-dispatcher mongodb/mongodb echo "::group::composer update" composer update --no-progress --ansi diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 7a8998a51ba99..ceffbe310240c 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -157,7 +157,7 @@ jobs: if [[ $ok -ne 0 ]]; then printf "\n%-70s%10s\n" $title $(($end-$start))s echo "$OUTPUT" - echo -e "\n::error::\\e[41mKO\\e[0m $title\\n" + echo -e "\n::error::KO $title\\n" else printf "::group::%-68s%10s\n" $title $(($end-$start))s echo "$OUTPUT" From 18bf1bf44c7a0f5297facdcfc3d53da89cf434e9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 29 Jun 2021 11:23:13 +0200 Subject: [PATCH 77/83] update Italian translation --- .../Validator/Resources/translations/validators.it.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index 1af8185e80e16..bca112204ddc8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -386,6 +386,10 @@ This value is not a valid International Securities Identification Number (ISIN). Questo valore non è un codice identificativo internazionale di valori mobiliari (ISIN) valido. + + This value should be a valid expression. + Questo valore dovrebbe essere un'espressione valida. + From 72020d8134c8d1701b67da37abb50c2aa8d7a00d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 29 Jun 2021 11:51:57 +0200 Subject: [PATCH 78/83] [Messenger] fix FlattenExceptionNormalizer --- .../Serialization/Normalizer/FlattenExceptionNormalizer.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php b/src/Symfony/Component/Messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php index 344eea7cc743f..f7d909f2c599d 100644 --- a/src/Symfony/Component/Messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php +++ b/src/Symfony/Component/Messenger/Transport/Serialization/Normalizer/FlattenExceptionNormalizer.php @@ -42,13 +42,11 @@ public function normalize($object, $format = null, array $context = []) 'file' => $object->getFile(), 'line' => $object->getLine(), 'previous' => null === $object->getPrevious() ? null : $this->normalize($object->getPrevious(), $format, $context), + 'status' => $object->getStatusCode(), 'status_text' => $object->getStatusText(), 'trace' => $object->getTrace(), 'trace_as_string' => $object->getTraceAsString(), ]; - if (null !== $status = $object->getStatusCode()) { - $normalized['status'] = $status; - } return $normalized; } @@ -70,7 +68,7 @@ public function denormalize($data, $type, $format = null, array $context = []) $object->setMessage($data['message']); $object->setCode($data['code']); - $object->setStatusCode($data['status'] ?? null); + $object->setStatusCode($data['status'] ?? 500); $object->setClass($data['class']); $object->setFile($data['file']); $object->setLine($data['line']); From 62183afac46b9dab7a7c9b34c6f4b449a4d11e45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=A0=E8=81=8A=E7=9A=84=E6=9D=B0=E5=9F=BA?= Date: Wed, 30 Jun 2021 13:40:44 +0800 Subject: [PATCH 79/83] Missing translations for Chinese (zh_CN) #41814 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. change "数值" to "值" in some tokens.("数值" in Chinese means an numeric value, but some tokens not declare it's value is a number); 2. add the id=100 translation. --- .../Resources/translations/validators.zh_CN.xlf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf index 43ac9143bb963..3b5a16bd5fcd5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf @@ -368,7 +368,7 @@ This value is not a valid hostname. - 该数值不是有效的主机名称。 + 该值不是有效的主机名称。 The number of elements in this collection should be a multiple of {{ compared_value }}. @@ -376,7 +376,7 @@ This value should satisfy at least one of the following constraints: - 该数值需符合以下其中一个约束: + 该值需符合以下其中一个约束: Each element of this collection should satisfy its own set of constraints. @@ -384,7 +384,11 @@ This value is not a valid International Securities Identification Number (ISIN). - 该数值不是有效的国际证券识别码 (ISIN)。 + 该值不是有效的国际证券识别码 (ISIN)。 + + + This value should be a valid expression. + 该值需为一个有效的表达式。 From c35eb75f79bc21c2127e9ace2c5989d24dad080f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Wed, 30 Jun 2021 08:57:46 +0200 Subject: [PATCH 80/83] Handle concurency in Csrf DoctrineTokenProvider --- .../Security/RememberMe/DoctrineTokenProvider.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php index 0e1983f01ff9f..ae4be69b259f2 100644 --- a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php @@ -192,8 +192,15 @@ public function updateExistingToken(PersistentTokenInterface $token, string $tok return; } - $this->deleteTokenBySeries($tmpSeries); - $this->createNewToken(new PersistentToken($token->getClass(), $token->getUserIdentifier(), $tmpSeries, $token->getTokenValue(), $lastUsed)); + $this->conn->beginTransaction(); + try { + $this->deleteTokenBySeries($tmpSeries); + $this->createNewToken(new PersistentToken($token->getClass(), $token->getUserIdentifier(), $tmpSeries, $token->getTokenValue(), $lastUsed)); + + $this->conn->commit(); + } catch (\Exception $e) { + $this->conn->rollBack(); + } } /** From 4b9b68c0235d587a328de67e122e166e5bd55be7 Mon Sep 17 00:00:00 2001 From: Arne Groskurth Date: Tue, 29 Jun 2021 10:47:48 +0200 Subject: [PATCH 81/83] [Filesystem] Workaround cannot dumpFile into "protected" folders on Windows --- .../Component/Filesystem/Filesystem.php | 8 ------- .../Filesystem/Tests/FilesystemTest.php | 21 +++++++++++++++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 483c0b4261bfa..dfb1394add28c 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -678,10 +678,6 @@ public function dumpFile($filename, $content) $this->mkdir($dir); } - if (!is_writable($dir)) { - throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir); - } - // Will create a temp file with 0600 access rights // when the filesystem supports chmod. $tmpFile = $this->tempnam($dir, basename($filename)); @@ -721,10 +717,6 @@ public function appendToFile($filename, $content) $this->mkdir($dir); } - if (!is_writable($dir)) { - throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir); - } - if (false === @file_put_contents($filename, $content, \FILE_APPEND)) { throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename); } diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index 77f780127e050..5639c220c735d 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -1751,6 +1751,27 @@ public function testCopyShouldKeepExecutionPermission() $this->assertFilePermissions(767, $targetFilePath); } + public function testDumpToProtectedDirectory() + { + if (\DIRECTORY_SEPARATOR !== '\\') { + $this->markTestSkipped('This test is specific to Windows.'); + } + + if (($userProfilePath = getenv('USERPROFILE')) === false || !is_dir($userProfilePath)) { + throw new \RuntimeException('Failed to retrieve user profile path.'); + } + + $targetPath = implode(\DIRECTORY_SEPARATOR, [$userProfilePath, 'Downloads', '__test_file.ext']); + + try { + $this->assertFileDoesNotExist($targetPath); + $this->filesystem->dumpFile($targetPath, 'foobar'); + $this->assertFileExists($targetPath); + } finally { + $this->filesystem->remove($targetPath); + } + } + /** * Normalize the given path (transform each forward slash into a real directory separator). */ From fd09b3a3ff7ee74f10f49ef78b11ddf1c7d2f700 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 30 Jun 2021 10:27:41 +0200 Subject: [PATCH 82/83] Update CHANGELOG for 5.3.3 --- CHANGELOG-5.3.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md index 25c4691a7fbd8..d3d595787c3cf 100644 --- a/CHANGELOG-5.3.md +++ b/CHANGELOG-5.3.md @@ -7,6 +7,43 @@ in 5.3 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.3.0...v5.3.1 +* 5.3.3 (2021-06-30) + + * bug #41910 [Security] Handle concurency in Csrf DoctrineTokenProvider (jderusse) + * bug #41881 Fix SessionTokenStorage reuse with Request (jderusse) + * bug #41893 [Filesystem] Workaround cannot dumpFile into "protected" folders on Windows (arnegroskurth) + * bug #41896 [Messenger] fix FlattenExceptionNormalizer (nicolas-grekas) + * bug #41242 [SecurityBundle] Change information label from red to yellow (94noni) + * bug #41665 [HttpKernel] Keep max lifetime also when part of the responses don't set it (mpdude) + * bug #41760 [ErrorHandler] fix handling buffered SilencedErrorContext (nicolas-grekas) + * bug #41807 [HttpClient] fix Psr18Client when allow_url_fopen=0 (nicolas-grekas) + * bug #41735 [Runtime] Fix project dir variable when vendor not in project root (Ash014) + * bug #40857 [DependencyInjection] Add support of PHP enumerations (alexandre-daubois) + * bug #41767 [Config] fix tracking default values that reference the parent class (nicolas-grekas) + * bug #41768 [DependencyInjection] Fix binding "iterable $foo" when using the PHP-DSL (nicolas-grekas) + * bug #41777 [DependencyInjection] accept service locator definitions with no class (nicolas-grekas) + * bug #41801 [Uid] Fix fromString() with low base58 values (fancyweb) + * bug #41793 [Cache] handle prefixed redis connections when clearing pools (nicolas-grekas) + * bug #41804 [Cache] fix eventual consistency when using RedisTagAwareAdapter with a cluster (nicolas-grekas) + * bug #41773 [Cache] Disable locking on Windows by default (nicolas-grekas) + * bug #41655 [Mailer] fix encoding of addresses using SmtpTransport (dmaicher) + * bug #41663 [HttpKernel] [HttpCache] Keep s-maxage=0 from ESI sub-responses (mpdude) + * bug #41739 Avoid broken action URL in text notification mail (mbrodala) + * bug #41737 [Security] Fix special char used to create cache key (jderusse) + * bug #41701 [VarDumper] Fix tests for PHP 8.1 (alexandre-daubois) + * bug #41795 [FrameworkBundle] Replace var_export with VarExporter to use array short syntax in secrets list files (alexandre-daubois) + * bug #41779 [DependencyInjection] throw proper exception when decorating a synthetic service (nicolas-grekas) + * bug #41787 [Security] Implement fluent interface on RememberMeBadge::disable() (derrabus) + * bug #41776 [ErrorHandler] [DebugClassLoader] Do not check Phake mocks classes (adoy) + * bug #41780 [PhpUnitBridge] fix handling the COMPOSER_BINARY env var when using simple-phpunit (Taluu) + * bug #41755 [PasswordHasher] UserPasswordHasher only calls getSalt when method exists (dbrumann) + * bug #41670 [HttpFoundation] allow savePath of NativeFileSessionHandler to be null (simon.chrzanowski) + * bug #41751 [Messenger] prevent reflection usages when classes do not exist (xabbuh) + * bug #41747 [Security] Fixed 'security.command.debug_firewall' not found (Nyholm) + * bug #41741 [Security] Fix invalid RememberMe value after update (jderusse) + * bug #41744 [Security] Fix invalid cookie when migrating to new Security (jderusse) + * bug #41740 [Security] make the getter usable if no user identifier is set (xabbuh) + * 5.3.2 (2021-06-17) * security #cve-2021-32693 [SecurityHttp] Fix "Authentication granted with multiple firewalls" (wouterj) From 4865d80129d23dbad7e0a100cdb02466ec91033f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 30 Jun 2021 10:27:49 +0200 Subject: [PATCH 83/83] Update VERSION for 5.3.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 5aaee87e04978..d251c23ec2a2c 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -75,12 +75,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '5.3.3-DEV'; + public const VERSION = '5.3.3'; public const VERSION_ID = 50303; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 3; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '01/2022'; public const END_OF_LIFE = '01/2022';