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'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy